@@ -293,12 +293,25 @@ module Zip4j {
293293 call .( MethodAccess ) .getReceiverType ( ) instanceof TypeZipInputStream
294294 ) and
295295 call .getCallee ( ) .hasName ( [ "read" , "readNBytes" , "readAllBytes" ] ) and
296- call .getArgument ( 0 ) = n1 .asExpr ( ) and
297- call = n2 .asExpr ( )
296+ call .getArgument ( 0 ) = n2 .asExpr ( ) and
297+ call . getQualifier ( ) = n1 .asExpr ( )
298298 )
299299 }
300300}
301301
302+ module CommonsIO {
303+ class IOUtils extends MethodAccess {
304+ IOUtils ( ) {
305+ this .getMethod ( )
306+ .hasName ( [
307+ "copy" , "copyLarge" , "read" , "readFully" , "readLines" , "toBufferedInputStream" ,
308+ "toByteArray" , "toCharArray" , "toString" , "buffer"
309+ ] ) and
310+ this .getMethod ( ) .getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.io" , "IOUtils" )
311+ }
312+ }
313+ }
314+
302315module Zip {
303316 class TypeInputStream extends RefType {
304317 TypeInputStream ( ) {
@@ -308,10 +321,42 @@ module Zip {
308321 }
309322 }
310323
324+ class ReadInputStreamCall extends MethodAccess {
325+ ReadInputStreamCall ( ) {
326+ this .getReceiverType ( ) instanceof TypeInputStream and
327+ this .getCallee ( ) .hasName ( [ "read" , "readNBytes" , "readAllBytes" ] )
328+ }
329+
330+ Expr getAWriteArgument ( ) { result = this .getArgument ( 0 ) }
331+
332+ // look at Zip4j comments for this method
333+ predicate isControlledRead ( ) { none ( ) }
334+ }
335+
336+ // *InputStream Izis = new *InputStream(inputStream)
337+ predicate inputStreamAdditionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
338+ exists ( Call call |
339+ (
340+ call .getCallee ( ) .getDeclaringType ( ) instanceof TypeInputStream or
341+ call .( MethodAccess ) .getReceiverType ( ) instanceof TypeInputStream
342+ ) and
343+ call .getArgument ( 0 ) = n1 .asExpr ( ) and
344+ call = n2 .asExpr ( )
345+ )
346+ }
347+
311348 class TypeInflator extends RefType {
312349 TypeInflator ( ) { this .hasQualifiedName ( "java.util.zip" , "Inflater" ) }
313350 }
314351
352+ class Inflatorsource extends Call {
353+ Inflatorsource ( ) {
354+ exists ( Call c | c .getCallee ( ) .( Constructor ) .getDeclaringType ( ) instanceof TypeInflator |
355+ this = c
356+ )
357+ }
358+ }
359+
315360 predicate inflatorAdditionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
316361 // inflater.inflate(n2)
317362 exists ( MethodAccess ma |
@@ -343,48 +388,78 @@ module Zip {
343388 predicate isControlledRead ( ) { none ( ) }
344389 }
345390
346- // InflaterInputStream Izis = new InflaterInputStream(inputStream)
347- predicate inputStreamAdditionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
348- exists ( Call call |
349- (
350- call .getCallee ( ) .getDeclaringType ( ) instanceof TypeInputStream or
351- call .( MethodAccess ) .getReceiverType ( ) instanceof TypeInputStream
352- ) and
353- call .getArgument ( 0 ) = n1 .asExpr ( ) and
354- call = n2 .asExpr ( )
355- )
391+ class TypeZipFile extends RefType {
392+ TypeZipFile ( ) { this .hasQualifiedName ( "java.util.zip" , "ZipFile" ) }
356393 }
357394
358- class ReadInputStreamCall extends MethodAccess {
359- ReadInputStreamCall ( ) {
360- this .getReceiverType ( ) instanceof TypeInputStream and
361- this .getCallee ( ) .hasName ( [ "read" , "readNBytes" , "readAllBytes" ] )
395+ class ZipFilesource extends Call {
396+ ZipFilesource ( ) {
397+ exists ( Call c | c .getCallee ( ) .( Constructor ) .getDeclaringType ( ) instanceof TypeZipFile |
398+ this = c
399+ )
362400 }
401+ }
363402
364- Expr getAWriteArgument ( ) { result = this .getArgument ( 0 ) }
365-
366- // look at Zip4j comments for this method
367- predicate isControlledRead ( ) { none ( ) }
403+ // ZipFile zipFileAsn2 = new ZipFile(n1);
404+ // InputStream n2 = zipFile.getInputStream(n1);
405+ predicate zipFileadditionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
406+ exists ( MethodAccess ma |
407+ ma .getReceiverType ( ) instanceof TypeZipFile and
408+ ma = n2 .asExpr ( ) and
409+ ma .getQualifier ( ) = n1 .asExpr ( ) and
410+ ma .getCallee ( ) .hasName ( "getInputStream" )
411+ )
412+ or
413+ exists ( Call c |
414+ c .getCallee ( ) .getDeclaringType ( ) instanceof TypeZipFile and
415+ c .getArgument ( 0 ) = n1 .asExpr ( ) and
416+ c = n2 .asExpr ( )
417+ )
368418 }
369419}
370420
371- module CommonsIO {
372- class IOUtils extends MethodAccess {
373- IOUtils ( ) {
374- this .getMethod ( )
375- .hasName ( [
376- "copy" , "copyLarge" , "read" , "readFully" , "readLines" , "toBufferedInputStream" ,
377- "toByteArray" , "toCharArray" , "toString" , "buffer"
378- ] ) and
379- this .getMethod ( ) .getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.io" , "IOUtils" )
421+ module InputStream {
422+ class TypeInputStream extends RefType {
423+ TypeInputStream ( ) { this .getASupertype * ( ) .hasQualifiedName ( "java.io" , "InputStream" ) }
424+ }
425+
426+ class Source extends Call {
427+ Source ( ) {
428+ exists ( Call c | c .getCallee ( ) .getDeclaringType ( ) instanceof TypeInputStream | this = c )
380429 }
430+
431+ DataFlow:: Node getInputArgument ( ) { result .asExpr ( ) = this .( ConstructorCall ) .getArgument ( 0 ) }
432+ }
433+
434+ class Read extends MethodAccess {
435+ Read ( ) {
436+ this .getReceiverType ( ) instanceof TypeInputStream and
437+ this .getCallee ( ) .hasName ( [ "read" , "readNBytes" , "readAllBytes" ] )
438+ }
439+ }
440+
441+ predicate additionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
442+ exists ( Call call |
443+ (
444+ call .getCallee ( ) .getDeclaringType ( ) instanceof TypeInputStream or
445+ call .( MethodAccess ) .getReceiverType ( ) instanceof TypeInputStream
446+ ) and
447+ call .getCallee ( ) .hasName ( [ "read" , "readNBytes" , "readAllBytes" ] ) and
448+ call .getQualifier ( ) = n1 .asExpr ( ) and
449+ (
450+ call .getArgument ( 0 ) = n2 .asExpr ( ) or
451+ call = n2 .asExpr ( )
452+ )
453+ )
381454 }
382455}
383456
384457module DecompressionBombsConfig implements DataFlow:: StateConfigSig {
385458 class FlowState = DataFlow:: FlowState ;
386459
387460 predicate isSource ( DataFlow:: Node source , FlowState state ) {
461+ // any()
462+ // or
388463 (
389464 source instanceof RemoteFlowSource
390465 or
@@ -393,29 +468,37 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
393468 source instanceof FormRemoteFlowSource
394469 or
395470 source instanceof FileUploadRemoteFlowSource
471+ or
472+ // TODO: we have to add Zip*InputStreams instead of general inputStream because of Flow State
473+ source = any ( InputStream:: Source i ) .getInputArgument ( )
474+ or
475+ source .asExpr ( ) instanceof Zip:: Inflatorsource
396476 ) and
397- state = [ "Zip4j" , "Zip" , "ApacheCommons" , "XserialSnappy" ]
477+ state = [ "Zip4j" , "inflator" , "Zip" , "ApacheCommons" , "XserialSnappy" ]
478+ or
479+ source .asExpr ( ) instanceof Zip:: ZipFilesource and
480+ state = "ZipFile"
398481 }
399482
400- predicate isBarrier ( DataFlow:: Node sanitizer , FlowState state ) { none ( ) }
401-
402- /**
403- * if getNumArgument > 1 then we can check for sanitizers before reading each Buffer of byte
404- * otherwise it can be hard to write sanitizers
405- */
406483 predicate isSink ( DataFlow:: Node sink , FlowState state ) {
407484 (
408- sink . asExpr ( ) = any ( Zip :: InflateCall r ) . getAWriteArgument ( ) and
409- state = "Zip"
410- or
485+ // any() and
486+ // state = "Zip"
487+ // or
411488 exists ( CommonsIO:: IOUtils ma |
412489 sink .asExpr ( ) = ma .getArgument ( 0 ) and
413- state = [ "Zip4j" , "Zip" , "ApacheCommons" , "XserialSnappy" ]
490+ state = [ "Zip4j" , "inflator" , " Zip", "ApacheCommons" , "XserialSnappy" ]
414491 )
415492 or
416493 sink .asExpr ( ) = any ( Zip4j:: ReadInputStreamCall r ) .getAWriteArgument ( ) and
417494 state = "Zip4j"
418495 or
496+ sink .asExpr ( ) = any ( Zip:: InflateCall r ) .getAWriteArgument ( ) and
497+ state = "inflator"
498+ or
499+ sink .asExpr ( ) instanceof InputStream:: Read and
500+ state = "ZipFile"
501+ or
419502 sink .asExpr ( ) = any ( Zip:: ReadInputStreamCall r ) .getAWriteArgument ( ) and
420503 state = "Zip"
421504 or
@@ -433,34 +516,50 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
433516 )
434517 }
435518
519+ // predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
520+ // inputStreamAdditionalTaintStep(nodeFrom, nodeTo)
521+ // }
436522 predicate isAdditionalFlowStep (
437523 DataFlow:: Node nodeFrom , FlowState stateFrom , DataFlow:: Node nodeTo , FlowState stateTo
438524 ) {
525+ InputStream:: additionalTaintStep ( nodeFrom , nodeTo ) and
526+ stateFrom = "ZipFile" and
527+ stateTo = "ZipFile"
528+ or
439529 Zip:: inflatorAdditionalTaintStep ( nodeFrom , nodeTo ) and
530+ stateFrom = "inflator" and
531+ stateTo = "inflator"
532+ or
533+ Zip:: zipFileadditionalTaintStep ( nodeFrom , nodeTo ) and
534+ stateFrom = "ZipFile" and
535+ stateTo = "ZipFile"
536+ or
537+ Zip:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
440538 stateFrom = "Zip" and
441539 stateTo = "Zip"
442540 or
443- (
444- Zip:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
445- stateFrom = "Zip"
446- or
447- Zip4j:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
448- stateFrom = "Zip4j"
449- or
450- ApacheCommons:: Factory:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
451- stateFrom = "ApacheCommons"
452- or
453- ApacheCommons:: Compressors:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
454- stateFrom = "ApacheCommons"
455- or
456- ApacheCommons:: Archivers:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
457- stateFrom = "ApacheCommons"
458- or
459- XserialSnappy:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
460- stateFrom = "XserialSnappy"
461- ) and
462- stateTo = ""
541+ Zip4j:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
542+ stateFrom = "Zip4j" and
543+ stateTo = "Zip4j"
544+ or
545+ ApacheCommons:: Factory:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
546+ stateFrom = "ApacheCommons" and
547+ stateTo = "ApacheCommons"
548+ or
549+ ApacheCommons:: Compressors:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
550+ stateFrom = "ApacheCommons" and
551+ stateTo = "ApacheCommons"
552+ or
553+ ApacheCommons:: Archivers:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
554+ stateFrom = "ApacheCommons" and
555+ stateTo = "ApacheCommons"
556+ or
557+ XserialSnappy:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
558+ stateFrom = "ApacheCommons" and
559+ stateTo = "ApacheCommons"
463560 }
561+
562+ predicate isBarrier ( DataFlow:: Node sanitizer , FlowState state ) { none ( ) }
464563}
465564
466565module DecompressionBombsFlow = TaintTracking:: GlobalWithState< DecompressionBombsConfig > ;
0 commit comments