@@ -49,25 +49,18 @@ private module ValidationMethod<DataFlow::guardChecksSig/3 validationGuard> {
49
49
*/
50
50
private predicate exactPathMatchGuard ( Guard g , Expr e , boolean branch ) {
51
51
exists ( MethodAccess ma , RefType t |
52
- (
53
- t instanceof TypeString or
54
- t instanceof TypeUri or
55
- t instanceof TypePath or
56
- t instanceof TypeFile or
57
- t .hasQualifiedName ( "android.net" , "Uri" )
58
- ) and
59
- e = ma .getQualifier ( ) .getUnderlyingExpr ( )
60
- or
61
- (
62
- ma .getMethod ( ) .getDeclaringType ( ) instanceof StringsKt
63
- or
64
- ma .getMethod ( ) .getDeclaringType ( ) instanceof FilesKt
65
- ) and
66
- e = ma .getArgument ( 0 ) .getUnderlyingExpr ( )
52
+ t instanceof TypeString or
53
+ t instanceof TypeUri or
54
+ t instanceof TypePath or
55
+ t instanceof TypeFile or
56
+ t .hasQualifiedName ( "android.net" , "Uri" ) or
57
+ t instanceof StringsKt or
58
+ t instanceof FilesKt
67
59
|
60
+ e = getVisualQualifier ( ma ) .getUnderlyingExpr ( ) and
68
61
ma .getMethod ( ) .getDeclaringType ( ) = t and
69
62
ma = g and
70
- ma .getMethod ( ) . getName ( ) = [ "equals" , "equalsIgnoreCase" ] + [ "" , "$default" ] and
63
+ getSourceMethod ( ma .getMethod ( ) ) . hasName ( [ "equals" , "equalsIgnoreCase" ] ) and
71
64
branch = true
72
65
)
73
66
}
@@ -224,29 +217,19 @@ private class ConstantOrRegex extends Expr {
224
217
}
225
218
226
219
private predicate isStringPrefixMatch ( MethodAccess ma , Expr checkedExpr ) {
227
- exists ( Method m |
220
+ exists ( Method m , RefType t |
221
+ m .getDeclaringType ( ) = t and
222
+ ( t instanceof TypeString or t instanceof StringsKt ) and
228
223
m = ma .getMethod ( ) and
229
- (
230
- m .getDeclaringType ( ) instanceof TypeString and
231
- checkedExpr = ma .getQualifier ( ) .getUnderlyingExpr ( )
232
- or
233
- m .getDeclaringType ( ) instanceof StringsKt and
234
- checkedExpr = ma .getArgument ( 0 ) .getUnderlyingExpr ( )
235
- )
224
+ checkedExpr = getVisualQualifier ( ma ) .getUnderlyingExpr ( )
236
225
|
237
- m .hasName ( "startsWith" + [ "" , "$default" ] )
226
+ getSourceMethod ( m ) .hasName ( "startsWith" )
238
227
or
239
- exists ( int argPos |
240
- m .getDeclaringType ( ) instanceof TypeString and argPos = 0
241
- or
242
- m .getDeclaringType ( ) instanceof StringsKt and argPos = 1
243
- |
244
- m .hasName ( "regionMatches" + [ "" , "$default" ] ) and
245
- ma .getArgument ( argPos ) .( CompileTimeConstantExpr ) .getIntValue ( ) = 0
246
- or
247
- m .hasName ( "matches" ) and
248
- not ma .getArgument ( argPos ) .( ConstantOrRegex ) .getStringValue ( ) .matches ( ".*%" )
249
- )
228
+ getSourceMethod ( m ) .hasName ( "regionMatches" ) and
229
+ getVisualArgument ( ma , 0 ) .( CompileTimeConstantExpr ) .getIntValue ( ) = 0
230
+ or
231
+ m .hasName ( "matches" ) and
232
+ not getVisualArgument ( ma , 0 ) .( ConstantOrRegex ) .getStringValue ( ) .matches ( ".*%" )
250
233
)
251
234
}
252
235
@@ -256,30 +239,23 @@ private predicate isStringPrefixMatch(MethodAccess ma, Expr checkedExpr) {
256
239
private predicate isStringPartialMatch ( MethodAccess ma , Expr checkedExpr ) {
257
240
isStringPrefixMatch ( ma , checkedExpr )
258
241
or
259
- (
260
- ma .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
261
- checkedExpr = ma .getQualifier ( ) .getUnderlyingExpr ( )
262
- or
263
- ma .getMethod ( ) .getDeclaringType ( ) instanceof StringsKt and
264
- checkedExpr = ma .getArgument ( 0 ) .getUnderlyingExpr ( )
242
+ exists ( RefType t | t = ma .getMethod ( ) .getDeclaringType ( ) |
243
+ t instanceof TypeString or t instanceof StringsKt
265
244
) and
266
- ma .getMethod ( )
267
- .hasName ( [ "contains" , "matches" , "regionMatches" , "indexOf" , "lastIndexOf" ] + [ "" , "$default" ] )
245
+ getSourceMethod ( ma .getMethod ( ) )
246
+ .hasName ( [ "contains" , "matches" , "regionMatches" , "indexOf" , "lastIndexOf" ] ) and
247
+ checkedExpr = getVisualQualifier ( ma ) .getUnderlyingExpr ( )
268
248
}
269
249
270
250
/**
271
251
* Holds if `ma` is a call to a method that checks whether `checkedExpr` starts with a prefix.
272
252
*/
273
253
private predicate isPathPrefixMatch ( MethodAccess ma , Expr checkedExpr ) {
274
- exists ( RefType t |
275
- t instanceof TypePath and checkedExpr = ma .getQualifier ( ) .getUnderlyingExpr ( )
276
- or
277
- t instanceof FilesKt and
278
- checkedExpr = ma .getArgument ( 0 ) .getUnderlyingExpr ( )
279
- |
280
- t = ma .getMethod ( ) .getDeclaringType ( ) and
281
- ma .getMethod ( ) .hasName ( "startsWith" + [ "" , "$default" ] )
282
- )
254
+ exists ( RefType t | t = ma .getMethod ( ) .getDeclaringType ( ) |
255
+ t instanceof TypePath or t instanceof FilesKt
256
+ ) and
257
+ getSourceMethod ( ma .getMethod ( ) ) .hasName ( "startsWith" ) and
258
+ checkedExpr = getVisualQualifier ( ma )
283
259
}
284
260
285
261
private predicate isDisallowedWord ( ConstantOrRegex word ) {
@@ -291,22 +267,19 @@ private class PathTraversalGuard extends PathGuard {
291
267
Expr checkedExpr ;
292
268
293
269
PathTraversalGuard ( ) {
294
- exists ( MethodAccess ma |
295
- (
296
- ma .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
297
- checkedExpr = ma .getQualifier ( ) .getUnderlyingExpr ( )
298
- or
299
- ma .getMethod ( ) .getDeclaringType ( ) instanceof StringsKt and
300
- checkedExpr = ma .getArgument ( 0 ) .getUnderlyingExpr ( )
301
- ) and
270
+ exists ( MethodAccess ma , Method m , RefType t |
271
+ m = ma .getMethod ( ) and
272
+ t = m .getDeclaringType ( ) and
273
+ ( t instanceof TypeString or t instanceof StringsKt ) and
274
+ checkedExpr = getVisualQualifier ( ma ) .getUnderlyingExpr ( ) and
302
275
ma .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = ".."
303
276
|
304
277
this = ma and
305
- ma . getMethod ( ) .hasName ( "contains" + [ "" , "$default" ] )
278
+ getSourceMethod ( m ) .hasName ( "contains" )
306
279
or
307
280
exists ( EqualityTest eq |
308
281
this = eq and
309
- ma . getMethod ( ) .hasName ( [ "indexOf" , "lastIndexOf" ] + [ "" , "$default "] ) and
282
+ getSourceMethod ( m ) .hasName ( [ "indexOf" , "lastIndexOf" ] ) and
310
283
eq .getAnOperand ( ) = ma and
311
284
eq .getAnOperand ( ) .( CompileTimeConstantExpr ) .getIntValue ( ) = - 1
312
285
)
@@ -325,15 +298,46 @@ private class PathTraversalGuard extends PathGuard {
325
298
/** A complementary sanitizer that protects against path traversal using path normalization. */
326
299
private class PathNormalizeSanitizer extends MethodAccess {
327
300
PathNormalizeSanitizer ( ) {
328
- exists ( RefType t |
329
- t instanceof TypePath or
330
- t instanceof FilesKt
331
- |
332
- this .getMethod ( ) .getDeclaringType ( ) = t and
301
+ exists ( RefType t | this .getMethod ( ) .getDeclaringType ( ) = t |
302
+ ( t instanceof TypePath or t instanceof FilesKt ) and
333
303
this .getMethod ( ) .hasName ( "normalize" )
304
+ or
305
+ t instanceof TypeFile and
306
+ this .getMethod ( ) .hasName ( [ "getCanonicalPath" , "getCanonicalFile" ] )
334
307
)
335
- or
336
- this .getMethod ( ) .getDeclaringType ( ) instanceof TypeFile and
337
- this .getMethod ( ) .hasName ( [ "getCanonicalPath" , "getCanonicalFile" ] )
338
308
}
339
309
}
310
+
311
+ /**
312
+ * Gets the qualifier of `ma` as seen in the source code.
313
+ * This is a helper predicate to solve discrepancies between
314
+ * what `getQualifier` actually gets in Java and Kotlin.
315
+ */
316
+ private Expr getVisualQualifier ( MethodAccess ma ) {
317
+ if getSourceMethod ( ma .getMethod ( ) ) instanceof ExtensionMethod
318
+ then result = ma .getArgument ( 0 )
319
+ else result = ma .getQualifier ( )
320
+ }
321
+
322
+ /**
323
+ * Gets the argument of `ma` at position `argPos` as seen in the source code.
324
+ * This is a helper predicate to solve discrepancies between
325
+ * what `getArgument` actually gets in Java and Kotlin.
326
+ */
327
+ bindingset [ argPos]
328
+ private Argument getVisualArgument ( MethodAccess ma , int argPos ) {
329
+ if getSourceMethod ( ma .getMethod ( ) ) instanceof ExtensionMethod
330
+ then result = ma .getArgument ( argPos + 1 )
331
+ else result = ma .getArgument ( argPos )
332
+ }
333
+
334
+ /**
335
+ * Gets the proxied method if `m` is a Kotlin proxy that supplies default parameter values,
336
+ * Otherwise, just gets `m`.
337
+ */
338
+ private Method getSourceMethod ( Method m ) {
339
+ m = result .getKotlinParameterDefaultsProxy ( )
340
+ or
341
+ not exists ( Method src | m = src .getKotlinParameterDefaultsProxy ( ) ) and
342
+ result = m
343
+ }
0 commit comments