mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Java: Autoformat semmle.code.java.security.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user