@@ -3,174 +3,71 @@ private import semmle.code.java.dataflow.DataFlow
33private import semmle.code.java.dataflow.FlowSteps
44private import semmle.code.java.dataflow.ExternalFlow
55
6- /** A reference type that extends a parameterization the Promise type. */
7- private class RatpackPromise extends RefType {
8- RatpackPromise ( ) {
9- getSourceDeclaration ( ) .getASourceSupertype * ( ) .hasQualifiedName ( "ratpack.exec" , "Promise" )
10- }
11- }
12-
13- /**
6+ /**
147 * Ratpack methods that propagate user-supplied data as tainted.
158 */
169private class RatpackExecModel extends SummaryModelCsv {
1710 override predicate row ( string row ) {
1811 //"namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind",
19- row = [
20- "ratpack.exec;Promise;true;map;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
21- "ratpack.exec;Promise;true;map;;;ReturnValue of Argument[0];Element of ReturnValue;value" ,
22- "ratpack.exec;Promise;true;then;;;Element of Argument[-1];Parameter[0] of Argument[0];value"
23- ]
24- }
25- }
26-
27-
28- private class RatpackPromiseValueMethod extends Method , TaintPreservingCallable {
29- RatpackPromiseValueMethod ( ) { isStatic ( ) and hasName ( "value" ) }
30-
31- override predicate returnsTaintFrom ( int arg ) { arg = 0 }
32- }
33-
34- abstract private class FluentLambdaMethod extends Method {
35- /**
36- * Holds if this lambda consumes taint from the quaifier when `lambdaArg`
37- * for `methodArg` is tainted.
38- * Eg. `tainted.map(stillTainted -> ..)`
39- */
40- abstract predicate consumesTaint ( int methodArg , int lambdaArg ) ;
41-
42- /**
43- * Holds if the lambda passed at the given `arg` position produces taint
44- * that taints the result of this method.
45- * Eg. `var tainted = CompletableFuture.supplyAsync(() -> taint());`
46- */
47- predicate doesReturnTaint ( int arg ) { none ( ) }
48- }
49-
50- private class RatpackPromiseProviderMethod extends Method , FluentLambdaMethod {
51- RatpackPromiseProviderMethod ( ) { isStatic ( ) and hasName ( [ "flatten" , "sync" ] ) }
52-
53- override predicate consumesTaint ( int methodArg , int lambdaArg ) { none ( ) }
54-
55- override predicate doesReturnTaint ( int arg ) { arg = 0 }
56- }
57-
58- abstract private class SimpleFluentLambdaMethod extends FluentLambdaMethod {
59- override predicate consumesTaint ( int methodArg , int lambdaArg ) {
60- methodArg = 0 and consumesTaint ( lambdaArg )
12+ row =
13+ [ "ratpack.exec;Promise;true;" ] +
14+ [
15+ // `Promise` creation methods
16+ "value;;;Argument[0];Element of ReturnValue;value" ,
17+ "flatten;;;Element of ReturnValue of Argument[0];Element of ReturnValue;value" ,
18+ "sync;;;ReturnValue of Argument[0];Element of ReturnValue;value" ,
19+ // `Promise` value transformation methods
20+ "map;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
21+ "map;;;ReturnValue of Argument[0];Element of ReturnValue;value" ,
22+ "blockingMap;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
23+ "blockingMap;;;ReturnValue of Argument[0];Element of ReturnValue;value" ,
24+ "mapError;;;ReturnValue of Argument[0];Element of ReturnValue;value" ,
25+ // `Promise` termination method
26+ "then;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
27+ // 'next' accesses qualfier the 'Promise' value and also returns the qualifier
28+ "next;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
29+ "next;;;Argument[-1];ReturnValue;value" ,
30+ // 'cacheIf' accesses qualfier the 'Promise' value and also returns the qualifier
31+ "cacheIf;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
32+ "cacheIf;;;Argument[-1];ReturnValue;value" ,
33+ // 'route' accesses qualfier the 'Promise' value, and conditionally returns the qualifier or
34+ // the result of the second argument
35+ "route;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
36+ "route;;;Element of Argument[-1];Parameter[0] of Argument[1];value" ,
37+ "route;;;Argument[-1];ReturnValue;value" ,
38+ // `flatMap` type methods return their returned `Promise`
39+ "flatMap;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
40+ "flatMap;;;Element of ReturnValue of Argument[0];Element of ReturnValue;value" ,
41+ "flatMapError;;;Element of ReturnValue of Argument[0];Element of ReturnValue;value" ,
42+ // `mapIf` methods conditionally map their values, or return themselves
43+ "mapIf;;;Element of Argument[-1];Parameter[0] of Argument[0];value" ,
44+ "mapIf;;;Element of Argument[-1];Parameter[0] of Argument[1];value" ,
45+ "mapIf;;;Element of Argument[-1];Parameter[0] of Argument[2];value" ,
46+ "mapIf;;;ReturnValue of Argument[1];Element of ReturnValue;value" ,
47+ "mapIf;;;ReturnValue of Argument[2];Element of ReturnValue;value"
48+ ]
6149 }
62-
63- /**
64- * Holds if this lambda consumes taint from the quaifier when `arg` is tainted.
65- * Eg. `tainted.map(stillTainted -> ..)`
66- */
67- abstract predicate consumesTaint ( int lambdaArg ) ;
6850}
6951
70- private class RatpackPromiseMapMethod extends SimpleFluentLambdaMethod {
71- RatpackPromiseMapMethod ( ) {
72- getDeclaringType ( ) instanceof RatpackPromise and
73- hasName ( [ "blockingMap" ] ) // "flatMap" & "apply" cause false positives. Wait for fluent lambda support.
52+ /** A reference type that extends a parameterization the Promise type. */
53+ private class RatpackPromise extends RefType {
54+ RatpackPromise ( ) {
55+ getSourceDeclaration ( ) . getASourceSupertype * ( ) . hasQualifiedName ( "ratpack.exec" , "Promise" )
7456 }
75-
76- override predicate consumesTaint ( int lambdaArg ) { lambdaArg = 0 }
77-
78- override predicate doesReturnTaint ( int arg ) { arg = 0 }
7957}
8058
8159/**
82- * Represents the `mapIf` method.
83- *
84- * `<O> Promise<O> mapIf(Predicate<T> predicate, Function<T, O> onTrue, Function<T, O> onFalse)`
60+ * Ratpack `Promise` method that will return `this`.
8561 */
86- private class RatpackPromiseMapIfMethod extends FluentLambdaMethod {
87- RatpackPromiseMapIfMethod ( ) {
88- getDeclaringType ( ) instanceof RatpackPromise and
89- hasName ( [ "mapIf" ] ) and // "flatMapIf" causes false positives. Wait for fluent lambda support.
90- getNumberOfParameters ( ) = 3
91- }
92-
93- override predicate consumesTaint ( int methodArg , int lambdaArg ) {
94- methodArg = [ 1 , 2 , 3 ] and lambdaArg = 0
95- }
96-
97- override predicate doesReturnTaint ( int arg ) { arg = [ 1 , 2 ] }
98- }
99-
100- private class RatpackPromiseMapErrorMethod extends FluentLambdaMethod {
101- RatpackPromiseMapErrorMethod ( ) {
102- getDeclaringType ( ) instanceof RatpackPromise and
103- hasName ( [ "mapError" ] ) // "flatMapError" causes false positives. Wait for fluent lambda support.
104- }
105-
106- override predicate consumesTaint ( int methodArg , int lambdaArg ) { none ( ) }
107-
108- override predicate doesReturnTaint ( int arg ) { arg = getNumberOfParameters ( ) - 1 }
109- }
110-
111- // private class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
112- // RatpackPromiseThenMethod() {
113- // getDeclaringType() instanceof RatpackPromise and
114- // hasName("then")
115- // }
116-
117- // override predicate consumesTaint(int lambdaArg) { lambdaArg = 0 }
118- // }
119-
120- private class RatpackPromiseFluentMethod extends FluentMethod , FluentLambdaMethod {
62+ private class RatpackPromiseFluentMethod extends FluentMethod {
12163 RatpackPromiseFluentMethod ( ) {
12264 getDeclaringType ( ) instanceof RatpackPromise and
12365 not isStatic ( ) and
66+ // It's generally safe to assume that if the return type exactly matches the declaring type, `this` will be returned.
12467 exists ( ParameterizedType t |
12568 t instanceof RatpackPromise and
12669 t = getDeclaringType ( ) and
12770 t = getReturnType ( )
12871 )
12972 }
130-
131- override predicate consumesTaint ( int methodArg , int lambdaArg ) {
132- hasName ( [ "next" ] ) and methodArg = 0 and lambdaArg = 0
133- or
134- hasName ( [ "cacheIf" ] ) and methodArg = 0 and lambdaArg = 0
135- or
136- hasName ( [ "route" ] ) and methodArg = [ 0 , 1 ] and lambdaArg = 0
137- }
138-
139- override predicate doesReturnTaint ( int arg ) { none ( ) } // "flatMapIf" causes false positives. Wait for fluent lambda support.
140- }
141-
142- /**
143- * Holds if the method access qualifier `node1` has dataflow to the functional expression parameter `node2`.
144- */
145- private predicate stepIntoLambda ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
146- exists ( MethodAccess ma , FluentLambdaMethod flm , int methodArg , int lambdaArg |
147- flm .consumesTaint ( methodArg , lambdaArg )
148- |
149- ma .getMethod ( ) = flm and
150- node1 .asExpr ( ) = ma .getQualifier ( ) and
151- ma .getArgument ( methodArg ) .( FunctionalExpr ) .asMethod ( ) .getParameter ( lambdaArg ) =
152- node2 .asParameter ( )
153- )
154- }
155-
156- /**
157- * Holds if the return statement result of the functional expression `node1` has dataflow to the
158- * method access result `node2`.
159- */
160- private predicate stepOutOfLambda ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
161- exists ( FluentLambdaMethod flm , MethodAccess ma , FunctionalExpr fe , int arg |
162- flm .doesReturnTaint ( arg )
163- |
164- fe .asMethod ( ) .getBody ( ) .getAStmt ( ) .( ReturnStmt ) .getResult ( ) = node1 .asExpr ( ) and
165- ma .getMethod ( ) = flm and
166- node2 .asExpr ( ) = ma and
167- ma .getArgument ( arg ) = fe
168- )
169- }
170-
171- private class RatpackPromiseTaintPreservingStep extends AdditionalTaintStep {
172- override predicate step ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
173- stepIntoLambda ( node1 , node2 ) or
174- stepOutOfLambda ( node1 , node2 )
175- }
17673}
0 commit comments