Skip to content

Commit b2e3df2

Browse files
committed
Add support for Promise.value and Promise::flatMap
1 parent b2ad128 commit b2e3df2

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@ private import semmle.code.java.dataflow.DataFlow
33
private import semmle.code.java.dataflow.FlowSteps
44

55
/** A reference type that extends a parameterization the Promise type. */
6-
class RatpackPromise extends RefType {
6+
private class RatpackPromise extends RefType {
77
RatpackPromise() {
88
getSourceDeclaration().getASourceSupertype*().hasQualifiedName("ratpack.exec", "Promise")
99
}
1010
}
1111

12+
private class RatpackPromiseValueMethod extends Method, TaintPreservingCallable {
13+
RatpackPromiseValueMethod() { isStatic() and hasName("value") }
14+
15+
override predicate returnsTaintFrom(int arg) { arg = 0 }
16+
}
17+
1218
abstract private class SimpleFluentLambdaMethod extends Method {
1319
SimpleFluentLambdaMethod() { getNumberOfParameters() = 1 }
1420

@@ -25,18 +31,18 @@ abstract private class SimpleFluentLambdaMethod extends Method {
2531
predicate doesReturnTaint() { none() }
2632
}
2733

28-
class RatpackPromiseMapMethod extends SimpleFluentLambdaMethod {
34+
private class RatpackPromiseMapMethod extends SimpleFluentLambdaMethod {
2935
RatpackPromiseMapMethod() {
3036
getDeclaringType() instanceof RatpackPromise and
31-
hasName("map")
37+
hasName(["map", "flatMap"])
3238
}
3339

3440
override predicate consumesTaint(int arg) { arg = 0 }
3541

3642
override predicate doesReturnTaint() { any() }
3743
}
3844

39-
class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
45+
private class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
4046
RatpackPromiseThenMethod() {
4147
getDeclaringType() instanceof RatpackPromise and
4248
hasName("then")
@@ -45,7 +51,7 @@ class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
4551
override predicate consumesTaint(int arg) { arg = 0 }
4652
}
4753

48-
class RatpackPromiseNextMethod extends FluentMethod, SimpleFluentLambdaMethod {
54+
private class RatpackPromiseNextMethod extends FluentMethod, SimpleFluentLambdaMethod {
4955
RatpackPromiseNextMethod() {
5056
getDeclaringType() instanceof RatpackPromise and
5157
hasName("next")
@@ -54,21 +60,27 @@ class RatpackPromiseNextMethod extends FluentMethod, SimpleFluentLambdaMethod {
5460
override predicate consumesTaint(int arg) { arg = 0 }
5561
}
5662

57-
private class RatpackPromiseTaintPreservingCallable extends AdditionalTaintStep {
63+
private class RatpackPromiseTaintPreservingStep extends AdditionalTaintStep {
5864
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
5965
stepIntoLambda(node1, node2) or
6066
stepOutOfLambda(node1, node2)
6167
}
6268

69+
/**
70+
* Holds if the method access qualifier `node1` has dataflow to the functional expression parameter `node2`.
71+
*/
6372
predicate stepIntoLambda(DataFlow::Node node1, DataFlow::Node node2) {
64-
exists(MethodAccess ma, SimpleFluentLambdaMethod sflm, int arg |
73+
exists(MethodAccess ma, SimpleFluentLambdaMethod sflm, int arg | sflm.consumesTaint(arg) |
6574
ma.getMethod() = sflm and
66-
sflm.consumesTaint(arg) and
6775
node1.asExpr() = ma.getQualifier() and
6876
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(arg) = node2.asParameter()
6977
)
7078
}
7179

80+
/**
81+
* Holds if the return statement result of the functional expression `node1` has dataflow to the
82+
* method access result `node2`.
83+
*/
7284
predicate stepOutOfLambda(DataFlow::Node node1, DataFlow::Node node2) {
7385
exists(SimpleFluentLambdaMethod sflm, MethodAccess ma, FunctionalExpr fe |
7486
sflm.doesReturnTaint()

java/ql/test/library-tests/frameworks/ratpack/resources/Resource.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import ratpack.core.handling.Context;
22
import ratpack.core.http.TypedData;
33
import ratpack.core.form.UploadedFile;
4+
import ratpack.exec.Promise;
45
import java.io.OutputStream;
56

67
class Resource {
78

89
void sink(Object o) {}
910

11+
String taint() {
12+
return null;
13+
}
14+
1015
void test1(Context ctx) {
1116
sink(ctx.getRequest().getContentLength()); //$hasTaintFlow
1217
sink(ctx.getRequest().getCookies()); //$hasTaintFlow
@@ -53,4 +58,14 @@ void test5(Context ctx) {
5358
.next(this::sink) //$hasTaintFlow
5459
.then(this::sink); //$hasTaintFlow
5560
}
61+
62+
void test6() {
63+
String tainted = taint();
64+
Promise.value(tainted);
65+
sink(Promise.value(tainted)); //$hasTaintFlow
66+
Promise
67+
.value(tainted)
68+
.flatMap(a -> Promise.value(a))
69+
.then(this::sink); //$hasTaintFlow
70+
}
5671
}

java/ql/test/stubs/ratpack-1.9.x/ratpack/exec/Promise.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)