Skip to content

Commit b2ad128

Browse files
committed
Refactors Ratpack lambda taint tracking to use generic API
1 parent 170657b commit b2ad128

File tree

1 file changed

+39
-33
lines changed

1 file changed

+39
-33
lines changed

java/ql/src/semmle/code/java/frameworks/ratpack/RatpackExec.qll

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,68 +9,74 @@ class RatpackPromise extends RefType {
99
}
1010
}
1111

12-
/**
13-
* Taint flows from the qualifier to the first argument of the lambda passed to this method access.
14-
* Eg. `tainted.map(stillTainted -> ..)`
15-
*/
16-
abstract private class TaintFromQualifierToFunctionalArgumentMethodAccess extends MethodAccess { }
12+
abstract private class SimpleFluentLambdaMethod extends Method {
13+
SimpleFluentLambdaMethod() { getNumberOfParameters() = 1 }
1714

18-
class RatpackPromiseMapMethod extends Method {
15+
/**
16+
* Holds if this lambda consumes taint from the quaifier when `arg` is tainted.
17+
* Eg. `tainted.map(stillTainted -> ..)`
18+
*/
19+
abstract predicate consumesTaint(int arg);
20+
21+
/**
22+
* Holds if the lambda passed produces taint that taints the result of this method.
23+
* Eg. `var tainted = CompletableFuture.supplyAsync(() -> taint());`
24+
*/
25+
predicate doesReturnTaint() { none() }
26+
}
27+
28+
class RatpackPromiseMapMethod extends SimpleFluentLambdaMethod {
1929
RatpackPromiseMapMethod() {
2030
getDeclaringType() instanceof RatpackPromise and
2131
hasName("map")
2232
}
23-
}
2433

25-
class RatpackPromiseMapMethodAccess extends TaintFromQualifierToFunctionalArgumentMethodAccess {
26-
RatpackPromiseMapMethodAccess() { getMethod() instanceof RatpackPromiseMapMethod }
34+
override predicate consumesTaint(int arg) { arg = 0 }
35+
36+
override predicate doesReturnTaint() { any() }
2737
}
2838

29-
class RatpackPromiseThenMethod extends Method {
39+
class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
3040
RatpackPromiseThenMethod() {
3141
getDeclaringType() instanceof RatpackPromise and
3242
hasName("then")
3343
}
34-
}
3544

36-
class RatpackPromiseThenMethodAccess extends TaintFromQualifierToFunctionalArgumentMethodAccess {
37-
RatpackPromiseThenMethodAccess() { getMethod() instanceof RatpackPromiseThenMethod }
45+
override predicate consumesTaint(int arg) { arg = 0 }
3846
}
3947

40-
class RatpackPromiseNextMethod extends FluentMethod {
48+
class RatpackPromiseNextMethod extends FluentMethod, SimpleFluentLambdaMethod {
4149
RatpackPromiseNextMethod() {
4250
getDeclaringType() instanceof RatpackPromise and
4351
hasName("next")
4452
}
45-
}
4653

47-
class RatpackPromiseNextMethodAccess extends TaintFromQualifierToFunctionalArgumentMethodAccess {
48-
RatpackPromiseNextMethodAccess() { getMethod() instanceof RatpackPromiseNextMethod }
54+
override predicate consumesTaint(int arg) { arg = 0 }
4955
}
5056

5157
private class RatpackPromiseTaintPreservingCallable extends AdditionalTaintStep {
5258
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
53-
stepFromFunctionalExpToPromise(node1, node2) or
54-
stepFromPromiseToFunctionalArgument(node1, node2)
59+
stepIntoLambda(node1, node2) or
60+
stepOutOfLambda(node1, node2)
5561
}
5662

57-
/**
58-
* Tracks taint from return from lambda function to the outer `Promise`.
59-
*/
60-
private predicate stepFromFunctionalExpToPromise(DataFlow::Node node1, DataFlow::Node node2) {
61-
exists(FunctionalExpr fe |
62-
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
63-
node2.asExpr().(RatpackPromiseMapMethodAccess).getArgument(0) = fe
63+
predicate stepIntoLambda(DataFlow::Node node1, DataFlow::Node node2) {
64+
exists(MethodAccess ma, SimpleFluentLambdaMethod sflm, int arg |
65+
ma.getMethod() = sflm and
66+
sflm.consumesTaint(arg) and
67+
node1.asExpr() = ma.getQualifier() and
68+
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(arg) = node2.asParameter()
6469
)
6570
}
6671

67-
/**
68-
* Tracks taint from the previous `Promise` to the first argument of lambda passed to `map` or `then`.
69-
*/
70-
private predicate stepFromPromiseToFunctionalArgument(DataFlow::Node node1, DataFlow::Node node2) {
71-
exists(TaintFromQualifierToFunctionalArgumentMethodAccess ma |
72-
node1.asExpr() = ma.getQualifier() and
73-
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
72+
predicate stepOutOfLambda(DataFlow::Node node1, DataFlow::Node node2) {
73+
exists(SimpleFluentLambdaMethod sflm, MethodAccess ma, FunctionalExpr fe |
74+
sflm.doesReturnTaint()
75+
|
76+
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
77+
ma.getMethod() = sflm and
78+
node2.asExpr() = ma and
79+
ma.getArgument(0) = fe
7480
)
7581
}
7682
}

0 commit comments

Comments
 (0)