Skip to content

Commit 170657b

Browse files
committed
Add additional Ratpack test and improve Promise based dataflow tracking
1 parent dabf00e commit 170657b

File tree

5 files changed

+119
-9
lines changed

5 files changed

+119
-9
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44

55
import java
6+
private import semmle.code.java.dataflow.DataFlow
7+
private import semmle.code.java.dataflow.FlowSteps
68

79
/**
810
* Ratpack methods that access user-supplied request data.
@@ -81,3 +83,31 @@ class RatpackUploadFileGetMethod extends RatpackGetRequestDataMethod {
8183
hasName("getFileName")
8284
}
8385
}
86+
87+
class RatpackHeader extends RefType {
88+
RatpackHeader() {
89+
hasQualifiedName("ratpack.http", "Headers") or
90+
hasQualifiedName("ratpack.core.http", "Headers")
91+
}
92+
}
93+
94+
private class RatpackHeaderTaintPropigatingMethod extends Method {
95+
RatpackHeaderTaintPropigatingMethod() {
96+
getDeclaringType() instanceof RatpackHeader and
97+
hasName(["get", "getAll", "getNames", "asMultiValueMap"])
98+
}
99+
}
100+
101+
class TaintPropigatingHeaderMethod extends AdditionalTaintStep {
102+
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
103+
stepHeaderPropigatingTaint(node1, node2)
104+
}
105+
106+
private predicate stepHeaderPropigatingTaint(DataFlow::Node node1, DataFlow::Node node2) {
107+
exists(MethodAccess ma |
108+
ma.getMethod() instanceof RatpackHeaderTaintPropigatingMethod and
109+
node2.asExpr() = ma and
110+
node1.asExpr() = ma.getQualifier()
111+
)
112+
}
113+
}

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@ 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 { }
17+
1218
class RatpackPromiseMapMethod extends Method {
1319
RatpackPromiseMapMethod() {
1420
getDeclaringType() instanceof RatpackPromise and
1521
hasName("map")
1622
}
1723
}
1824

19-
class RatpackPromiseMapMethodAccess extends MethodAccess {
25+
class RatpackPromiseMapMethodAccess extends TaintFromQualifierToFunctionalArgumentMethodAccess {
2026
RatpackPromiseMapMethodAccess() { getMethod() instanceof RatpackPromiseMapMethod }
2127
}
2228

@@ -27,10 +33,21 @@ class RatpackPromiseThenMethod extends Method {
2733
}
2834
}
2935

30-
class RatpackPromiseThenMethodAccess extends MethodAccess {
36+
class RatpackPromiseThenMethodAccess extends TaintFromQualifierToFunctionalArgumentMethodAccess {
3137
RatpackPromiseThenMethodAccess() { getMethod() instanceof RatpackPromiseThenMethod }
3238
}
3339

40+
class RatpackPromiseNextMethod extends FluentMethod {
41+
RatpackPromiseNextMethod() {
42+
getDeclaringType() instanceof RatpackPromise and
43+
hasName("next")
44+
}
45+
}
46+
47+
class RatpackPromiseNextMethodAccess extends TaintFromQualifierToFunctionalArgumentMethodAccess {
48+
RatpackPromiseNextMethodAccess() { getMethod() instanceof RatpackPromiseNextMethod }
49+
}
50+
3451
private class RatpackPromiseTaintPreservingCallable extends AdditionalTaintStep {
3552
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
3653
stepFromFunctionalExpToPromise(node1, node2) or
@@ -51,12 +68,7 @@ private class RatpackPromiseTaintPreservingCallable extends AdditionalTaintStep
5168
* Tracks taint from the previous `Promise` to the first argument of lambda passed to `map` or `then`.
5269
*/
5370
private predicate stepFromPromiseToFunctionalArgument(DataFlow::Node node1, DataFlow::Node node2) {
54-
exists(RatpackPromiseMapMethodAccess ma |
55-
node1.asExpr() = ma.getQualifier() and
56-
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
57-
)
58-
or
59-
exists(RatpackPromiseThenMethodAccess ma |
71+
exists(TaintFromQualifierToFunctionalArgumentMethodAccess ma |
6072
node1.asExpr() = ma.getQualifier() and
6173
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
6274
)

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import ratpack.core.handling.Context;
22
import ratpack.core.http.TypedData;
3+
import ratpack.core.form.UploadedFile;
4+
import java.io.OutputStream;
35

46
class Resource {
57

@@ -10,18 +12,45 @@ void test1(Context ctx) {
1012
sink(ctx.getRequest().getCookies()); //$hasTaintFlow
1113
sink(ctx.getRequest().oneCookie("Magic-Cookie")); //$hasTaintFlow
1214
sink(ctx.getRequest().getHeaders()); //$hasTaintFlow
15+
sink(ctx.getRequest().getHeaders().get("questionable_header")); //$hasTaintFlow
16+
sink(ctx.getRequest().getHeaders().getAll("questionable_header")); //$hasTaintFlow
17+
sink(ctx.getRequest().getHeaders().getNames()); //$hasTaintFlow
18+
sink(ctx.getRequest().getHeaders().asMultiValueMap()); //$hasTaintFlow
19+
sink(ctx.getRequest().getHeaders().asMultiValueMap().get("questionable_header")); //$hasTaintFlow
1320
sink(ctx.getRequest().getPath()); //$hasTaintFlow
1421
sink(ctx.getRequest().getQuery()); //$hasTaintFlow
1522
sink(ctx.getRequest().getQueryParams()); //$hasTaintFlow
23+
sink(ctx.getRequest().getQueryParams().get("questionable_parameter")); //$hasTaintFlow
1624
sink(ctx.getRequest().getRawUri()); //$hasTaintFlow
1725
sink(ctx.getRequest().getUri()); //$hasTaintFlow
1826
}
1927

2028
void test2(TypedData td) {
2129
sink(td.getText()); //$hasTaintFlow
30+
sink(td.getBuffer()); //$hasTaintFlow
31+
sink(td.getBytes()); //$hasTaintFlow
32+
sink(td.getContentType()); //$hasTaintFlow
33+
sink(td.getInputStream()); //$hasTaintFlow
2234
}
2335

24-
void test2(Context ctx) {
36+
void test3(TypedData td, OutputStream os) throws java.io.IOException {
37+
sink(os);
38+
td.writeTo(os);
39+
sink(os); //$hasTaintFlow
40+
}
41+
42+
void test4(UploadedFile uf) {
43+
sink(uf.getFileName()); //$hasTaintFlow
44+
}
45+
46+
void test5(Context ctx) {
47+
sink(ctx.getRequest().getBody().map(TypedData::getText)); //$hasTaintFlow
2548
ctx.getRequest().getBody().map(TypedData::getText).then(this::sink); //$hasTaintFlow
49+
ctx
50+
.getRequest()
51+
.getBody()
52+
.map(TypedData::getText)
53+
.next(this::sink) //$hasTaintFlow
54+
.then(this::sink); //$hasTaintFlow
2655
}
2756
}

java/ql/test/stubs/ratpack-1.9.x/ratpack/core/form/UploadedFile.java

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

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

Lines changed: 2 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)