Skip to content

Commit 87b1028

Browse files
committed
fix pgzip missed sink, apply isBarrier directly to CopyN sink, add new flow state for pgzip
1 parent 572777f commit 87b1028

File tree

4 files changed

+478
-474
lines changed

4 files changed

+478
-474
lines changed

go/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
2727
sink instanceof DecompressionBombs::Sink and
2828
state =
2929
[
30-
"ZstdNewReader", "XzNewReader", "GzipNewReader", "S2NewReader", "SnappyNewReader",
31-
"ZlibNewReader", "FlateNewReader", "Bzip2NewReader", "ZipOpenReader", "ZipKlauspost"
30+
"ZstdNewReader", "XzNewReader", "GzipNewReader", "PgzipNewReader", "S2NewReader",
31+
"SnappyNewReader", "ZlibNewReader", "FlateNewReader", "Bzip2NewReader", "ZipOpenReader",
32+
"ZipKlauspost"
3233
]
3334
}
3435

@@ -45,41 +46,6 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
4546
addStep.isAdditionalFlowStep(fromNode, fromState, toNode, toState)
4647
)
4748
}
48-
49-
predicate isBarrier(DataFlow::Node node) {
50-
// `io.CopyN` should not be a sink if its return value flows to a
51-
// comparison (<, >, <=, >=).
52-
exists(Function f, DataFlow::CallNode cn |
53-
f.hasQualifiedName("io", "CopyN") and cn = f.getACall()
54-
|
55-
node = cn.getArgument(1) and
56-
localStep*(cn.getResult(0), any(DataFlow::RelationalComparisonNode rcn).getAnOperand())
57-
)
58-
}
59-
}
60-
61-
/**
62-
* Holds if the value of `pred` can flow into `succ` in one step through an
63-
* arithmetic operation (other than remainder).
64-
*
65-
* Note: this predicate is copied from AllocationSizeOverflow. When this query
66-
* is promoted it should be put in a shared location.
67-
*/
68-
predicate additionalStep(DataFlow::Node pred, DataFlow::Node succ) {
69-
succ.asExpr().(ArithmeticExpr).getAnOperand() = pred.asExpr() and
70-
not succ.asExpr() instanceof RemExpr
71-
}
72-
73-
/**
74-
* Holds if the value of `pred` can flow into `succ` in one step, either by a standard taint step
75-
* or by an additional step.
76-
*
77-
* Note: this predicate is copied from AllocationSizeOverflow. When this query
78-
* is promoted it should be put in a shared location.
79-
*/
80-
predicate localStep(DataFlow::Node pred, DataFlow::Node succ) {
81-
TaintTracking::localTaintStep(pred, succ) or
82-
additionalStep(pred, succ)
8349
}
8450

8551
module DecompressionBombsFlow = TaintTracking::GlobalWithState<DecompressionBombsConfig>;

go/ql/src/experimental/frameworks/DecompressionBombs.qll

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)