11/**
2- * @name User-controlled file decompression
3- * @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
2+ * @name Uncontrolled file decompression
3+ * @description Uncontrolled data that flows into decompression library APIs without checking the compression rate is dangerous
44 * @kind path-problem
55 * @problem.severity error
66 * @security-severity 7.8
77 * @precision high
8- * @id java/user-controlled -file-decompression
8+ * @id java/uncontrolled -file-decompression
99 * @tags security
1010 * experimental
1111 * external/cwe/cwe-409
@@ -300,19 +300,55 @@ module Zip4j {
300300}
301301
302302module Zip {
303- class TypeZipInputStream extends RefType {
304- TypeZipInputStream ( ) {
303+ class TypeInputStream extends RefType {
304+ TypeInputStream ( ) {
305305 this .getASupertype * ( )
306306 .hasQualifiedName ( "java.util.zip" ,
307307 [ "ZipInputStream" , "GZIPInputStream" , "InflaterInputStream" ] )
308308 }
309309 }
310310
311+ class TypeInflator extends RefType {
312+ TypeInflator ( ) { this .hasQualifiedName ( "java.util.zip" , "Inflater" ) }
313+ }
314+
315+ predicate inflatorAdditionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
316+ // inflater.inflate(n2)
317+ exists ( MethodAccess ma |
318+ ma .getReceiverType ( ) instanceof TypeInflator and
319+ ma .getArgument ( 0 ) = n2 .asExpr ( ) and
320+ ma .getQualifier ( ) = n1 .asExpr ( ) and
321+ ma .getCallee ( ) .hasName ( "inflate" )
322+ )
323+ or
324+ // Inflater inflater = new Inflater();
325+ // n2 = inflater.setInput(n1)
326+ exists ( MethodAccess ma |
327+ ma .getReceiverType ( ) instanceof TypeInflator and
328+ n1 .asExpr ( ) = ma .getArgument ( 0 ) and
329+ n2 .( DataFlow:: PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = ma .getQualifier ( ) and
330+ ma .getCallee ( ) .hasName ( "setInput" )
331+ )
332+ }
333+
334+ class InflateCall extends MethodAccess {
335+ InflateCall ( ) {
336+ this .getReceiverType ( ) instanceof TypeInflator and
337+ this .getCallee ( ) .hasName ( "inflate" )
338+ }
339+
340+ Expr getAWriteArgument ( ) { result = this .getArgument ( 0 ) }
341+
342+ // look at Zip4j comments for this method
343+ predicate isControlledRead ( ) { none ( ) }
344+ }
345+
346+ // InflaterInputStream Izis = new InflaterInputStream(inputStream)
311347 predicate inputStreamAdditionalTaintStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
312348 exists ( Call call |
313349 (
314- call .getCallee ( ) .getDeclaringType ( ) instanceof TypeZipInputStream or
315- call .( MethodAccess ) .getReceiverType ( ) instanceof TypeZipInputStream
350+ call .getCallee ( ) .getDeclaringType ( ) instanceof TypeInputStream or
351+ call .( MethodAccess ) .getReceiverType ( ) instanceof TypeInputStream
316352 ) and
317353 call .getArgument ( 0 ) = n1 .asExpr ( ) and
318354 call = n2 .asExpr ( )
@@ -321,7 +357,7 @@ module Zip {
321357
322358 class ReadInputStreamCall extends MethodAccess {
323359 ReadInputStreamCall ( ) {
324- this .getReceiverType ( ) instanceof TypeZipInputStream and
360+ this .getReceiverType ( ) instanceof TypeInputStream and
325361 this .getCallee ( ) .hasName ( [ "read" , "readNBytes" , "readAllBytes" ] )
326362 }
327363
@@ -369,6 +405,9 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
369405 */
370406 predicate isSink ( DataFlow:: Node sink , FlowState state ) {
371407 (
408+ sink .asExpr ( ) = any ( Zip:: InflateCall r ) .getAWriteArgument ( ) and
409+ state = "Zip"
410+ or
372411 exists ( CommonsIO:: IOUtils ma |
373412 sink .asExpr ( ) = ma .getArgument ( 0 ) and
374413 state = [ "Zip4j" , "Zip" , "ApacheCommons" , "XserialSnappy" ]
@@ -397,6 +436,10 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
397436 predicate isAdditionalFlowStep (
398437 DataFlow:: Node nodeFrom , FlowState stateFrom , DataFlow:: Node nodeTo , FlowState stateTo
399438 ) {
439+ Zip:: inflatorAdditionalTaintStep ( nodeFrom , nodeTo ) and
440+ stateFrom = "Zip" and
441+ stateTo = "Zip"
442+ or
400443 (
401444 Zip:: inputStreamAdditionalTaintStep ( nodeFrom , nodeTo ) and
402445 stateFrom = "Zip"
0 commit comments