@@ -49,25 +49,18 @@ private module ValidationMethod<DataFlow::guardChecksSig/3 validationGuard> {
4949 */
5050private predicate exactPathMatchGuard ( Guard g , Expr e , boolean branch ) {
5151 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
6759 |
60+ e = getVisualQualifier ( ma ) .getUnderlyingExpr ( ) and
6861 ma .getMethod ( ) .getDeclaringType ( ) = t and
6962 ma = g and
70- ma .getMethod ( ) . getName ( ) = [ "equals" , "equalsIgnoreCase" ] + [ "" , "$default" ] and
63+ getSourceMethod ( ma .getMethod ( ) ) . hasName ( [ "equals" , "equalsIgnoreCase" ] ) and
7164 branch = true
7265 )
7366}
@@ -224,29 +217,19 @@ private class ConstantOrRegex extends Expr {
224217}
225218
226219private 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
228223 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 ( )
236225 |
237- m .hasName ( "startsWith" + [ "" , "$default" ] )
226+ getSourceMethod ( m ) .hasName ( "startsWith" )
238227 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 ( ".*%" )
250233 )
251234}
252235
@@ -256,30 +239,23 @@ private predicate isStringPrefixMatch(MethodAccess ma, Expr checkedExpr) {
256239private predicate isStringPartialMatch ( MethodAccess ma , Expr checkedExpr ) {
257240 isStringPrefixMatch ( ma , checkedExpr )
258241 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
265244 ) 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 ( )
268248}
269249
270250/**
271251 * Holds if `ma` is a call to a method that checks whether `checkedExpr` starts with a prefix.
272252 */
273253private 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 )
283259}
284260
285261private predicate isDisallowedWord ( ConstantOrRegex word ) {
@@ -291,22 +267,19 @@ private class PathTraversalGuard extends PathGuard {
291267 Expr checkedExpr ;
292268
293269 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
302275 ma .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = ".."
303276 |
304277 this = ma and
305- ma . getMethod ( ) .hasName ( "contains" + [ "" , "$default" ] )
278+ getSourceMethod ( m ) .hasName ( "contains" )
306279 or
307280 exists ( EqualityTest eq |
308281 this = eq and
309- ma . getMethod ( ) .hasName ( [ "indexOf" , "lastIndexOf" ] + [ "" , "$default "] ) and
282+ getSourceMethod ( m ) .hasName ( [ "indexOf" , "lastIndexOf" ] ) and
310283 eq .getAnOperand ( ) = ma and
311284 eq .getAnOperand ( ) .( CompileTimeConstantExpr ) .getIntValue ( ) = - 1
312285 )
@@ -325,15 +298,46 @@ private class PathTraversalGuard extends PathGuard {
325298/** A complementary sanitizer that protects against path traversal using path normalization. */
326299private class PathNormalizeSanitizer extends MethodAccess {
327300 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
333303 this .getMethod ( ) .hasName ( "normalize" )
304+ or
305+ t instanceof TypeFile and
306+ this .getMethod ( ) .hasName ( [ "getCanonicalPath" , "getCanonicalFile" ] )
334307 )
335- or
336- this .getMethod ( ) .getDeclaringType ( ) instanceof TypeFile and
337- this .getMethod ( ) .hasName ( [ "getCanonicalPath" , "getCanonicalFile" ] )
338308 }
339309}
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