Java: Autoformat semmle.code.java.security.

This commit is contained in:
Anders Schack-Mulligen
2018-10-11 14:15:54 +02:00
parent c6c6e4319d
commit e781990960
11 changed files with 449 additions and 354 deletions

View File

@@ -21,15 +21,15 @@ private predicate boxedToString(Method method) {
* it is better to use a prepared query than to just put single quotes around the string.
*/
predicate endsInQuote(Expr expr) {
exists(string str | str = expr.(StringLiteral).getRepresentedString() |
str.matches("%'")) or
exists(Variable var | expr = var.getAnAccess() | endsInQuote(var.getAnAssignedValue())) or
exists(string str | str = expr.(StringLiteral).getRepresentedString() | str.matches("%'"))
or
exists(Variable var | expr = var.getAnAccess() | endsInQuote(var.getAnAssignedValue()))
or
endsInQuote(expr.(AddExpr).getRightOperand())
}
/** The given expression is controlled if the other expression is controlled. */
private
predicate controlledStringProp(Expr src, Expr dest) {
private predicate controlledStringProp(Expr src, Expr dest) {
// Propagation through variables.
exists(Variable var | var.getAnAccess() = dest | src = var.getAnAssignedValue())
or
@@ -54,8 +54,7 @@ predicate controlledStringProp(Expr src, Expr dest) {
}
/** Expressions that have a small number of inflows from `controlledStringProp`. */
private
predicate modestControlledStringInflow(Expr dest) {
private predicate modestControlledStringInflow(Expr dest) {
strictcount(Expr src | controlledStringProp(src, dest)) < 10
}
@@ -63,8 +62,7 @@ predicate modestControlledStringInflow(Expr dest) {
* A limited version of `controlledStringProp` that ignores destinations that are written a
* very high number of times.
*/
private
predicate controlledStringLimitedProp(Expr src, Expr dest) {
private predicate controlledStringLimitedProp(Expr src, Expr dest) {
controlledStringProp(src, dest) and
modestControlledStringInflow(dest)
}
@@ -76,17 +74,24 @@ predicate controlledStringLimitedProp(Expr src, Expr dest) {
cached
predicate controlledString(Expr expr) {
(
expr instanceof StringLiteral or
expr instanceof NullLiteral or
expr.(VarAccess).getVariable() instanceof EnumConstant or
expr.getType() instanceof PrimitiveType or
expr.getType() instanceof BoxedType or
expr instanceof StringLiteral
or
expr instanceof NullLiteral
or
expr.(VarAccess).getVariable() instanceof EnumConstant
or
expr.getType() instanceof PrimitiveType
or
expr.getType() instanceof BoxedType
or
exists(Method method | method = expr.(MethodAccess).getMethod() |
method instanceof ClassNameMethod or
method instanceof ClassSimpleNameMethod or
boxedToString(method)
) or
exists(ValidatedVariable var | var.getAnAccess() = expr) or
)
or
exists(ValidatedVariable var | var.getAnAccess() = expr)
or
forex(Expr other | controlledStringLimitedProp(other, expr) | controlledString(other))
) and
not expr instanceof TypeAccess

View File

@@ -30,9 +30,7 @@ import semmle.code.java.dispatch.VirtualDispatch
*/
deprecated class FlowSource extends Expr {
/** Holds if this source flows to the `sink`. */
predicate flowsTo(Expr sink) {
flowsToAndLocal((FlowExpr) sink)
}
predicate flowsTo(Expr sink) { flowsToAndLocal(sink.(FlowExpr)) }
/**
* The same as `flowsTo(sink,fromArg)`, plus `localFlow` and reads from instance fields.
@@ -43,12 +41,15 @@ deprecated class FlowSource extends Expr {
// Verify that the sink is not excluded for this `FlowSource`.
not isExcluded(sink) and
(
flowsTo(sink, _) or
flowsTo(sink, _)
or
exists(FlowExpr tracked |
// The tracked expression should not be excluded for this `FlowSource`.
not isExcluded(tracked) and
flowsToAndLocal(tracked) and (
localFlowStep(tracked, sink) or
flowsToAndLocal(tracked) and
(
localFlowStep(tracked, sink)
or
exists(Field field |
tracked = field.getAnAssignedValue() and
sink = field.getAnAccess()
@@ -66,38 +67,44 @@ deprecated class FlowSource extends Expr {
private predicate flowsTo(FlowExpr sink, boolean fromArg) {
// Base case.
sink = this and fromArg = false
or exists(FlowExpr tracked |
or
exists(FlowExpr tracked |
// The tracked expression should not be excluded for this `FlowSource`.
not isExcluded(tracked)
|
|
// Flow within a single method.
(flowsTo(tracked, fromArg) and
(
flowsTo(tracked, fromArg) and
localFlowStep(tracked, sink)
)
or
// Flow through a field.
or (flowsTo(tracked, _) and
(
flowsTo(tracked, _) and
staticFieldStep(tracked, sink) and
fromArg = false
)
or
// Flow through a method that returns one of its arguments.
or exists(MethodAccess call, int i |
exists(MethodAccess call, int i |
flowsTo(tracked, fromArg) and
methodReturnsArg(responderForArg(call, i, tracked), i) and
sink = call
)
or
// Flow into a method.
or exists(Call c, Callable m, Parameter p, int i |
exists(Call c, Callable m, Parameter p, int i |
flowsTo(tracked, _) and
m = responderForArg(c, i, tracked) and
m.getParameter(i) = p and
parameterDefUsePair(p, sink) and
fromArg = true
)
or
// Flow out of a method.
// This path is only enabled if the flow did not come from the argument;
// such cases are handled by `methodReturnsArg`.
or (
(
flowsTo(tracked, false) and
methodStep(tracked, sink) and
fromArg = false
@@ -115,13 +122,12 @@ deprecated class FlowSource extends Expr {
not isExcluded(sink.(FlowExpr)) and
(
sink = this
or exists(FlowSource tracked | tracked.flowsToReverse(sink) |
localFlowStep(this, tracked)
)
or exists(FlowSource tracked | tracked.flowsToReverse(sink) |
staticFieldStep(this, tracked)
)
or exists(FlowSource tracked, MethodAccess call, int i |
or
exists(FlowSource tracked | tracked.flowsToReverse(sink) | localFlowStep(this, tracked))
or
exists(FlowSource tracked | tracked.flowsToReverse(sink) | staticFieldStep(this, tracked))
or
exists(FlowSource tracked, MethodAccess call, int i |
tracked.flowsToReverse(sink) and
tracked = call and
methodReturnsArg(call.getMethod(), i) and
@@ -149,7 +155,6 @@ deprecated class FlowExpr extends Expr {
FlowExpr() {
// Ignore paths through test code.
not getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass and
not exists(ValidatedVariable var | this = var.getAnAccess())
}
}
@@ -163,7 +168,8 @@ deprecated private Callable responderForArg(Call call, int i, FlowExpr tracked)
/** Gets the responders to consider when tracking flow through a `call`. */
deprecated private Callable responder(Call call) {
result = exactCallable(call) or
result = exactCallable(call)
or
(
not exists(exactCallable(call)) and
result = call.getCallee()
@@ -183,9 +189,11 @@ deprecated predicate methodReturnsArg(Method method, int arg) {
* that return their argument.
*/
deprecated private Expr parameterFlow(Method method, int arg) {
result = method.getParameter(arg).getAnAccess() or
result = method.getParameter(arg).getAnAccess()
or
exists(Expr tracked | tracked = parameterFlow(method, arg) |
localFlowStep(tracked, result) or
localFlowStep(tracked, result)
or
exists(MethodAccess acc, int j |
acc.getArgument(j) = tracked and
methodReturnsArg(acc.getMethod(), j) and
@@ -197,50 +205,53 @@ deprecated private Expr parameterFlow(Method method, int arg) {
/**
* One step of flow within a single method.
*/
deprecated cached private predicate localFlowStep(Expr tracked, Expr sink) {
cached
deprecated private predicate localFlowStep(Expr tracked, Expr sink) {
variableStep(tracked, sink)
or
// A concatenation of a tracked expression.
or sink.(AddExpr).getAnOperand() = tracked
sink.(AddExpr).getAnOperand() = tracked
or
// A parenthesized tracked expression.
or sink.(ParExpr).getExpr() = tracked
sink.(ParExpr).getExpr() = tracked
or
// A cast of a tracked expression.
or sink.(CastExpr).getExpr() = tracked
sink.(CastExpr).getExpr() = tracked
or
// A conditional expression with a tracked branch.
or sink.(ConditionalExpr).getTrueExpr() = tracked
or sink.(ConditionalExpr).getFalseExpr() = tracked
sink.(ConditionalExpr).getTrueExpr() = tracked
or
sink.(ConditionalExpr).getFalseExpr() = tracked
or
// An array initialization or creation expression.
or sink.(ArrayCreationExpr).getInit() = tracked
or sink.(ArrayInit).getAnInit() = tracked
sink.(ArrayCreationExpr).getInit() = tracked
or
sink.(ArrayInit).getAnInit() = tracked
or
// An access to an element of a tracked array.
or sink.(ArrayAccess).getArray() = tracked
or arrayAccessStep(tracked, sink)
or constructorStep(tracked, sink)
or qualifierToMethodStep(tracked, sink)
or argToMethodStep(tracked, sink)
sink.(ArrayAccess).getArray() = tracked
or
arrayAccessStep(tracked, sink)
or
constructorStep(tracked, sink)
or
qualifierToMethodStep(tracked, sink)
or
argToMethodStep(tracked, sink)
or
// An unsafe attempt to escape tainted input.
or (unsafeEscape(sink) and sink.(MethodAccess).getQualifier() = tracked)
(unsafeEscape(sink) and sink.(MethodAccess).getQualifier() = tracked)
or
// A logic expression.
or sink.(LogicExpr).getAnOperand() = tracked
or comparisonStep(tracked, sink)
or stringBuilderStep(tracked, sink)
or serializationStep(tracked, sink)
or argToArgStep(tracked, sink)
sink.(LogicExpr).getAnOperand() = tracked
or
comparisonStep(tracked, sink)
or
stringBuilderStep(tracked, sink)
or
serializationStep(tracked, sink)
or
argToArgStep(tracked, sink)
}
/**
@@ -262,14 +273,25 @@ deprecated private predicate argToArgStep(Expr tracked, VarAccess sink) {
* `output`th argument if the `input`th argument is tainted.
*/
deprecated private predicate dataPreservingArgToArg(Method method, int input, int output) {
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and (
method.hasName("copy") and input = 0 and output = 1 or
method.hasName("copyLarge") and input = 0 and output = 1 or
method.hasName("read") and input = 0 and output = 1 or
method.hasName("readFully") and input = 0 and output = 1 and not method.getParameterType(1).hasName("int") or
method.hasName("write") and input = 0 and output = 1 or
method.hasName("writeChunked") and input = 0 and output = 1 or
method.hasName("writeLines") and input = 0 and output = 2 or
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and
(
method.hasName("copy") and input = 0 and output = 1
or
method.hasName("copyLarge") and input = 0 and output = 1
or
method.hasName("read") and input = 0 and output = 1
or
method.hasName("readFully") and
input = 0 and
output = 1 and
not method.getParameterType(1).hasName("int")
or
method.hasName("write") and input = 0 and output = 1
or
method.hasName("writeChunked") and input = 0 and output = 1
or
method.hasName("writeLines") and input = 0 and output = 2
or
method.hasName("writeLines") and input = 1 and output = 2
)
}
@@ -285,7 +307,9 @@ deprecated private predicate variableStep(Expr tracked, VarAccess sink) {
deprecated private predicate staticFieldStep(Expr tracked, FieldAccess sink) {
exists(Field f |
f.isStatic() and
f.getAnAssignedValue() = tracked | f.getAnAccess() = sink
f.getAnAssignedValue() = tracked
|
f.getAnAccess() = sink
)
}
@@ -302,12 +326,13 @@ deprecated private predicate methodStep(Expr tracked, MethodAccess sink) {
m = responder(sink)
)
}
/** Access to a method that passes taint from an argument. */
deprecated private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
exists(Method m, int i |
m = sink.(MethodAccess).getMethod()
and dataPreservingArgument(m, i)
and tracked = sink.(MethodAccess).getArgument(i)
m = sink.(MethodAccess).getMethod() and
dataPreservingArgument(m, i) and
tracked = sink.(MethodAccess).getArgument(i)
)
}
@@ -316,21 +341,22 @@ deprecated private predicate comparisonStep(Expr tracked, Expr sink) {
exists(Expr other |
(
exists(BinaryExpr e | e instanceof ComparisonExpr or e instanceof EqualityTest |
e = sink
and e.getAnOperand() = tracked
and e.getAnOperand() = other
e = sink and
e.getAnOperand() = tracked and
e.getAnOperand() = other
)
or
exists(MethodAccess m | m.getMethod() instanceof EqualsMethod |
m = sink
and (
(m.getQualifier() = tracked and m.getArgument(0) = other) or
m = sink and
(
(m.getQualifier() = tracked and m.getArgument(0) = other)
or
(m.getQualifier() = other and m.getArgument(0) = tracked)
)
)
)
and (other.isCompileTimeConstant() or other instanceof NullLiteral)
and tracked != other
) and
(other.isCompileTimeConstant() or other instanceof NullLiteral) and
tracked != other
)
}
@@ -340,8 +366,8 @@ deprecated private predicate stringBuilderStep(Expr tracked, Expr sink) {
exists(MethodAccess input, int arg |
input = sbvar.getAnInput(arg) and
tracked = input.getArgument(arg)
)
and sink = sbvar.getToStringCall()
) and
sink = sbvar.getToStringCall()
)
}
@@ -403,12 +429,13 @@ deprecated class StringBuilderVar extends LocalVariableDecl {
* Gets a call that adds something to this string builder, from the argument at the given index.
*/
MethodAccess getAnInput(int arg) {
result.getQualifier() = getAChainedReference()
and
result.getQualifier() = getAChainedReference() and
(
result.getMethod().getName() = "append" and arg = 0
or result.getMethod().getName() = "insert" and arg = 1
or result.getMethod().getName() = "replace" and arg = 2
or
result.getMethod().getName() = "insert" and arg = 1
or
result.getMethod().getName() = "replace" and arg = 2
)
}
@@ -416,15 +443,16 @@ deprecated class StringBuilderVar extends LocalVariableDecl {
* Gets a call that appends something to this string builder.
*/
MethodAccess getAnAppend() {
result.getQualifier() = getAChainedReference()
and result.getMethod().getName() = "append"
result.getQualifier() = getAChainedReference() and
result.getMethod().getName() = "append"
}
MethodAccess getNextAppend(MethodAccess append) {
result = getAnAppend() and
append = getAnAppend() and
(
result.getQualifier() = append or
result.getQualifier() = append
or
not exists(MethodAccess chainAccess | chainAccess.getQualifier() = append) and
exists(RValue sbva1, RValue sbva2 |
adjacentUseUse(sbva1, sbva2) and
@@ -438,8 +466,8 @@ deprecated class StringBuilderVar extends LocalVariableDecl {
* Gets a call that converts this string builder to a string.
*/
MethodAccess getToStringCall() {
result.getQualifier() = getAChainedReference()
and result.getMethod().getName() = "toString"
result.getQualifier() = getAChainedReference() and
result.getMethod().getName() = "toString"
}
private Expr getAChainedReference(VarAccess sbva) {
@@ -453,9 +481,7 @@ deprecated class StringBuilderVar extends LocalVariableDecl {
/**
* Gets an expression that refers to this `StringBuilder`, possibly after some chained calls.
*/
Expr getAChainedReference() {
result = getAChainedReference(_)
}
Expr getAChainedReference() { result = getAChainedReference(_) }
}
deprecated private MethodAccess callReturningSameType(Expr ref) {
@@ -465,7 +491,8 @@ deprecated private MethodAccess callReturningSameType(Expr ref) {
deprecated private class BulkData extends RefType {
BulkData() {
this.(Array).getElementType().(PrimitiveType).getName().regexpMatch("byte|char") or
this.(Array).getElementType().(PrimitiveType).getName().regexpMatch("byte|char")
or
exists(RefType t | this.getASourceSupertype*() = t |
t.hasQualifiedName("java.io", "InputStream") or
t.hasQualifiedName("java.nio", "ByteBuffer") or
@@ -494,48 +521,74 @@ deprecated predicate constructorStep(Expr tracked, ConstructorCall sink) {
exists(int argi | sink.getArgument(argi) = tracked |
exists(string s | sink.getConstructedType().getQualifiedName() = s |
// String constructor does nothing to data
s = "java.lang.String" and argi = 0 or
s = "java.lang.String" and argi = 0
or
// some readers preserve the content of streams
s = "java.io.InputStreamReader" and argi = 0 or
s = "java.io.BufferedReader" and argi = 0 or
s = "java.io.CharArrayReader" and argi = 0 or
s = "java.io.StringReader" and argi = 0 or
s = "java.io.InputStreamReader" and argi = 0
or
s = "java.io.BufferedReader" and argi = 0
or
s = "java.io.CharArrayReader" and argi = 0
or
s = "java.io.StringReader" and argi = 0
or
// data preserved through streams
s = "java.io.ObjectInputStream" and argi = 0 or
s = "java.io.ByteArrayInputStream" and argi = 0 or
s = "java.io.DataInputStream" and argi = 0 or
s = "java.io.BufferedInputStream" and argi = 0 or
s = "com.esotericsoftware.kryo.io.Input" and argi = 0 or
s = "java.beans.XMLDecoder" and argi = 0 or
s = "java.io.ObjectInputStream" and argi = 0
or
s = "java.io.ByteArrayInputStream" and argi = 0
or
s = "java.io.DataInputStream" and argi = 0
or
s = "java.io.BufferedInputStream" and argi = 0
or
s = "com.esotericsoftware.kryo.io.Input" and argi = 0
or
s = "java.beans.XMLDecoder" and argi = 0
or
// a tokenizer preserves the content of a string
s = "java.util.StringTokenizer" and argi = 0 or
s = "java.util.StringTokenizer" and argi = 0
or
// unzipping the stream preserves content
s = "java.util.zip.ZipInputStream" and argi = 0 or
s = "java.util.zip.GZIPInputStream" and argi = 0 or
s = "java.util.zip.ZipInputStream" and argi = 0
or
s = "java.util.zip.GZIPInputStream" and argi = 0
or
// string builders and buffers
s = "java.lang.StringBuilder" and argi = 0 or
s = "java.lang.StringBuffer" and argi = 0 or
s = "java.lang.StringBuilder" and argi = 0
or
s = "java.lang.StringBuffer" and argi = 0
or
// a cookie with tainted ingredients is tainted
s = "javax.servlet.http.Cookie" and argi = 0 or
s = "javax.servlet.http.Cookie" and argi = 1 or
s = "javax.servlet.http.Cookie" and argi = 0
or
s = "javax.servlet.http.Cookie" and argi = 1
or
// various xml stream source constructors.
s = "org.xml.sax.InputSource" and argi = 0 or
s = "javax.xml.transform.sax.SAXSource" and argi = 0 and sink.getNumArgument() = 1 or
s = "javax.xml.transform.sax.SAXSource" and argi = 1 and sink.getNumArgument() = 2 or
s = "javax.xml.transform.stream.StreamSource" and argi = 0 or
s = "org.xml.sax.InputSource" and argi = 0
or
s = "javax.xml.transform.sax.SAXSource" and argi = 0 and sink.getNumArgument() = 1
or
s = "javax.xml.transform.sax.SAXSource" and argi = 1 and sink.getNumArgument() = 2
or
s = "javax.xml.transform.stream.StreamSource" and argi = 0
or
//a URI constructed from a tainted string is tainted.
s = "java.net.URI" and argi = 0 and sink.getNumArgument() = 1
) or
)
or
exists(RefType t | t.getQualifiedName() = "java.lang.Number" |
hasSubtypeStar(t, sink.getConstructedType())
) and argi = 0 or
) and
argi = 0
or
// wrappers constructed by extension
exists(Constructor c, Parameter p, SuperConstructorInvocationStmt sup |
c = sink.getConstructor() and
p = c.getParameter(argi) and
sup.getEnclosingCallable() = c and
constructorStep(p.getAnAccess(), sup)
) or
)
or
// a custom InputStream that wraps a tainted data source is tainted
inputStreamWrapper(sink.getConstructor(), argi)
)
@@ -565,49 +618,57 @@ deprecated class DataPreservingMethod extends Method {
this.getName() = "toUpperCase" or
this.getName() = "trim"
)
) or
)
or
(
exists(Class c | c.getQualifiedName() = "java.lang.Number" |
hasSubtypeStar(c, this.getDeclaringType())) and
hasSubtypeStar(c, this.getDeclaringType())
) and
(
this.getName().matches("to%String") or
this.getName() = "toByteArray" or
this.getName().matches("%Value")
)
) or
)
or
(
this.getDeclaringType().getQualifiedName().matches("%Reader") and
this.getName().matches("read%")
) or
)
or
(
this.getDeclaringType().getQualifiedName().matches("%StringWriter") and
this.getName() = "toString"
) or
)
or
(
this.getDeclaringType().hasQualifiedName("java.util", "StringTokenizer") and
this.getName().matches("next%")
) or
)
or
(
this.getDeclaringType().hasQualifiedName("java.io", "ByteArrayOutputStream") and
(this.getName() = "toByteArray" or this.getName() = "toString")
) or
)
or
(
this.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
this.getName().matches("read%")
) or
)
or
(
(
this.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
this.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer")
) and
(
this.getName() = "toString" or this.getName() = "append"
)
) or
(this.getName() = "toString" or this.getName() = "append")
)
or
(
this.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
this.hasName("getInputSource")
) or
)
or
(
this.getDeclaringType().hasQualifiedName("javax.xml.transform.stream", "StreamSource") and
this.hasName("getInputStream")
@@ -623,17 +684,21 @@ deprecated predicate dataPreservingArgument(Method method, int arg) {
(
method instanceof StringReplaceMethod and
arg = 1
) or
)
or
(
exists(Class c | c.getQualifiedName() = "java.lang.Number" |
hasSubtypeStar(c, method.getDeclaringType())
) and
(
(method.getName().matches("parse%") and arg = 0) or
(method.getName().matches("valueOf%") and arg = 0) or
(method.getName().matches("parse%") and arg = 0)
or
(method.getName().matches("valueOf%") and arg = 0)
or
(method.getName().matches("to%String") and arg = 0)
)
) or
)
or
(
(
method.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
@@ -646,43 +711,58 @@ deprecated predicate dataPreservingArgument(Method method, int arg) {
or
method.getName() = "replace" and arg = 2
)
) or
)
or
(
(
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Encoder") or
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder")
) and
(
method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1 or
method.getName() = "decode" and arg = 0 and method.getNumberOfParameters() = 1 or
method.getName() = "encodeToString" and arg = 0 or
method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1
or
method.getName() = "decode" and arg = 0 and method.getNumberOfParameters() = 1
or
method.getName() = "encodeToString" and arg = 0
or
method.getName() = "wrap" and arg = 0
)
) or
)
or
(
(method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils")) and
(
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils")
) and
(
method.getName() = "buffer" and arg = 0 or
method.getName() = "readLines" and arg = 0 or
method.getName() = "readFully" and arg = 0 and method.getParameterType(1).hasName("int") or
method.getName() = "toBufferedInputStream" and arg = 0 or
method.getName() = "toBufferedReader" and arg = 0 or
method.getName() = "toByteArray" and arg = 0 or
method.getName() = "toCharArray" and arg = 0 or
method.getName() = "toInputStream" and arg = 0 or
method.getName() = "buffer" and arg = 0
or
method.getName() = "readLines" and arg = 0
or
method.getName() = "readFully" and arg = 0 and method.getParameterType(1).hasName("int")
or
method.getName() = "toBufferedInputStream" and arg = 0
or
method.getName() = "toBufferedReader" and arg = 0
or
method.getName() = "toByteArray" and arg = 0
or
method.getName() = "toCharArray" and arg = 0
or
method.getName() = "toInputStream" and arg = 0
or
method.getName() = "toString" and arg = 0
)
) or
)
or
(
//A URI created from a tainted string is still tainted.
method.getDeclaringType().hasQualifiedName("java.net", "URI") and
method.hasName("create") and arg = 0
) or
method.hasName("create") and
arg = 0
)
or
(
method.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
method.hasName("sourceToInputSource") and arg = 0
method.hasName("sourceToInputSource") and
arg = 0
)
}
@@ -711,7 +791,7 @@ deprecated predicate unsafeEscape(MethodAccess ma) {
*
* Class for `tainted` user input.
*/
deprecated abstract class UserInput extends FlowSource {}
abstract deprecated class UserInput extends FlowSource { }
/**
* DEPRECATED: Use semmle.code.java.dataflow.FlowSources.RemoteUserInput instead.
@@ -721,37 +801,38 @@ deprecated abstract class UserInput extends FlowSource {}
deprecated class RemoteUserInput extends UserInput {
RemoteUserInput() {
this.(MethodAccess).getMethod() instanceof RemoteTaintedMethod
or
// Parameters to RMI methods.
or exists(RemoteCallableMethod method |
method.getAParameter().getAnAccess() = this
and (
getType() instanceof PrimitiveType
or getType() instanceof TypeString
)
)
// Parameters to Jax WS methods.
or exists(JaxWsEndpoint endpoint |
endpoint.getARemoteMethod().getAParameter().getAnAccess() = this
)
// Parameters to Jax Rs methods.
or exists(JaxRsResourceClass service |
service.getAnInjectableCallable().getAParameter().getAnAccess() = this or
service.getAnInjectableField().getAnAccess() = this
)
// Reverse DNS. Try not to trigger on `localhost`.
or exists(MethodAccess m | m = this |
m.getMethod() instanceof ReverseDNSMethod and
not exists(MethodAccess l |
(variableStep(l, m.getQualifier()) or l = m.getQualifier())
and l.getMethod().getName() = "getLocalHost"
exists(RemoteCallableMethod method |
method.getAParameter().getAnAccess() = this and
(
getType() instanceof PrimitiveType or
getType() instanceof TypeString
)
)
or
// Parameters to Jax WS methods.
exists(JaxWsEndpoint endpoint |
endpoint.getARemoteMethod().getAParameter().getAnAccess() = this
)
or
// Parameters to Jax Rs methods.
exists(JaxRsResourceClass service |
service.getAnInjectableCallable().getAParameter().getAnAccess() = this or
service.getAnInjectableField().getAnAccess() = this
)
or
// Reverse DNS. Try not to trigger on `localhost`.
exists(MethodAccess m | m = this |
m.getMethod() instanceof ReverseDNSMethod and
not exists(MethodAccess l |
(variableStep(l, m.getQualifier()) or l = m.getQualifier()) and
l.getMethod().getName() = "getLocalHost"
)
)
or
//MessageBodyReader
or exists(MessageBodyReaderRead m |
exists(MessageBodyReaderRead m |
m.getParameter(4).getAnAccess() = this or
m.getParameter(5).getAnAccess() = this
)
@@ -763,35 +844,34 @@ deprecated class RemoteUserInput extends UserInput {
*
* Input that may be controlled by a local user.
*/
deprecated abstract class LocalUserInput extends UserInput {}
abstract deprecated class LocalUserInput extends UserInput { }
deprecated class EnvInput extends LocalUserInput {
EnvInput() {
// Parameters to a main method.
exists(MainMethod main | this = main.getParameter(0).getAnAccess())
or
// Args4j arguments.
or exists(Field f | this = f.getAnAccess() | f.getAnAnnotation().getType().getQualifiedName() = "org.kohsuke.args4j.Argument")
exists(Field f | this = f.getAnAccess() |
f.getAnAnnotation().getType().getQualifiedName() = "org.kohsuke.args4j.Argument"
)
or
// Results from various specific methods.
or this.(MethodAccess).getMethod() instanceof EnvTaintedMethod
this.(MethodAccess).getMethod() instanceof EnvTaintedMethod
or
// Access to `System.in`.
or exists(Field f | this = f.getAnAccess() | f instanceof SystemIn)
exists(Field f | this = f.getAnAccess() | f instanceof SystemIn)
or
// Access to files.
or this.(ConstructorCall).getConstructedType().hasQualifiedName("java.io", "FileInputStream")
this.(ConstructorCall).getConstructedType().hasQualifiedName("java.io", "FileInputStream")
}
}
deprecated class DatabaseInput extends LocalUserInput {
DatabaseInput() {
this.(MethodAccess).getMethod() instanceof ResultSetGetStringMethod
}
DatabaseInput() { this.(MethodAccess).getMethod() instanceof ResultSetGetStringMethod }
}
library
deprecated class RemoteTaintedMethod extends Method {
deprecated library class RemoteTaintedMethod extends Method {
RemoteTaintedMethod() {
this instanceof ServletRequestGetParameterMethod or
this instanceof HttpServletRequestGetQueryStringMethod or
@@ -812,8 +892,7 @@ deprecated class RemoteTaintedMethod extends Method {
}
}
library
deprecated class EnvTaintedMethod extends Method {
deprecated library class EnvTaintedMethod extends Method {
EnvTaintedMethod() {
this instanceof MethodSystemGetenv or
this instanceof PropertiesGetPropertyMethod or
@@ -822,9 +901,7 @@ deprecated class EnvTaintedMethod extends Method {
}
deprecated class TypeInetAddr extends RefType {
TypeInetAddr() {
this.getQualifiedName() = "java.net.InetAddress"
}
TypeInetAddr() { this.getQualifiedName() = "java.net.InetAddress" }
}
deprecated class ReverseDNSMethod extends Method {

View File

@@ -10,34 +10,23 @@ class SSLClass extends RefType {
}
class X509TrustManager extends RefType {
X509TrustManager() {
this.hasQualifiedName("javax.net.ssl", "X509TrustManager")
}
X509TrustManager() { this.hasQualifiedName("javax.net.ssl", "X509TrustManager") }
}
class HttpsURLConnection extends RefType {
HttpsURLConnection() {
hasQualifiedName("javax.net.ssl", "HttpsURLConnection")
}
HttpsURLConnection() { hasQualifiedName("javax.net.ssl", "HttpsURLConnection") }
}
class SSLSocketFactory extends RefType {
SSLSocketFactory() {
this.hasQualifiedName("javax.net.ssl", "SSLSocketFactory")
}
SSLSocketFactory() { this.hasQualifiedName("javax.net.ssl", "SSLSocketFactory") }
}
class SSLContext extends RefType {
SSLContext() {
hasQualifiedName("javax.net.ssl", "SSLContext")
}
SSLContext() { hasQualifiedName("javax.net.ssl", "SSLContext") }
}
class HostnameVerifier extends RefType {
HostnameVerifier() {
hasQualifiedName("javax.net.ssl", "HostnameVerifier")
}
HostnameVerifier() { hasQualifiedName("javax.net.ssl", "HostnameVerifier") }
}
class HostnameVerifierVerify extends Method {
@@ -86,13 +75,13 @@ private string algorithmRegex(string algorithmString) {
// Algorithms usually appear in names surrounded by characters that are not
// alphabetical characters in the same case. This handles the upper and lower
// case cases.
result = "((^|.*[^A-Z])(" + algorithmString + ")([^A-Z].*|$))"
// or...
+ "|" +
// For lowercase, we want to be careful to avoid being confused by camelCase
// hence we require two preceding uppercase letters to be sure of a case switch,
// or a preceding non-alphabetic character
"((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))"
result = "((^|.*[^A-Z])(" + algorithmString + ")([^A-Z].*|$))" +
// or...
"|" +
// For lowercase, we want to be careful to avoid being confused by camelCase
// hence we require two preceding uppercase letters to be sure of a case switch,
// or a preceding non-alphabetic character
"((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))"
}
/** Gets a blacklist of algorithms that are known to be insecure. */
@@ -119,7 +108,7 @@ private string rankedAlgorithmBlacklist(int i) {
private string algorithmBlacklistString(int i) {
i = 1 and result = rankedAlgorithmBlacklist(i)
or
result = rankedAlgorithmBlacklist(i) + "|" + algorithmBlacklistString(i-1)
result = rankedAlgorithmBlacklist(i) + "|" + algorithmBlacklistString(i - 1)
}
/** Gets a regex for matching strings that look like they contain a blacklisted algorithm. */
@@ -138,14 +127,12 @@ private string algorithmWhitelist() {
result = "ECIES"
}
private string rankedAlgorithmWhitelist(int i) {
result = rank[i](algorithmWhitelist())
}
private string rankedAlgorithmWhitelist(int i) { result = rank[i](algorithmWhitelist()) }
private string algorithmWhitelistString(int i) {
i = 1 and result = rankedAlgorithmWhitelist(i)
or
result = rankedAlgorithmWhitelist(i) + "|" + algorithmWhitelistString(i-1)
result = rankedAlgorithmWhitelist(i) + "|" + algorithmWhitelistString(i - 1)
}
/** Gets a regex for matching strings that look like they contain a whitelisted algorithm. */
@@ -160,10 +147,11 @@ string algorithmWhitelistRegex() {
*/
abstract class CryptoAlgoSpec extends Top {
CryptoAlgoSpec() { this instanceof Call }
abstract Expr getAlgoSpec();
}
abstract class JavaxCryptoAlgoSpec extends CryptoAlgoSpec {}
abstract class JavaxCryptoAlgoSpec extends CryptoAlgoSpec { }
class JavaxCryptoCipher extends JavaxCryptoAlgoSpec {
JavaxCryptoCipher() {
@@ -173,9 +161,7 @@ class JavaxCryptoCipher extends JavaxCryptoAlgoSpec {
)
}
override Expr getAlgoSpec() {
result = this.(MethodAccess).getArgument(0)
}
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
}
class JavaxCryptoSecretKey extends JavaxCryptoAlgoSpec {
@@ -187,9 +173,7 @@ class JavaxCryptoSecretKey extends JavaxCryptoAlgoSpec {
override Expr getAlgoSpec() {
exists(ConstructorCall c | c = this |
if c.getNumArgument() = 2
then result = c.getArgument(1)
else result = c.getArgument(3)
if c.getNumArgument() = 2 then result = c.getArgument(1) else result = c.getArgument(3)
)
}
}
@@ -202,9 +186,7 @@ class JavaxCryptoKeyGenerator extends JavaxCryptoAlgoSpec {
)
}
override Expr getAlgoSpec() {
result = this.(MethodAccess).getArgument(0)
}
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
}
class JavaxCryptoKeyAgreement extends JavaxCryptoAlgoSpec {
@@ -215,9 +197,7 @@ class JavaxCryptoKeyAgreement extends JavaxCryptoAlgoSpec {
)
}
override Expr getAlgoSpec() {
result = this.(MethodAccess).getArgument(0)
}
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
}
class JavaxCryptoKeyFactory extends JavaxCryptoAlgoSpec {
@@ -228,12 +208,10 @@ class JavaxCryptoKeyFactory extends JavaxCryptoAlgoSpec {
)
}
override Expr getAlgoSpec() {
result = this.(MethodAccess).getArgument(0)
}
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
}
abstract class JavaSecurityAlgoSpec extends CryptoAlgoSpec {}
abstract class JavaSecurityAlgoSpec extends CryptoAlgoSpec { }
class JavaSecurityMessageDigest extends JavaSecurityAlgoSpec {
JavaSecurityMessageDigest() {
@@ -242,9 +220,7 @@ class JavaSecurityMessageDigest extends JavaSecurityAlgoSpec {
)
}
override Expr getAlgoSpec() {
result = this.(ConstructorCall).getArgument(0)
}
override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) }
}
class JavaSecuritySignature extends JavaSecurityAlgoSpec {
@@ -254,7 +230,5 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec {
)
}
override Expr getAlgoSpec() {
result = this.(ConstructorCall).getArgument(0)
}
override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) }
}

View File

@@ -1,5 +1,4 @@
/* Definitions related to external processes. */
import semmle.code.java.Member
import semmle.code.java.JDK
import semmle.code.java.frameworks.apache.Exec
@@ -20,10 +19,11 @@ class ArgumentToExec extends Expr {
method instanceof MethodCommandLineParse or
method instanceof MethodCommandLineAddArguments
)
) or
)
or
exists(ConstructorCall expr, Constructor cons |
expr.getConstructor() = cons and
cons.getDeclaringType().hasQualifiedName("java.lang" , "ProcessBuilder") and
cons.getDeclaringType().hasQualifiedName("java.lang", "ProcessBuilder") and
expr.getArgument(0) = this
)
}
@@ -33,7 +33,5 @@ class ArgumentToExec extends Expr {
* An `ArgumentToExec` of type `String`.
*/
class StringArgumentToExec extends ArgumentToExec {
StringArgumentToExec() {
this.getType() instanceof TypeString
}
StringArgumentToExec() { this.getType() instanceof TypeString }
}

View File

@@ -7,22 +7,25 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) {
/*
* `fileAccess` used to construct a class that reads a file.
*/
exists(ClassInstanceExpr cie |
cie = fileReadingExpr and
cie.getArgument(0) = fileAccess
|
|
cie.getConstructedType().hasQualifiedName("java.io", "RandomAccessFile") or
cie.getConstructedType().hasQualifiedName("java.io", "FileReader") or
cie.getConstructedType().hasQualifiedName("java.io", "FileInputStream")
) or
)
or
exists(MethodAccess ma, Method filesMethod |
ma = fileReadingExpr and filesMethod = ma.getMethod()
|
|
(
/*
* Identify all method calls on the `Files` class that imply that we are reading the file
* represented by the first argument.
*/
filesMethod.getDeclaringType().hasQualifiedName("java.nio.file", "Files") and
fileAccess = ma.getArgument(0) and
(
@@ -33,7 +36,8 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) {
filesMethod.hasName("newByteChannel")
)
)
) or
)
or
// The `fileAccess` is used in a call which directly or indirectly accesses the file.
exists(Call call, int parameterPos, VarAccess nestedFileAccess, Expr nestedFileReadingExpr |
call = fileReadingExpr and
@@ -47,14 +51,10 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) {
* An expression that, directly or indirectly, reads from a file.
*/
class FileReadExpr extends Expr {
FileReadExpr() {
fileRead(_,this)
}
FileReadExpr() { fileRead(_, this) }
/**
* Gets the `VarAccess` representing the file that is read.
*/
VarAccess getFileVarAccess() {
fileRead(result, this)
}
VarAccess getFileVarAccess() { fileRead(result, this) }
}

View File

@@ -14,30 +14,42 @@ class SetWritable extends Method {
* Gets an `EnumConstant` that may be in the `Set` of `Enum`s represented by `enumSetRef`.
*/
private EnumConstant getAContainedEnumConstant(Expr enumSetRef) {
enumSetRef.getType().(RefType).getASupertype*().getSourceDeclaration().hasQualifiedName("java.util", "Set") and
enumSetRef
.getType()
.(RefType)
.getASupertype*()
.getSourceDeclaration()
.hasQualifiedName("java.util", "Set") and
(
// The set is defined inline using `EnumSet.of(...)`.
exists(MethodAccess enumSetOf |
enumSetOf = enumSetRef and
enumSetOf.getMethod().hasName("of") and
enumSetOf.getMethod().getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", "EnumSet")
|
enumSetOf
.getMethod()
.getDeclaringType()
.getSourceDeclaration()
.hasQualifiedName("java.util", "EnumSet")
|
// Any argument to `EnumSet.of(...)` is an `EnumConstant`.
result = enumSetOf.getAnArgument().(VarAccess).getVariable()
) or
)
or
// The set reference is an access of a variable...
exists(VarAccess enumSetAccess | enumSetAccess = enumSetRef |
// ...if the definition contains a value...
result = getAContainedEnumConstant(enumSetAccess.getVariable().getAnAssignedValue()) or
result = getAContainedEnumConstant(enumSetAccess.getVariable().getAnAssignedValue())
or
// ...or the value is added to the set.
exists(MethodAccess addToSet |
addToSet.getQualifier() = enumSetAccess.getVariable().getAnAccess()
|
|
(
// Call to `add(..)` on the enum set variable.
addToSet.getMethod().hasName("add") and
result = addToSet.getArgument(0).(VarAccess).getVariable()
) or
)
or
(
// Call to `addAll(..)` on the enum set variable.
addToSet.getMethod().hasName("addAll") and
@@ -57,6 +69,7 @@ private VarAccess getFileForPathConversion(Expr pathExpr) {
/*
* Look for conversion from `File` to `Path` using `file.getPath()`.
*/
exists(MethodAccess fileToPath |
fileToPath = pathExpr and
result = fileToPath.getQualifier() and
@@ -67,13 +80,14 @@ private VarAccess getFileForPathConversion(Expr pathExpr) {
/*
* Look for the pattern `Paths.get(file.get*Path())` for converting between a `File` and a `Path`.
*/
exists(MethodAccess pathsGet, MethodAccess fileGetPath |
pathsGet = pathExpr and
pathsGet.getMethod().hasName("get") and
pathsGet.getMethod().getDeclaringType().hasQualifiedName("java.nio.file", "Paths") and
fileGetPath = pathsGet.getArgument(0) and
result = fileGetPath.getQualifier()
|
|
fileGetPath.getMethod().hasName("getPath") or
fileGetPath.getMethod().hasName("getAbsolutePath") or
fileGetPath.getMethod().hasName("getCanonicalPath")
@@ -88,6 +102,7 @@ private predicate fileSetWorldWritable(VarAccess fileAccess, Expr setWorldWritab
/*
* Calls to `File.setWritable(.., false)`.
*/
exists(MethodAccess fileSetWritable |
// A call to the `setWritable` method.
fileSetWritable.getMethod() instanceof SetWritable and
@@ -97,10 +112,12 @@ private predicate fileSetWorldWritable(VarAccess fileAccess, Expr setWorldWritab
fileSetWritable.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = false and
setWorldWritable = fileSetWritable and
fileAccess = fileSetWritable.getQualifier()
) or
)
or
/*
* Calls to `Files.setPosixFilePermissions(...)`.
*/
exists(MethodAccess setPosixPerms |
setPosixPerms = setWorldWritable and
setPosixPerms.getMethod().hasName("setPosixFilePermissions") and
@@ -109,13 +126,16 @@ private predicate fileSetWorldWritable(VarAccess fileAccess, Expr setWorldWritab
fileAccess = setPosixPerms.getArgument(0) or
// The argument was a file that has been converted to a path.
fileAccess = getFileForPathConversion(setPosixPerms.getArgument(0))
) |
)
|
// The second argument is a set of `FilePermission`s.
getAContainedEnumConstant(setPosixPerms.getArgument(1)).hasName("OTHERS_WRITE")
) or
)
or
/*
* Calls to something that indirectly sets the file permissions.
*/
exists(Call call, int parameterPos, VarAccess nestedFileAccess, Expr nestedSetWorldWritable |
call = setWorldWritable and
fileSetWorldWritable(nestedFileAccess, nestedSetWorldWritable) and
@@ -128,14 +148,10 @@ private predicate fileSetWorldWritable(VarAccess fileAccess, Expr setWorldWritab
* An expression that, directly or indirectly, makes the file argument world writable.
*/
class SetFileWorldWritable extends Expr {
SetFileWorldWritable() {
fileSetWorldWritable(_, this)
}
SetFileWorldWritable() { fileSetWorldWritable(_, this) }
/**
* Gets the `VarAccess` representing the file that is set world writable.
*/
VarAccess getFileVarAccess() {
fileSetWorldWritable(result, this)
}
VarAccess getFileVarAccess() { fileSetWorldWritable(result, this) }
}

View File

@@ -3,9 +3,7 @@ import semmle.code.java.dataflow.DefUse
import semmle.code.java.dataflow.DataFlow
class SecureRandomNumberGenerator extends RefType {
SecureRandomNumberGenerator() {
this.hasQualifiedName("java.security", "SecureRandom")
}
SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") }
}
class GetRandomData extends MethodAccess {
@@ -26,12 +24,13 @@ private predicate isSeeded(RValue use) {
private class PredictableSeedFlowConfiguration extends DataFlow::Configuration {
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof PredictableSeedExpr
}
override predicate isSink(DataFlow::Node sink) {
isSeeding(sink.asExpr(), _)
}
override predicate isSink(DataFlow::Node sink) { isSeeding(sink.asExpr(), _) }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
predictableCalcStep(node1.asExpr(), node2.asExpr())
}
@@ -42,14 +41,15 @@ private class TypeNumber extends Class {
}
private predicate predictableCalcStep(Expr e1, Expr e2) {
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p)) or
exists(AssignOp a | a = e2 |
e1 = a.getDest() and a.getRhs() instanceof PredictableSeedExpr
) or
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p))
or
exists(AssignOp a | a = e2 | e1 = a.getDest() and a.getRhs() instanceof PredictableSeedExpr)
or
exists(ConstructorCall cc, TypeNumber t | cc = e2 |
cc.getArgument(0) = e1 and
t.hasSubtype*(cc.getConstructedType())
) or
)
or
exists(Method m, MethodAccess ma |
ma = e2 and
e1 = ma.getQualifier() and
@@ -60,7 +60,8 @@ private predicate predictableCalcStep(Expr e1, Expr e2) {
m.getName() = "toByteArray" or
m.getName().matches("%Value")
)
) or
)
or
exists(Method m, MethodAccess ma |
ma = e2 and
e1 = ma.getArgument(0) and
@@ -82,7 +83,7 @@ private predicate safelySeeded(RValue use) {
or
exists(GetRandomData da, RValue seeduse |
da.getQualifier() = seeduse and useUsePair(seeduse, use)
|
|
not exists(RValue prior | useUsePair(prior, seeduse) | isSeeded(prior))
)
}
@@ -96,10 +97,11 @@ private predicate isSeeding(Expr arg, RValue use) {
exists(Expr e, VariableAssign def |
def.getSource() = e and
isSeedingConstruction(e, arg)
|
|
defUsePair(def, use) or
def.getDestVar().(Field).getAnAccess() = use
) or
)
or
exists(Expr e, RValue seeduse |
e.(MethodAccess).getQualifier() = seeduse and
isRandomSeeding(e, arg) and
@@ -109,7 +111,9 @@ private predicate isSeeding(Expr arg, RValue use) {
private predicate isSeedingSource(Expr arg, RValue use, Expr source) {
isSeeding(arg, use) and
exists(PredictableSeedFlowConfiguration conf | conf.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(arg)))
exists(PredictableSeedFlowConfiguration conf |
conf.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(arg))
)
}
private predicate isRandomSeeding(MethodAccess m, Expr arg) {
@@ -121,29 +125,34 @@ private predicate isRandomSeeding(MethodAccess m, Expr arg) {
}
private predicate isSeedingConstruction(ClassInstanceExpr c, Expr arg) {
c.getConstructedType() instanceof SecureRandomNumberGenerator
and
c.getNumArgument() = 1
and
c.getConstructedType() instanceof SecureRandomNumberGenerator and
c.getNumArgument() = 1 and
c.getArgument(0) = arg
}
class PredictableSeedExpr extends Expr {
PredictableSeedExpr() {
this.(MethodAccess).getCallee() instanceof ReturnsPredictableExpr or
this instanceof CompileTimeConstantExpr or
this.(ArrayCreationExpr).getInit() instanceof PredictableSeedExpr or
this.(MethodAccess).getCallee() instanceof ReturnsPredictableExpr
or
this instanceof CompileTimeConstantExpr
or
this.(ArrayCreationExpr).getInit() instanceof PredictableSeedExpr
or
exists(ArrayInit init | init = this |
forall(Expr e | e = init.getAnInit() | e instanceof PredictableSeedExpr)
)
}
}
abstract class ReturnsPredictableExpr extends Method {}
abstract class ReturnsPredictableExpr extends Method { }
class ReturnsSystemTime extends ReturnsPredictableExpr {
ReturnsSystemTime() {
(this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("currentTimeMillis")) or
(
this.getDeclaringType().hasQualifiedName("java.lang", "System") and
this.hasName("currentTimeMillis")
)
or
(this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime"))
}
}

View File

@@ -1,5 +1,4 @@
/* Detection of strings and arrays of strings containing relative paths. */
import java
/**
@@ -13,10 +12,9 @@ predicate relativePath(Element tree, string command) {
text.regexpMatch("[^/\\\\ \t]*[ \t].*")
) and
command = text.replaceAll("\t", " ").splitAt(" ", 0).replaceAll("\"", "")
) or
exists(AddExpr add | tree = add |
relativePath(add.getLeftOperand(), command)
)
or
exists(AddExpr add | tree = add | relativePath(add.getLeftOperand(), command))
}
/**

View File

@@ -10,6 +10,7 @@
* in a fashion that the user can control. This includes authorization
* methods such as logins, and sending of data, etc.
*/
import java
private string suspicious() {
@@ -27,16 +28,18 @@ private string nonSuspicious() {
}
/** An expression that might contain sensitive data. */
abstract class SensitiveExpr extends Expr {
}
abstract class SensitiveExpr extends Expr { }
/** A method access that might produce sensitive data. */
class SensitiveMethodAccess extends SensitiveExpr, MethodAccess {
SensitiveMethodAccess() {
this.getMethod() instanceof SensitiveDataMethod or
this.getMethod() instanceof SensitiveDataMethod
or
// This is particularly to pick up methods with an argument like "password", which
// may indicate a lookup.
exists(string s | this.getAnArgument().(StringLiteral).getRepresentedString().toLowerCase() = s |
exists(string s |
this.getAnArgument().(StringLiteral).getRepresentedString().toLowerCase() = s
|
s.matches(suspicious()) and
not s.matches(nonSuspicious())
)
@@ -54,18 +57,16 @@ class SensitiveVarAccess extends SensitiveExpr, VarAccess {
}
/** A method that may produce sensitive data. */
abstract class SensitiveDataMethod extends Method {}
abstract class SensitiveDataMethod extends Method { }
class CredentialsMethod extends SensitiveDataMethod {
CredentialsMethod() {
exists(string s | s = this.getName().toLowerCase() |
s.matches(suspicious())
)
exists(string s | s = this.getName().toLowerCase() | s.matches(suspicious()))
}
}
/** A method whose execution may be sensitive. */
abstract class SensitiveExecutionMethod extends Method {}
abstract class SensitiveExecutionMethod extends Method { }
/** A method that may perform authorization. */
class AuthMethod extends SensitiveExecutionMethod {

View File

@@ -1,5 +1,4 @@
/* Definitions used by `SqlUnescaped.ql`. */
import semmle.code.java.security.ControlledString
import semmle.code.java.dataflow.TaintTracking
@@ -17,7 +16,8 @@ predicate builtFromUncontrolledConcat(Expr expr, Expr uncontrolled) {
or
// Recursive cases
exists(Expr other | builtFromUncontrolledConcat(other, uncontrolled) |
expr.(AddExpr).getAnOperand() = other or
expr.(AddExpr).getAnOperand() = other
or
exists(Variable var | var.getAnAssignedValue() = other and var.getAnAccess() = expr)
)
}

View File

@@ -12,24 +12,39 @@ class XssSink extends DataFlow::ExprNode {
exists(HttpServletResponseSendErrorMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getArgument(1)
) or
)
or
exists(ServletWriterSourceToWritingMethodFlowConfig writer, MethodAccess ma |
ma.getMethod() instanceof WritingMethod and
writer.hasFlowToExpr(ma.getQualifier()) and
this.getExpr() = ma.getArgument(_)
) or exists(Method m |
)
or
exists(Method m |
m.getDeclaringType() instanceof TypeWebView and
(m.getAReference().getArgument(0) = this.getExpr() and m.getName() = "loadData" or
m.getAReference().getArgument(0) = this.getExpr() and m.getName() = "loadUrl" or
m.getAReference().getArgument(1) = this.getExpr() and m.getName() = "loadDataWithBaseURL")
(
m.getAReference().getArgument(0) = this.getExpr() and m.getName() = "loadData"
or
m.getAReference().getArgument(0) = this.getExpr() and m.getName() = "loadUrl"
or
m.getAReference().getArgument(1) = this.getExpr() and m.getName() = "loadDataWithBaseURL"
)
)
}
}
class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking::Configuration {
ServletWriterSourceToWritingMethodFlowConfig() { this = "XSS::ServletWriterSourceToWritingMethodFlowConfig" }
ServletWriterSourceToWritingMethodFlowConfig() {
this = "XSS::ServletWriterSourceToWritingMethodFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ServletWriterSource }
override predicate isSink(DataFlow::Node sink) { exists(MethodAccess ma | sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod) }
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod
)
}
}
class WritingMethod extends Method {
@@ -45,8 +60,10 @@ class WritingMethod extends Method {
class ServletWriterSource extends MethodAccess {
ServletWriterSource() {
this.getMethod() instanceof ServletResponseGetWriterMethod or
this.getMethod() instanceof ServletResponseGetOutputStreamMethod or
this.getMethod() instanceof ServletResponseGetWriterMethod
or
this.getMethod() instanceof ServletResponseGetOutputStreamMethod
or
exists(Method m | m = this.getMethod() |
m.getDeclaringType().getQualifiedName() = "javax.servlet.jsp.JspContext" and
m.getName() = "getOut"