Skip to content

Commit b495e1e

Browse files
authored
Merge pull request github#5411 from aschackmull/java/dataflow-lambda-dispatch
Java: Bugfix dispatch to lambda in call context.
2 parents 0bfeba5 + d1f30d9 commit b495e1e

File tree

6 files changed

+143
-5
lines changed

6 files changed

+143
-5
lines changed

java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ private module DispatchImpl {
4141
)
4242
}
4343

44+
private RefType getPreciseType(Expr e) {
45+
result = e.(FunctionalExpr).getConstructedType()
46+
or
47+
not e instanceof FunctionalExpr and result = e.getType()
48+
}
49+
4450
/**
4551
* Holds if the `i`th argument of `ctx` has type `t` and `ctx` is a
4652
* relevant call context.
@@ -55,7 +61,7 @@ private module DispatchImpl {
5561
ctx.getArgument(i) = arg
5662
|
5763
src = variableTrack(arg) and
58-
srctype = src.getType() and
64+
srctype = getPreciseType(src) and
5965
if src instanceof ClassInstanceExpr then exact = true else exact = false
6066
)
6167
or
@@ -67,11 +73,9 @@ private module DispatchImpl {
6773
if ctx instanceof ClassInstanceExpr then exact = true else exact = false
6874
)
6975
|
70-
exists(TypeVariable v | v = srctype |
71-
t = v.getUpperBoundType+() and not t instanceof TypeVariable
72-
)
76+
t = srctype.(BoundedType).getAnUltimateUpperBoundType()
7377
or
74-
t = srctype and not srctype instanceof TypeVariable
78+
t = srctype and not srctype instanceof BoundedType
7579
)
7680
}
7781

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import java.lang.Runtime;
2+
import java.util.function.Function;
3+
4+
public class Executor {
5+
6+
private static final Processor<String> processor = new Processor<String>();
7+
8+
private static String source() { return "taint"; }
9+
10+
public static void main(String[] args) {
11+
exec1(source());
12+
exec2(source());
13+
exec3(source());
14+
exec4(source());
15+
exec5(source());
16+
}
17+
18+
private static void exec1(String command){
19+
command = process(s->s.toUpperCase(),command);
20+
exec(command);
21+
}
22+
23+
private static void exec2(String command){
24+
command = process(s->"Taint stops here.",command);
25+
exec(command);
26+
}
27+
28+
private static void exec3(String command){
29+
command = processor.process(s->s.toUpperCase(),command);
30+
exec(command);
31+
}
32+
33+
private static void exec4(String command){
34+
command = processor.process(s->"Taint stops here.",command);
35+
exec_b(command);
36+
}
37+
38+
private static void exec5(String command){
39+
command = processor.process(s->s.toUpperCase(),command);
40+
exec_b(command);
41+
}
42+
43+
public static String process(Function<String, String> fun, String command){
44+
return processor.process(fun, command);
45+
}
46+
47+
private static void exec(String command){
48+
command = process(s->s.trim(),command);
49+
try {
50+
Runtime.getRuntime().exec(command);
51+
}
52+
catch(Exception e) {}
53+
}
54+
55+
private static void exec_b(String command){
56+
command = processor.process(s->s.trim(),command);
57+
try {
58+
Runtime.getRuntime().exec(command);
59+
}
60+
catch(Exception e) {}
61+
}
62+
}
63+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import java.util.function.Function;
2+
3+
public class Processor<T> {
4+
5+
public <R> R process(Function<T,R> function, T arg) {
6+
return function.apply(arg);
7+
}
8+
}
9+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import java.util.function.Function;
2+
3+
public class StringProcessor {
4+
5+
private static final Processor<String> processor = new Processor<String>();
6+
7+
public static void main(String[] args) {
8+
String command = args[0];
9+
lambdaExec(command);
10+
}
11+
12+
public static void lambdaExec(String command){
13+
processor.process(s->exec(s), command);
14+
}
15+
16+
public static String lambdaUnrelated(String command){
17+
return processor.process(s->s+"not related to anything", command);
18+
}
19+
20+
public static String exec(String command){
21+
try {
22+
command = processor.process(s->s.trim(), command);
23+
Runtime.getRuntime().exec(command);
24+
return "Executed: "+command;
25+
} catch(Exception e) {
26+
return null;
27+
}
28+
}
29+
}
30+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| Executor.java:11:15:11:22 | source(...) | Executor.java:50:39:50:45 | command |
2+
| Executor.java:11:15:11:22 | source(...) | StringProcessor.java:23:39:23:45 | command |
3+
| Executor.java:12:15:12:22 | source(...) | Executor.java:50:39:50:45 | command |
4+
| Executor.java:12:15:12:22 | source(...) | StringProcessor.java:23:39:23:45 | command |
5+
| Executor.java:13:15:13:22 | source(...) | Executor.java:50:39:50:45 | command |
6+
| Executor.java:13:15:13:22 | source(...) | StringProcessor.java:23:39:23:45 | command |
7+
| Executor.java:15:15:15:22 | source(...) | Executor.java:58:39:58:45 | command |
8+
| StringProcessor.java:8:26:8:29 | args | StringProcessor.java:23:39:23:45 | command |
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import java
2+
import semmle.code.java.dataflow.TaintTracking
3+
4+
class Conf extends TaintTracking::Configuration {
5+
Conf() { this = "qltest lambda" }
6+
7+
override predicate isSource(DataFlow::Node src) {
8+
src.asExpr().(VarAccess).getVariable().hasName("args")
9+
or
10+
src.asExpr().(MethodAccess).getMethod().hasName("source")
11+
}
12+
13+
override predicate isSink(DataFlow::Node sink) {
14+
sink.asExpr().(Argument).getCall() =
15+
any(MethodAccess ma |
16+
ma.getMethod().hasName("exec") and
17+
ma.getQualifier().(MethodAccess).getMethod().hasName("getRuntime")
18+
)
19+
}
20+
}
21+
22+
from DataFlow::Node src, DataFlow::Node sink, Conf c
23+
where c.hasFlow(src, sink)
24+
select src, sink

0 commit comments

Comments
 (0)