@@ -3,174 +3,71 @@ private import semmle.code.java.dataflow.DataFlow
3
3
private import semmle.code.java.dataflow.FlowSteps
4
4
private import semmle.code.java.dataflow.ExternalFlow
5
5
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
+ /**
14
7
* Ratpack methods that propagate user-supplied data as tainted.
15
8
*/
16
9
private class RatpackExecModel extends SummaryModelCsv {
17
10
override predicate row ( string row ) {
18
11
//"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
+ ]
61
49
}
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 ) ;
68
50
}
69
51
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" )
74
56
}
75
-
76
- override predicate consumesTaint ( int lambdaArg ) { lambdaArg = 0 }
77
-
78
- override predicate doesReturnTaint ( int arg ) { arg = 0 }
79
57
}
80
58
81
59
/**
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`.
85
61
*/
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 {
121
63
RatpackPromiseFluentMethod ( ) {
122
64
getDeclaringType ( ) instanceof RatpackPromise and
123
65
not isStatic ( ) and
66
+ // It's generally safe to assume that if the return type exactly matches the declaring type, `this` will be returned.
124
67
exists ( ParameterizedType t |
125
68
t instanceof RatpackPromise and
126
69
t = getDeclaringType ( ) and
127
70
t = getReturnType ( )
128
71
)
129
72
}
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
- }
176
73
}
0 commit comments