mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge branch 'master' into CWE-643
This commit is contained in:
12
java/ql/src/Customizations.qll
Normal file
12
java/ql/src/Customizations.qll
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Contains customizations to the standard library.
|
||||
*
|
||||
* This module is imported by `java.qll`, so any customizations defined here automatically
|
||||
* apply to all queries.
|
||||
*
|
||||
* Typical examples of customizations include adding new subclasses of abstract classes such as
|
||||
* the `RemoteFlowSource` and `AdditionalTaintStep` classes associated with the security queries
|
||||
* to model frameworks that are not covered by the standard library.
|
||||
*/
|
||||
|
||||
import java
|
||||
@@ -4,7 +4,7 @@ class Test {
|
||||
{
|
||||
String latlonCoords = args[1];
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
Process exec = rt.exec("cmd.exe /C latlon2utm.exe -" + latlonCoords);
|
||||
Process exec = rt.exec("cmd.exe /C latlon2utm.exe " + latlonCoords);
|
||||
}
|
||||
|
||||
// GOOD: use an array of arguments instead of executing a string
|
||||
|
||||
@@ -29,5 +29,12 @@ private class InsecureDefaultHttpResponseClassInstantiation extends InsecureNett
|
||||
}
|
||||
}
|
||||
|
||||
private class InsecureDefaultFullHttpResponseClassInstantiation extends InsecureNettyObjectCreation {
|
||||
InsecureDefaultFullHttpResponseClassInstantiation() {
|
||||
getConstructedType().hasQualifiedName("io.netty.handler.codec.http", "DefaultFullHttpResponse") and
|
||||
getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = false
|
||||
}
|
||||
}
|
||||
|
||||
from InsecureNettyObjectCreation new
|
||||
select new, "Response-splitting vulnerability due to header value verification being disabled."
|
||||
|
||||
1
java/ql/src/experimental/README.md
Normal file
1
java/ql/src/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -1,5 +1,6 @@
|
||||
/** Provides all default Java QL imports. */
|
||||
|
||||
import Customizations
|
||||
import semmle.code.FileSystem
|
||||
import semmle.code.Location
|
||||
import semmle.code.java.Annotation
|
||||
|
||||
@@ -167,6 +167,7 @@ class CompileTimeConstantExpr extends Expr {
|
||||
/**
|
||||
* Gets the string value of this expression, where possible.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
string getStringValue() {
|
||||
result = this.(StringLiteral).getRepresentedString()
|
||||
or
|
||||
|
||||
@@ -364,13 +364,45 @@ private predicate typeFlow(TypeFlowNode n, RefType t) {
|
||||
typeFlowJoin(lastRank(n), n, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate erasedTypeBound(RefType t) {
|
||||
exists(RefType t0 | typeFlow(_, t0) and t = t0.getErasure())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate typeBound(RefType t) { typeFlow(_, t) }
|
||||
|
||||
/**
|
||||
* Holds if we have a bound for `n` that is better than `t`, taking only erased
|
||||
* types into account.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate irrelevantErasedBound(TypeFlowNode n, RefType t) {
|
||||
exists(RefType bound |
|
||||
typeFlow(n, bound)
|
||||
or
|
||||
n.getType() = bound and typeFlow(n, _)
|
||||
|
|
||||
t = bound.getErasure().(RefType).getASourceSupertype+() and
|
||||
erasedTypeBound(t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we have a bound for `n` that is better than `t`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate irrelevantBound(TypeFlowNode n, RefType t) {
|
||||
exists(RefType bound | typeFlow(n, bound) or n.getType() = bound |
|
||||
t = bound.getErasure().(RefType).getASourceSupertype+()
|
||||
exists(RefType bound |
|
||||
typeFlow(n, bound) and
|
||||
t = bound.getASupertype+() and
|
||||
typeBound(t) and
|
||||
typeFlow(n, t) and
|
||||
not t.getASupertype*() = bound
|
||||
or
|
||||
n.getType() = bound and
|
||||
typeFlow(n, t) and
|
||||
t = bound.getASupertype*()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -380,7 +412,8 @@ private predicate irrelevantBound(TypeFlowNode n, RefType t) {
|
||||
*/
|
||||
private predicate bestTypeFlow(TypeFlowNode n, RefType t) {
|
||||
typeFlow(n, t) and
|
||||
not irrelevantBound(n, t.getErasure())
|
||||
not irrelevantErasedBound(n, t.getErasure()) and
|
||||
not irrelevantBound(n, t)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -161,10 +161,27 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) {
|
||||
/**
|
||||
* Holds if the step from `n1` to `n2` is either extracting a value from a
|
||||
* container, inserting a value into a container, or transforming one container
|
||||
* to another.
|
||||
* to another. This is restricted to cases where `n2` is the returned value of
|
||||
* a call.
|
||||
*/
|
||||
predicate containerStep(Expr n1, Expr n2) {
|
||||
qualifierToMethodStep(n1, n2) or
|
||||
predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1, n2) }
|
||||
|
||||
/**
|
||||
* Holds if the step from `n1` to `n2` is either extracting a value from a
|
||||
* container, inserting a value into a container, or transforming one container
|
||||
* to another. This is restricted to cases where the value of `n2` is being modified.
|
||||
*/
|
||||
predicate containerUpdateStep(Expr n1, Expr n2) {
|
||||
qualifierToArgumentStep(n1, n2) or
|
||||
argToQualifierStep(n1, n2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the step from `n1` to `n2` is either extracting a value from a
|
||||
* container, inserting a value into a container, or transforming one container
|
||||
* to another.
|
||||
*/
|
||||
predicate containerStep(Expr n1, Expr n2) {
|
||||
containerReturnValueStep(n1, n2) or
|
||||
containerUpdateStep(n1, n2)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
private import java
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon::Public
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
@@ -120,7 +120,7 @@ predicate jumpStep(Node node1, Node node2) {
|
||||
* Holds if `fa` is an access to an instance field that occurs as the
|
||||
* destination of an assignment of the value `src`.
|
||||
*/
|
||||
predicate instanceFieldAssign(Expr src, FieldAccess fa) {
|
||||
private predicate instanceFieldAssign(Expr src, FieldAccess fa) {
|
||||
exists(AssignExpr a |
|
||||
a.getSource() = src and
|
||||
a.getDest() = fa and
|
||||
@@ -324,3 +324,5 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
guard.controls(n.asExpr().getBasicBlock(), arg.getBooleanValue().booleanNot())
|
||||
)
|
||||
}
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
@@ -26,6 +26,8 @@ private newtype TNode =
|
||||
e instanceof Argument and not e.getType() instanceof ImmutableType
|
||||
or
|
||||
exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
|
||||
or
|
||||
exists(ArrayAccess aa | e = aa.getArray())
|
||||
} or
|
||||
TImplicitExprPostUpdate(InstanceAccessExt ia) {
|
||||
implicitInstanceArgument(_, ia)
|
||||
|
||||
@@ -41,6 +41,9 @@ predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
|
||||
or
|
||||
localAdditionalTaintUpdateStep(src.asExpr(),
|
||||
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
|
||||
or
|
||||
exists(Argument arg |
|
||||
src.asExpr() = arg and
|
||||
arg.isVararg() and
|
||||
@@ -105,30 +108,20 @@ private predicate localAdditionalTaintExprStep(Expr src, Expr sink) {
|
||||
or
|
||||
sink.(LogicExpr).getAnOperand() = src
|
||||
or
|
||||
exists(Assignment assign | assign.getSource() = src |
|
||||
sink = assign.getDest().(ArrayAccess).getArray()
|
||||
)
|
||||
or
|
||||
exists(EnhancedForStmt for, SsaExplicitUpdate v |
|
||||
for.getExpr() = src and
|
||||
v.getDefiningExpr() = for.getVariable() and
|
||||
v.getAFirstUse() = sink
|
||||
)
|
||||
or
|
||||
containerStep(src, sink)
|
||||
containerReturnValueStep(src, sink)
|
||||
or
|
||||
constructorStep(src, sink)
|
||||
or
|
||||
qualifierToMethodStep(src, sink)
|
||||
or
|
||||
qualifierToArgumentStep(src, sink)
|
||||
or
|
||||
argToMethodStep(src, sink)
|
||||
or
|
||||
argToArgStep(src, sink)
|
||||
or
|
||||
argToQualifierStep(src, sink)
|
||||
or
|
||||
comparisonStep(src, sink)
|
||||
or
|
||||
stringBuilderStep(src, sink)
|
||||
@@ -136,6 +129,26 @@ private predicate localAdditionalTaintExprStep(Expr src, Expr sink) {
|
||||
serializationStep(src, sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `src` to `sink` excluding
|
||||
* local data flow steps. That is, `src` and `sink` are likely to represent
|
||||
* different objects.
|
||||
* This is restricted to cases where the step updates the value of `sink`.
|
||||
*/
|
||||
private predicate localAdditionalTaintUpdateStep(Expr src, Expr sink) {
|
||||
exists(Assignment assign | assign.getSource() = src |
|
||||
sink = assign.getDest().(ArrayAccess).getArray()
|
||||
)
|
||||
or
|
||||
containerUpdateStep(src, sink)
|
||||
or
|
||||
qualifierToArgumentStep(src, sink)
|
||||
or
|
||||
argToArgStep(src, sink)
|
||||
or
|
||||
argToQualifierStep(src, sink)
|
||||
}
|
||||
|
||||
private class BulkData extends RefType {
|
||||
BulkData() {
|
||||
this.(Array).getElementType().(PrimitiveType).getName().regexpMatch("byte|char")
|
||||
@@ -242,7 +255,7 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) {
|
||||
}
|
||||
|
||||
/** Access to a method that passes taint from qualifier to argument. */
|
||||
private predicate qualifierToArgumentStep(Expr tracked, RValue sink) {
|
||||
private predicate qualifierToArgumentStep(Expr tracked, Expr sink) {
|
||||
exists(MethodAccess ma, int arg |
|
||||
taintPreservingQualifierToArgument(ma.getMethod(), arg) and
|
||||
tracked = ma.getQualifier() and
|
||||
@@ -367,10 +380,25 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
|
||||
taintPreservingArgumentToMethod(m, i) and
|
||||
tracked = sink.(MethodAccess).getArgument(i)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
taintPreservingArgumentToMethod(ma.getMethod()) and
|
||||
tracked = ma.getAnArgument() and
|
||||
sink = ma
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `method` is a library method that return tainted data if its
|
||||
* Holds if `method` is a library method that returns tainted data if any
|
||||
* of its arguments are tainted.
|
||||
*/
|
||||
private predicate taintPreservingArgumentToMethod(Method method) {
|
||||
method.getDeclaringType() instanceof TypeString and
|
||||
(method.hasName("format") or method.hasName("join"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `method` is a library method that returns tainted data if its
|
||||
* `arg`th argument is tainted.
|
||||
*/
|
||||
private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
@@ -458,7 +486,7 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
* Holds if `tracked` and `sink` are arguments to a method that transfers taint
|
||||
* between arguments.
|
||||
*/
|
||||
private predicate argToArgStep(Expr tracked, RValue sink) {
|
||||
private predicate argToArgStep(Expr tracked, Expr sink) {
|
||||
exists(MethodAccess ma, Method method, int input, int output |
|
||||
taintPreservingArgToArg(method, input, output) and
|
||||
ma.getMethod() = method and
|
||||
|
||||
@@ -305,6 +305,7 @@ private module Unification {
|
||||
arg2 = t2.getTypeArgument(pos)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate failsUnification(Type t1, Type t2) {
|
||||
unificationTargets(t1, t2) and
|
||||
(
|
||||
|
||||
1
java/ql/test/experimental/README.md
Normal file
1
java/ql/test/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -32,7 +32,6 @@ nodes
|
||||
| A2.java:15:15:15:28 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A2.java:27:27:27:34 | o : Number | semmle.label | o : Number |
|
||||
| A2.java:29:9:29:9 | o | semmle.label | o |
|
||||
| A2.java:37:10:37:10 | o | semmle.label | o |
|
||||
| A.java:14:29:14:36 | o : Number | semmle.label | o : Number |
|
||||
| A.java:16:9:16:9 | o | semmle.label | o |
|
||||
| A.java:20:30:20:37 | o : Number | semmle.label | o : Number |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
| Read | A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
|
||||
| Store | A.java:9:16:9:16 | x | A.java:9:5:9:8 | this [post update] | A.java:2:7:2:9 | foo |
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplCommon::Public
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplCommon
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private
|
||||
|
||||
private predicate read(Node n1, Content f, Node n2) {
|
||||
readDirect(n1, f, n2) or
|
||||
argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2)
|
||||
}
|
||||
|
||||
private predicate store(Node n1, Content f, Node n2) {
|
||||
storeDirect(n1, f, n2) or
|
||||
argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2)
|
||||
}
|
||||
|
||||
from Node n1, Content f, Node n2, string k
|
||||
where
|
||||
read(n1, f, n2) and k = "Read"
|
||||
|
||||
65
java/ql/test/library-tests/dataflow/taint-ioutils/Test.java
Normal file
65
java/ql/test/library-tests/dataflow/taint-ioutils/Test.java
Normal file
@@ -0,0 +1,65 @@
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
class Test {
|
||||
public static void ioutils() {
|
||||
InputStream inp = new FileInputStream("test"); // user input
|
||||
|
||||
InputStream buf = IOUtils.buffer(inp);
|
||||
List<String> lines = IOUtils.readLines(inp, "UTF-8");
|
||||
byte[] bytes = IOUtils.readFully(inp, 1000);
|
||||
InputStream buf2 = IOUtils.toBufferedInputStream(inp);
|
||||
Reader bufread = IOUtils.toBufferedReader(new InputStreamReader(inp));
|
||||
byte[] bytes2 = IOUtils.toByteArray(inp, 1000);
|
||||
char[] chars = IOUtils.toCharArray(inp, "UTF-8");
|
||||
String s = IOUtils.toString(inp, "UTF-8");
|
||||
InputStream is = IOUtils.toInputStream(s, "UTF-8");
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
writer.toString(); // not tainted
|
||||
IOUtils.copy(inp, writer, "UTF-8");
|
||||
writer.toString(); // tainted
|
||||
|
||||
writer = new StringWriter();
|
||||
writer.toString(); // not tainted
|
||||
IOUtils.copyLarge(bufread, writer);
|
||||
writer.toString(); // tainted
|
||||
|
||||
byte x;
|
||||
byte[] tgt = new byte[100];
|
||||
x = tgt[0]; // not tainted
|
||||
IOUtils.read(inp, tgt);
|
||||
x = tgt[0]; // tainted
|
||||
|
||||
tgt = new byte[100];
|
||||
x = tgt[0]; // not tainted
|
||||
IOUtils.readFully(inp, tgt);
|
||||
x = tgt[0]; // tainted
|
||||
|
||||
writer = new StringWriter();
|
||||
writer.toString(); // not tainted
|
||||
IOUtils.write(chars, writer);
|
||||
writer.toString(); // tainted
|
||||
|
||||
writer = new StringWriter();
|
||||
writer.toString(); // not tainted
|
||||
IOUtils.writeChunked(chars, writer);
|
||||
writer.toString(); // tainted
|
||||
|
||||
writer = new StringWriter();
|
||||
writer.toString(); // not tainted
|
||||
IOUtils.writeLines(lines, "\n", writer);
|
||||
writer.toString(); // tainted
|
||||
|
||||
writer = new StringWriter();
|
||||
writer.toString(); // not tainted
|
||||
IOUtils.writeLines(new ArrayList<String>(), s, writer);
|
||||
writer.toString(); // tainted
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
| Test.java:12:21:12:47 | new FileInputStream(...) |
|
||||
| Test.java:14:21:14:39 | buffer(...) |
|
||||
| Test.java:14:36:14:38 | inp |
|
||||
| Test.java:15:24:15:54 | readLines(...) |
|
||||
| Test.java:15:42:15:44 | inp |
|
||||
| Test.java:16:18:16:45 | readFully(...) |
|
||||
| Test.java:16:36:16:38 | inp |
|
||||
| Test.java:17:22:17:55 | toBufferedInputStream(...) |
|
||||
| Test.java:17:52:17:54 | inp |
|
||||
| Test.java:18:20:18:71 | toBufferedReader(...) |
|
||||
| Test.java:18:45:18:70 | new InputStreamReader(...) |
|
||||
| Test.java:18:67:18:69 | inp |
|
||||
| Test.java:19:19:19:48 | toByteArray(...) |
|
||||
| Test.java:19:39:19:41 | inp |
|
||||
| Test.java:20:18:20:50 | toCharArray(...) |
|
||||
| Test.java:20:38:20:40 | inp |
|
||||
| Test.java:21:14:21:43 | toString(...) |
|
||||
| Test.java:21:31:21:33 | inp |
|
||||
| Test.java:22:20:22:52 | toInputStream(...) |
|
||||
| Test.java:22:42:22:42 | s |
|
||||
| Test.java:26:16:26:18 | inp |
|
||||
| Test.java:26:21:26:26 | writer [post update] |
|
||||
| Test.java:27:3:27:8 | writer |
|
||||
| Test.java:27:3:27:19 | toString(...) |
|
||||
| Test.java:31:21:31:27 | bufread |
|
||||
| Test.java:31:30:31:35 | writer [post update] |
|
||||
| Test.java:32:3:32:8 | writer |
|
||||
| Test.java:32:3:32:19 | toString(...) |
|
||||
| Test.java:37:16:37:18 | inp |
|
||||
| Test.java:37:21:37:23 | tgt [post update] |
|
||||
| Test.java:38:3:38:12 | ...=... |
|
||||
| Test.java:38:7:38:9 | tgt |
|
||||
| Test.java:38:7:38:12 | ...[...] |
|
||||
| Test.java:42:21:42:23 | inp |
|
||||
| Test.java:42:26:42:28 | tgt [post update] |
|
||||
| Test.java:43:3:43:12 | ...=... |
|
||||
| Test.java:43:7:43:9 | tgt |
|
||||
| Test.java:43:7:43:12 | ...[...] |
|
||||
| Test.java:47:17:47:21 | chars |
|
||||
| Test.java:47:24:47:29 | writer [post update] |
|
||||
| Test.java:48:3:48:8 | writer |
|
||||
| Test.java:48:3:48:19 | toString(...) |
|
||||
| Test.java:52:24:52:28 | chars |
|
||||
| Test.java:52:31:52:36 | writer [post update] |
|
||||
| Test.java:53:3:53:8 | writer |
|
||||
| Test.java:53:3:53:19 | toString(...) |
|
||||
| Test.java:57:22:57:26 | lines |
|
||||
| Test.java:57:35:57:40 | writer [post update] |
|
||||
| Test.java:58:3:58:8 | writer |
|
||||
| Test.java:58:3:58:19 | toString(...) |
|
||||
| Test.java:62:47:62:47 | s |
|
||||
| Test.java:62:50:62:55 | writer [post update] |
|
||||
| Test.java:63:3:63:8 | writer |
|
||||
| Test.java:63:3:63:19 | toString(...) |
|
||||
@@ -0,0 +1,15 @@
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "qltest:dataflow:ioutils" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UserInput }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { any() }
|
||||
}
|
||||
|
||||
from UserInput u, DataFlow::Node e, Conf config
|
||||
where config.hasFlow(u, e) and e.getEnclosingCallable().hasName("ioutils")
|
||||
select e
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-io-2.6
|
||||
@@ -24,4 +24,52 @@ public class A {
|
||||
bInput.read(b2);
|
||||
sink(b2);
|
||||
}
|
||||
|
||||
void streamWrite(ByteArrayOutputStream baos, byte[] data) {
|
||||
baos.write(data);
|
||||
}
|
||||
|
||||
void test3(ByteArrayOutputStream baos) {
|
||||
streamWrite(baos, taint());
|
||||
sink(baos.toByteArray());
|
||||
}
|
||||
|
||||
static class BaosHolder {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
void streamWriteHolder(BaosHolder bh, byte[] data) {
|
||||
bh.baos.write(data);
|
||||
}
|
||||
|
||||
void test4(BaosHolder bh) {
|
||||
streamWriteHolder(bh, taint());
|
||||
sink(bh.baos.toByteArray());
|
||||
}
|
||||
|
||||
static class DataHolder {
|
||||
byte[] data = new byte[10];
|
||||
}
|
||||
|
||||
void test5_a(DataHolder dh) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(taint());
|
||||
bais.read(dh.data);
|
||||
test5_b(dh);
|
||||
}
|
||||
|
||||
void test5_b(DataHolder dh) {
|
||||
sink(dh.data);
|
||||
}
|
||||
|
||||
void arrayWrite(byte[] from, byte[] to) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
}
|
||||
|
||||
void test6() {
|
||||
byte[] b = new byte[10];
|
||||
arrayWrite(taint(), b);
|
||||
sink(b);
|
||||
}
|
||||
}
|
||||
|
||||
159
java/ql/test/library-tests/dataflow/taint/B.java
Normal file
159
java/ql/test/library-tests/dataflow/taint/B.java
Normal file
@@ -0,0 +1,159 @@
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class B {
|
||||
public static String[] taint() { return new String[] { "tainted" }; }
|
||||
|
||||
public static void sink(Object o) { }
|
||||
|
||||
public static void maintest() {
|
||||
String[] args = taint();
|
||||
// tainted - access to main args
|
||||
String[] aaaargs = args;
|
||||
sink(aaaargs);
|
||||
// tainted - access to tainted array
|
||||
String s = args[0];
|
||||
sink(s);
|
||||
// tainted - concatenation of tainted string
|
||||
String concat = "Look at me " + s + ", I'm tainted!";
|
||||
sink(concat);
|
||||
// tainted - parenthesised
|
||||
String pars = (concat);
|
||||
sink(pars);
|
||||
// tainted method argument, implies tainted return value
|
||||
String method = tainty(pars);
|
||||
sink(method);
|
||||
// tainted - complex
|
||||
String complex = ("Look at me " + args[0]) + ", I'm tainted!";
|
||||
sink(complex);
|
||||
// tainted - data preserving constructors
|
||||
String constructed = new String(complex);
|
||||
sink(constructed);
|
||||
// tainted - unsafe escape
|
||||
String badEscape = constructed.replaceAll("(<script>)", "");
|
||||
sink(badEscape);
|
||||
// tainted - tokenized string
|
||||
String token = new StringTokenizer(badEscape).nextToken();
|
||||
sink(token);
|
||||
|
||||
// not tainted
|
||||
String safe = notTainty(complex);
|
||||
sink(safe);
|
||||
String shouldBeFine = taintyOtherArg(safe, complex);
|
||||
sink(shouldBeFine);
|
||||
// non-whitelisted constructors don't pass taint
|
||||
StringWrapper herring = new StringWrapper(complex);
|
||||
sink(herring);
|
||||
|
||||
// tainted equality check with constant
|
||||
boolean cond = "foo" == s;
|
||||
sink(cond);
|
||||
// tainted logic with tainted operand
|
||||
boolean logic = cond && safe();
|
||||
sink(logic);
|
||||
// tainted condition
|
||||
sink(concat.endsWith("I'm tainted"));
|
||||
// tainted
|
||||
logic = safe() || cond;
|
||||
sink(logic);
|
||||
// tainted, use of equals
|
||||
logic = badEscape.equals("constant");
|
||||
sink(logic);
|
||||
|
||||
// not tainted
|
||||
boolean okay = s == shouldBeFine;
|
||||
sink(okay);
|
||||
|
||||
// methods on string that pass on taint
|
||||
String trimmed = s.trim();
|
||||
sink(trimmed);
|
||||
String[] split = s.split(" ");
|
||||
sink(split);
|
||||
String lower = s.toLowerCase();
|
||||
sink(lower);
|
||||
String upper = s.toUpperCase();
|
||||
sink(upper);
|
||||
byte[] bytes = s.getBytes("UTF-8");
|
||||
sink(bytes);
|
||||
String toString = s.toString();
|
||||
sink(toString);
|
||||
String subs = s.substring(1, 10);
|
||||
sink(subs);
|
||||
String repl = "some constant".replace(" ", s);
|
||||
sink(repl);
|
||||
String replAll = "some constant".replaceAll(" ", s);
|
||||
sink(replAll);
|
||||
String replFirst = "some constant".replaceFirst(" ", s);
|
||||
sink(replFirst);
|
||||
|
||||
ByteArrayOutputStream baos = null;
|
||||
ObjectOutput oos = null;
|
||||
ByteArrayInputStream bais = null;
|
||||
ObjectInputStream ois = null;
|
||||
try
|
||||
{
|
||||
// serialization of tainted string
|
||||
baos = new ByteArrayOutputStream();
|
||||
oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(s);
|
||||
byte[] serializedData = baos.toByteArray(); // tainted
|
||||
sink(serializedData);
|
||||
// serialization of fixed string
|
||||
baos = new ByteArrayOutputStream();
|
||||
oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject("not tainted");
|
||||
byte[] serializedData2 = baos.toByteArray(); // *not* tainted
|
||||
sink(serializedData2);
|
||||
|
||||
// de-serialization of tainted string
|
||||
bais = new ByteArrayInputStream(serializedData);
|
||||
ois = new ObjectInputStream(bais);
|
||||
String deserializedData = (String)ois.readObject(); // tainted
|
||||
sink(deserializedData);
|
||||
} catch (IOException e) {
|
||||
// ignored in test code
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignored in test code
|
||||
}
|
||||
|
||||
// tainted array initializers
|
||||
String[] taintedArray = new String[] { s };
|
||||
sink(taintedArray);
|
||||
String[][] taintedArray2 = new String[][] { { s } };
|
||||
sink(taintedArray2);
|
||||
String[][][] taintedArray3 = new String[][][] { { { s } } };
|
||||
sink(taintedArray3);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public static String tainty(String arg) {
|
||||
// tainted return value
|
||||
return arg;
|
||||
}
|
||||
|
||||
public static String taintyOtherArg(String safe, String tainted) {
|
||||
return safe;
|
||||
}
|
||||
|
||||
public static String notTainty(String arg) {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
public static class StringWrapper {
|
||||
public String wrapped;
|
||||
|
||||
public StringWrapper(String s) {
|
||||
this.wrapped = s;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean safe() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
38
java/ql/test/library-tests/dataflow/taint/MethodFlow.java
Normal file
38
java/ql/test/library-tests/dataflow/taint/MethodFlow.java
Normal file
@@ -0,0 +1,38 @@
|
||||
public class MethodFlow {
|
||||
public static String taint() { return "tainted"; }
|
||||
|
||||
public static void sink(String s) { }
|
||||
|
||||
public void test() {
|
||||
String tainted = taint();
|
||||
sink(tainted);
|
||||
String tainted2 = notNull(taint());
|
||||
sink(tainted2);
|
||||
String tainted3 = wrapNotNull(taint());
|
||||
sink(tainted3);
|
||||
|
||||
String safe = notNull("a constant");
|
||||
sink(safe);
|
||||
|
||||
String diffString = returnDiffString(taint());
|
||||
sink(diffString);
|
||||
}
|
||||
|
||||
public <T> T notNull(T x) {
|
||||
if (x == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public <T> T wrapNotNull(T x) {
|
||||
T res = notNull(x);
|
||||
sink("Logged: " + res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public String returnDiffString(String x) {
|
||||
sink("Received: " + x);
|
||||
return "OK";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
public class StringBuilderTests {
|
||||
public static String taint() { return "tainted"; }
|
||||
|
||||
public static void sink(String s) { }
|
||||
|
||||
static void stringBuilderBad() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("from preferences select locale where user='");
|
||||
sb.append(taint());
|
||||
sb.append("'");
|
||||
sink(sb.toString());
|
||||
}
|
||||
|
||||
static void stringBuilderOkay() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("from preferences select locale where user='");
|
||||
sb.append("fred");
|
||||
sb.append("'");
|
||||
sink(sb.toString());
|
||||
}
|
||||
|
||||
static void stringBufferBad() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("from preferences select locale where user='");
|
||||
sb.append(taint());
|
||||
sb.append("'");
|
||||
sink(sb.toString());
|
||||
}
|
||||
|
||||
static void stringBuilderNoVarBad() {
|
||||
sink(new StringBuilder()
|
||||
.append("from preferences select locale where user='")
|
||||
.append(taint())
|
||||
.append("'").toString()
|
||||
);
|
||||
}
|
||||
|
||||
static void stringBuilderConstructorBad() {
|
||||
StringBuilder sb = new StringBuilder(taint());
|
||||
sb.append("from preferences select locale where user='");
|
||||
sb.append("fred");
|
||||
sb.append("'");
|
||||
sink(sb.toString());
|
||||
}
|
||||
|
||||
static void stringBuilderMultipleAppendsBad() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("from preferences select locale where user='").append(taint());
|
||||
sb.append("'");
|
||||
sink(sb.toString());
|
||||
}
|
||||
|
||||
static void stringBuilderReplaceBad() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("from preferences select locale where user='placeholder'");
|
||||
sb.replace(45, 57, taint());
|
||||
sink(sb.toString());
|
||||
}
|
||||
|
||||
static void stringBuilderInsertBad() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("from preferences select locale where user=''");
|
||||
sb.insert(45, taint());
|
||||
sink(sb.toString());
|
||||
}
|
||||
}
|
||||
26
java/ql/test/library-tests/dataflow/taint/Varargs.java
Normal file
26
java/ql/test/library-tests/dataflow/taint/Varargs.java
Normal file
@@ -0,0 +1,26 @@
|
||||
public class Varargs {
|
||||
public String taint() { return "tainted"; }
|
||||
|
||||
public void sink(String s) { }
|
||||
|
||||
public void sources() {
|
||||
f1(taint());
|
||||
f2(taint(), taint());
|
||||
f3(new String[] { taint(), "" });
|
||||
}
|
||||
|
||||
public void f1(String... ss) {
|
||||
String s = ss[0];
|
||||
sink(s);
|
||||
}
|
||||
|
||||
public void f2(String... ss) {
|
||||
String s = ss[0];
|
||||
sink(s);
|
||||
}
|
||||
|
||||
public void f3(String... ss) {
|
||||
String s = ss[0];
|
||||
sink(s);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,51 @@
|
||||
| A.java:10:19:10:25 | taint(...) | A.java:15:10:15:11 | b2 |
|
||||
| A.java:20:19:20:25 | taint(...) | A.java:25:10:25:11 | b2 |
|
||||
| A.java:33:23:33:29 | taint(...) | A.java:34:10:34:27 | toByteArray(...) |
|
||||
| A.java:46:27:46:33 | taint(...) | A.java:47:10:47:30 | toByteArray(...) |
|
||||
| A.java:55:58:55:64 | taint(...) | A.java:61:10:61:16 | dh.data |
|
||||
| A.java:72:16:72:22 | taint(...) | A.java:73:10:73:10 | b |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:18:10:18:16 | aaaargs |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:21:10:21:10 | s |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:24:10:24:15 | concat |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:27:10:27:13 | pars |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:30:10:30:15 | method |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:33:10:33:16 | complex |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:36:10:36:20 | constructed |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:39:10:39:18 | badEscape |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:42:10:42:14 | token |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:55:10:55:13 | cond |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:58:10:58:14 | logic |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:60:10:60:39 | endsWith(...) |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:63:10:63:14 | logic |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:66:10:66:14 | logic |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:74:10:74:16 | trimmed |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:76:10:76:14 | split |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:78:10:78:14 | lower |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:80:10:80:14 | upper |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:82:10:82:14 | bytes |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:84:10:84:17 | toString |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:86:10:86:13 | subs |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:88:10:88:13 | repl |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:90:10:90:16 | replAll |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:92:10:92:18 | replFirst |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:105:12:105:25 | serializedData |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:117:12:117:27 | deserializedData |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:126:10:126:21 | taintedArray |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:128:10:128:22 | taintedArray2 |
|
||||
| B.java:15:21:15:27 | taint(...) | B.java:130:10:130:22 | taintedArray3 |
|
||||
| MethodFlow.java:7:22:7:28 | taint(...) | MethodFlow.java:8:10:8:16 | tainted |
|
||||
| MethodFlow.java:9:31:9:37 | taint(...) | MethodFlow.java:10:10:10:17 | tainted2 |
|
||||
| MethodFlow.java:11:35:11:41 | taint(...) | MethodFlow.java:12:10:12:17 | tainted3 |
|
||||
| MethodFlow.java:11:35:11:41 | taint(...) | MethodFlow.java:30:10:30:25 | ... + ... |
|
||||
| MethodFlow.java:17:42:17:48 | taint(...) | MethodFlow.java:35:10:35:25 | ... + ... |
|
||||
| StringBuilderTests.java:9:15:9:21 | taint(...) | StringBuilderTests.java:11:10:11:22 | toString(...) |
|
||||
| StringBuilderTests.java:25:15:25:21 | taint(...) | StringBuilderTests.java:27:10:27:22 | toString(...) |
|
||||
| StringBuilderTests.java:33:15:33:21 | taint(...) | StringBuilderTests.java:31:10:34:29 | toString(...) |
|
||||
| StringBuilderTests.java:39:42:39:48 | taint(...) | StringBuilderTests.java:43:10:43:22 | toString(...) |
|
||||
| StringBuilderTests.java:48:69:48:75 | taint(...) | StringBuilderTests.java:50:10:50:22 | toString(...) |
|
||||
| StringBuilderTests.java:56:24:56:30 | taint(...) | StringBuilderTests.java:57:10:57:22 | toString(...) |
|
||||
| StringBuilderTests.java:63:19:63:25 | taint(...) | StringBuilderTests.java:64:10:64:22 | toString(...) |
|
||||
| Varargs.java:7:8:7:14 | taint(...) | Varargs.java:14:10:14:10 | s |
|
||||
| Varargs.java:8:8:8:14 | taint(...) | Varargs.java:19:10:19:10 | s |
|
||||
| Varargs.java:8:17:8:23 | taint(...) | Varargs.java:19:10:19:10 | s |
|
||||
| Varargs.java:9:23:9:29 | taint(...) | Varargs.java:24:10:24:10 | s |
|
||||
|
||||
@@ -34,4 +34,38 @@ public class A {
|
||||
Box b4 = Box.mk(taint());
|
||||
sink(b4.getS1());
|
||||
}
|
||||
|
||||
static class Box2 {
|
||||
String s;
|
||||
String getS() { return s; }
|
||||
void setS(String s) { this.s = s; }
|
||||
|
||||
Box2(String s) {
|
||||
setS(s + "1");
|
||||
}
|
||||
String getS1() { return getS() + "2"; }
|
||||
String getS2() { return step(getS() + "_") + "2"; }
|
||||
void setS1(String s) { setS("3" + s); }
|
||||
void setS2(String s) { setS("3" + step("_" + s)); }
|
||||
static Box2 mk(String s) {
|
||||
Box2 b = new Box2("");
|
||||
b.setS(step(s));
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
void foo2(Box2 b1, Box2 b2) {
|
||||
b1.setS1(taint());
|
||||
sink(b1.getS1());
|
||||
|
||||
b2.setS2(taint());
|
||||
sink(b2.getS2());
|
||||
|
||||
String t3 = taint();
|
||||
Box2 b3 = new Box2(step(t3));
|
||||
sink(b3.s);
|
||||
|
||||
Box2 b4 = Box2.mk(taint());
|
||||
sink(b4.getS1());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
| A.java:27:14:27:20 | taint(...) | A.java:28:10:28:19 | getS2(...) |
|
||||
| A.java:30:17:30:23 | taint(...) | A.java:32:10:32:13 | b3.s |
|
||||
| A.java:34:21:34:27 | taint(...) | A.java:35:10:35:19 | getS1(...) |
|
||||
| A.java:58:14:58:20 | taint(...) | A.java:59:10:59:19 | getS1(...) |
|
||||
| A.java:61:14:61:20 | taint(...) | A.java:62:10:62:19 | getS2(...) |
|
||||
| A.java:64:17:64:23 | taint(...) | A.java:66:10:66:13 | b3.s |
|
||||
| A.java:68:23:68:29 | taint(...) | A.java:69:10:69:19 | getS1(...) |
|
||||
|
||||
49
java/ql/test/library-tests/dataflow/taintsources/A.java
Normal file
49
java/ql/test/library-tests/dataflow/taintsources/A.java
Normal file
@@ -0,0 +1,49 @@
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class A {
|
||||
public static void main(String[] args) {
|
||||
String[] a = args; // user input
|
||||
String s = args[0]; // user input
|
||||
}
|
||||
|
||||
public static void userInput() throws SQLException, IOException, MalformedURLException {
|
||||
System.getenv("test"); // user input
|
||||
class TestServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
req.getParameter("test"); // remote user input
|
||||
req.getHeader("test"); // remote user input
|
||||
req.getQueryString(); // remote user input
|
||||
req.getCookies()[0].getValue(); // remote user input
|
||||
}
|
||||
}
|
||||
new Properties().getProperty("test"); // user input
|
||||
System.getProperty("test"); // user input
|
||||
new Object() {
|
||||
public void test(ResultSet rs) throws SQLException {
|
||||
rs.getString(0); // user input
|
||||
}
|
||||
};
|
||||
new URL("test").openConnection().getInputStream(); // remote user input
|
||||
new Socket("test", 1234).getInputStream(); // remote user input
|
||||
InetAddress.getByName("test").getHostName(); // remote user input
|
||||
|
||||
System.in.read(); // user input
|
||||
new FileInputStream("test").read(); // user input
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package security.library.dataflow;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface RmiFlow extends Remote {
|
||||
String listDirectory(String path);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package security.library.dataflow;
|
||||
|
||||
public class RmiFlowImpl implements RmiFlow {
|
||||
public String listDirectory(String path) {
|
||||
String command = "ls " + path;
|
||||
Runtime.getRuntime().exec(command);
|
||||
return "pretend there are some results here";
|
||||
}
|
||||
|
||||
public String notRemotable(String path) {
|
||||
String command = "ls " + path;
|
||||
Runtime.getRuntime().exec(command);
|
||||
return "pretend there are some results here";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
| A.java:17:27:17:39 | args | A.java:17:27:17:39 | args |
|
||||
| A.java:17:27:17:39 | args | A.java:18:18:18:21 | args |
|
||||
| A.java:17:27:17:39 | args | A.java:19:16:19:19 | args |
|
||||
| A.java:17:27:17:39 | args | A.java:19:16:19:22 | ...[...] |
|
||||
| A.java:23:5:23:25 | getenv(...) | A.java:23:5:23:25 | getenv(...) |
|
||||
| A.java:34:5:34:40 | getProperty(...) | A.java:34:5:34:40 | getProperty(...) |
|
||||
| A.java:35:5:35:30 | getProperty(...) | A.java:35:5:35:30 | getProperty(...) |
|
||||
| A.java:38:9:38:23 | getString(...) | A.java:38:9:38:23 | getString(...) |
|
||||
| A.java:45:5:45:13 | System.in | A.java:45:5:45:13 | System.in |
|
||||
| A.java:46:5:46:31 | new FileInputStream(...) | A.java:46:5:46:31 | new FileInputStream(...) |
|
||||
18
java/ql/test/library-tests/dataflow/taintsources/local.ql
Normal file
18
java/ql/test/library-tests/dataflow/taintsources/local.ql
Normal file
@@ -0,0 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "remote taint conf" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n instanceof UserInput and
|
||||
not n instanceof RemoteFlowSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) { any() }
|
||||
}
|
||||
|
||||
from DataFlow::Node src, DataFlow::Node sink, Conf conf
|
||||
where conf.hasFlow(src, sink)
|
||||
select src, sink
|
||||
1
java/ql/test/library-tests/dataflow/taintsources/options
Normal file
1
java/ql/test/library-tests/dataflow/taintsources/options
Normal file
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4
|
||||
@@ -0,0 +1,11 @@
|
||||
| A.java:28:9:28:32 | getParameter(...) | A.java:28:9:28:32 | getParameter(...) |
|
||||
| A.java:29:9:29:29 | getHeader(...) | A.java:29:9:29:29 | getHeader(...) |
|
||||
| A.java:30:9:30:28 | getQueryString(...) | A.java:30:9:30:28 | getQueryString(...) |
|
||||
| A.java:31:9:31:38 | getValue(...) | A.java:31:9:31:38 | getValue(...) |
|
||||
| A.java:41:5:41:53 | getInputStream(...) | A.java:41:5:41:53 | getInputStream(...) |
|
||||
| A.java:42:5:42:45 | getInputStream(...) | A.java:42:5:42:45 | getInputStream(...) |
|
||||
| A.java:43:5:43:47 | getHostName(...) | A.java:43:5:43:47 | getHostName(...) |
|
||||
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:4:30:4:40 | path |
|
||||
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:20:5:31 | ... + ... |
|
||||
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:28:5:31 | path |
|
||||
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:6:29:6:35 | command |
|
||||
15
java/ql/test/library-tests/dataflow/taintsources/remote.ql
Normal file
15
java/ql/test/library-tests/dataflow/taintsources/remote.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "remote taint conf" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) { n instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node n) { any() }
|
||||
}
|
||||
|
||||
from DataFlow::Node src, DataFlow::Node sink, Conf conf
|
||||
where conf.hasFlow(src, sink)
|
||||
select src, sink
|
||||
@@ -1,9 +1,7 @@
|
||||
| A.java:9:10:9:11 | f1 | ArrayList<Long> | true |
|
||||
| A.java:10:10:10:10 | l | List<Long> | false |
|
||||
| A.java:11:19:11:20 | f2 | List<Long> | false |
|
||||
| A.java:12:16:12:16 | x | List<Long> | false |
|
||||
| A.java:14:9:14:9 | y | A | false |
|
||||
| A.java:18:11:18:12 | l2 | List<Integer> | false |
|
||||
| A.java:19:9:19:9 | y | List<Integer> | false |
|
||||
| A.java:26:14:26:14 | o | List<Long> | false |
|
||||
| A.java:34:11:34:11 | x | Integer | false |
|
||||
|
||||
@@ -208,4 +208,16 @@ public class C {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ex15(Object o1, Object o2) {
|
||||
if (o1 == null && o2 != null) {
|
||||
return;
|
||||
}
|
||||
if (o1 == o2) {
|
||||
return;
|
||||
}
|
||||
if (o1.equals(o2)) { // NPE - false positive
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,5 +30,6 @@
|
||||
| C.java:144:15:144:15 | a | Variable $@ may be null here as suggested by $@ null guard. | C.java:141:20:141:26 | a | a | C.java:142:13:142:21 | ... == ... | this |
|
||||
| C.java:188:9:188:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:181:5:181:22 | Object obj | obj | C.java:181:12:181:21 | obj | this |
|
||||
| C.java:207:9:207:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:201:5:201:22 | Object obj | obj | C.java:201:12:201:21 | obj | this |
|
||||
| C.java:219:9:219:10 | o1 | Variable $@ may be null here as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this |
|
||||
| F.java:11:5:11:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this |
|
||||
| F.java:17:5:17:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:14:18:14:27 | obj | obj | F.java:15:9:15:19 | ... == ... | this |
|
||||
|
||||
14
java/ql/test/stubs/apache-commons-io-2.6/LICENSE.txt
Normal file
14
java/ql/test/stubs/apache-commons-io-2.6/LICENSE.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.apache.commons.io;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class IOUtils {
|
||||
public static BufferedInputStream buffer(InputStream inputStream) { return null; }
|
||||
public static void copy(InputStream input, Writer output, String inputEncoding) throws IOException { }
|
||||
public static long copyLarge(Reader input, Writer output) throws IOException { return 42; }
|
||||
public static int read(InputStream input, byte[] buffer) throws IOException { return 42; }
|
||||
public static void readFully(InputStream input, byte[] buffer) throws IOException { }
|
||||
public static byte[] readFully(InputStream input, int length) throws IOException { return null; }
|
||||
public static List<String> readLines(InputStream input, String encoding) throws IOException { return null; }
|
||||
public static InputStream toBufferedInputStream(InputStream input) throws IOException { return null; }
|
||||
public static BufferedReader toBufferedReader(Reader reader) { return null; }
|
||||
public static byte[] toByteArray(InputStream input, int size) throws IOException { return null; }
|
||||
public static char[] toCharArray(InputStream is, String encoding) throws IOException { return null; }
|
||||
public static InputStream toInputStream(String input, String encoding) throws IOException { return null; }
|
||||
public static String toString(InputStream input, String encoding) throws IOException { return null; }
|
||||
public static void write(char[] data, Writer output) throws IOException { }
|
||||
public static void writeChunked(char[] data, Writer output) throws IOException { }
|
||||
public static void writeLines(Collection<?> lines, String lineEnding, Writer writer) throws IOException { }
|
||||
}
|
||||
Reference in New Issue
Block a user