@@ -5,8 +5,9 @@ module DecompressionBombs {
55 FlowState ( ) {
66 this =
77 [
8- "ZstdNewReader" , "XzNewReader" , "GzipNewReader" , "S2NewReader" , "SnappyNewReader" ,
9- "ZlibNewReader" , "FlateNewReader" , "Bzip2NewReader" , "ZipOpenReader" , "ZipKlauspost" , ""
8+ "ZstdNewReader" , "XzNewReader" , "GzipNewReader" , "PgzipNewReader" , "S2NewReader" ,
9+ "SnappyNewReader" , "ZlibNewReader" , "FlateNewReader" , "Bzip2NewReader" , "ZipOpenReader" ,
10+ "ZipKlauspost" , ""
1011 ]
1112 }
1213 }
@@ -252,11 +253,12 @@ module DecompressionBombs {
252253 /**
253254 * Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/gzip` package
254255 */
255- module KlauspostGzip {
256+ module KlauspostGzipAndPgzip {
256257 class TheSink extends Sink {
257258 TheSink ( ) {
258259 exists ( Method f |
259- f .hasQualifiedName ( "github.com/klauspost/compress/gzip" , "Reader" , "Read" )
260+ f .hasQualifiedName ( [ "github.com/klauspost/compress/gzip" , "github.com/klauspost/pgzip" ] ,
261+ "Reader" , "Read" )
260262 |
261263 this = f .getACall ( ) .getReceiver ( )
262264 )
@@ -277,10 +279,15 @@ module DecompressionBombs {
277279 DataFlow:: Node fromNode , FlowState fromState , DataFlow:: Node toNode , FlowState toState
278280 ) {
279281 exists ( Function f , DataFlow:: CallNode call |
280- f .hasQualifiedName ( [ "github.com/klauspost/compress/gzip" , "github.com/klauspost/pgzip" ] ,
281- "NewReader" ) and
282- call = f .getACall ( )
283- |
282+ f .hasQualifiedName ( "github.com/klauspost/pgzip" , "NewReader" ) and
283+ call = f .getACall ( ) and
284+ fromNode = call .getArgument ( 0 ) and
285+ toNode = call .getResult ( 0 ) and
286+ fromState = "" and
287+ toState = "PgzipNewReader"
288+ or
289+ f .hasQualifiedName ( "github.com/klauspost/compress/gzip" , "NewReader" ) and
290+ call = f .getACall ( ) and
284291 fromNode = call .getArgument ( 0 ) and
285292 toNode = call .getResult ( 0 ) and
286293 fromState = "" and
@@ -651,7 +658,15 @@ module DecompressionBombs {
651658 module GeneralReadIoSink {
652659 class TheSink extends Sink {
653660 TheSink ( ) {
654- exists ( Function f | f .hasQualifiedName ( "io" , [ "Copy" , "CopyBuffer" , "CopyN" ] ) |
661+ exists ( Function f , DataFlow:: CallNode cn |
662+ f .hasQualifiedName ( "io" , "CopyN" ) and cn = f .getACall ( )
663+ |
664+ this = cn .getArgument ( 1 ) and
665+ // and the return value doesn't flow into a comparison (<, >, <=, >=).
666+ not localStep * ( cn .getResult ( 0 ) , any ( DataFlow:: RelationalComparisonNode rcn ) .getAnOperand ( ) )
667+ )
668+ or
669+ exists ( Function f | f .hasQualifiedName ( "io" , [ "Copy" , "CopyBuffer" ] ) |
655670 this = f .getACall ( ) .getArgument ( 1 )
656671 )
657672 or
@@ -677,5 +692,29 @@ module DecompressionBombs {
677692 )
678693 }
679694 }
695+
696+ /**
697+ * Holds if the value of `pred` can flow into `succ` in one step through an
698+ * arithmetic operation (other than remainder).
699+ *
700+ * Note: this predicate is copied from AllocationSizeOverflow. When this query
701+ * is promoted it should be put in a shared location.
702+ */
703+ predicate additionalStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
704+ succ .asExpr ( ) .( ArithmeticExpr ) .getAnOperand ( ) = pred .asExpr ( ) and
705+ not succ .asExpr ( ) instanceof RemExpr
706+ }
707+
708+ /**
709+ * Holds if the value of `pred` can flow into `succ` in one step, either by a standard taint step
710+ * or by an additional step.
711+ *
712+ * Note: this predicate is copied from AllocationSizeOverflow. When this query
713+ * is promoted it should be put in a shared location.
714+ */
715+ predicate localStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
716+ TaintTracking:: localTaintStep ( pred , succ ) or
717+ additionalStep ( pred , succ )
718+ }
680719 }
681720}
0 commit comments