Skip to content

Commit 31cae20

Browse files
committed
make DecompressionBombs module and extention points
1 parent 00d1b11 commit 31cae20

2 files changed

Lines changed: 704 additions & 174 deletions

File tree

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

Lines changed: 7 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -14,70 +14,18 @@
1414
import go
1515
import semmle.go.dataflow.Properties
1616
import MultipartAndFormRemoteSource
17+
import DecompressionBombs
1718

1819
module DecompressionBombsConfig implements DataFlow::StateConfigSig {
19-
class FlowState = DataFlow::FlowState;
20+
class FlowState = DecompressionBombs::FlowState;
2021

2122
predicate isSource(DataFlow::Node source, FlowState state) {
2223
source instanceof UntrustedFlowSource and
2324
state = ""
2425
}
2526

2627
predicate isSink(DataFlow::Node sink, FlowState state) {
27-
(
28-
exists(Function f | f.hasQualifiedName("io", ["Copy", "CopyBuffer", "CopyN"]) |
29-
sink = f.getACall().getArgument(1)
30-
)
31-
or
32-
exists(Function f | f.hasQualifiedName("io", ["Pipe", "ReadAll", "ReadAtLeast", "ReadFull"]) |
33-
sink = f.getACall().getArgument(0)
34-
)
35-
or
36-
exists(Function f |
37-
f.hasQualifiedName("bufio.Reader",
38-
["Read", "ReadBytes", "ReadByte", "ReadLine", "ReadRune", "ReadSlice", "ReadString"])
39-
|
40-
sink = f.getACall().getReceiver()
41-
)
42-
or
43-
exists(Function f | f.hasQualifiedName("bufio.Scanner", ["Text", "Bytes"]) |
44-
sink = f.getACall().getReceiver()
45-
)
46-
or
47-
exists(Function f | f.hasQualifiedName("io/ioutil", "ReadAll") |
48-
sink = f.getACall().getArgument(0)
49-
)
50-
or
51-
exists(Function f |
52-
f.hasQualifiedName([
53-
"github.com/klauspost/compress/flate.decompressor",
54-
"github.com/dsnet/compress/bzip2.Reader", "compress/flate.decompressor",
55-
"github.com/dsnet/compress/flate.Reader", "github.com/klauspost/compress/zlib.reader",
56-
"compress/zlib.reader", "github.com/golang/snappy.Reader",
57-
"github.com/klauspost/compress/s2.Reader", "github.com/klauspost/compress/gzip.Reader",
58-
"github.com/klauspost/pgzip.Reader", "github.com/klauspost/compress/zstd.Decoder",
59-
"github.com/DataDog/zstd.reader", "compress/gzip.Reader",
60-
"github.com/ulikunitz/xz.Reader", "archive/tar.Reader", "compress/bzip2.reader"
61-
], "Read")
62-
|
63-
sink = f.getACall().getReceiver()
64-
)
65-
or
66-
exists(Function f |
67-
f.hasQualifiedName("github.com/klauspost/compress/s2.Reader",
68-
["DecodeConcurrent", "ReadByte"])
69-
or
70-
f.hasQualifiedName("github.com/golang/snappy.Reader", "ReadByte")
71-
or
72-
f.hasQualifiedName("github.com/klauspost/compress/gzip.Reader", "WriteTo")
73-
or
74-
f.hasQualifiedName("github.com/klauspost/pgzip.Reader", "WriteTo")
75-
or
76-
f.hasQualifiedName("github.com/klauspost/compress/zstd.Decoder", ["WriteTo", "DecodeAll"])
77-
|
78-
sink = f.getACall().getReceiver()
79-
)
80-
) and
28+
sink instanceof DecompressionBombs::Sink and
8129
state =
8230
[
8331
"ZstdNewReader", "XzNewReader", "GzipNewReader", "S2NewReader", "SnapyNewReader",
@@ -86,131 +34,16 @@ module DecompressionBombsConfig implements DataFlow::StateConfigSig {
8634
}
8735

8836
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
89-
exists(DataFlow::FieldReadNode fi |
90-
fi.getType().hasQualifiedName("github.com/klauspost/compress/zip", "Reader")
91-
|
92-
fromNode = fi.getBase() and
93-
toNode = fi
94-
)
95-
or
96-
exists(Method f, DataFlow::CallNode call |
97-
f.hasQualifiedName("github.com/klauspost/compress/zip", "File", ["Open", "OpenRaw"]) and
98-
call = f.getACall()
99-
|
100-
fromNode = call.getReceiver() and
101-
toNode = call
37+
exists(DecompressionBombs::AdditionalTaintStep addStep |
38+
addStep.isAdditionalFlowStep(fromNode, toNode)
10239
)
10340
}
10441

10542
predicate isAdditionalFlowStep(
10643
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
10744
) {
108-
exists(Function f, DataFlow::CallNode call |
109-
f.hasQualifiedName("archive/zip", ["OpenReader", "NewReader"]) and call = f.getACall()
110-
|
111-
fromNode = call.getArgument(0) and
112-
toNode = call.getResult(0) and
113-
fromState = "" and
114-
toState = "ZipOpenReader"
115-
)
116-
or
117-
exists(Function f, DataFlow::CallNode call |
118-
f.hasQualifiedName("github.com/klauspost/compress/zip", ["NewReader", "OpenReader"]) and
119-
call = f.getACall()
120-
|
121-
fromNode = call.getArgument(0) and
122-
toNode = call.getResult(0) and
123-
fromState = "" and
124-
toState = "ZipKlauspost"
125-
)
126-
or
127-
exists(Function f, DataFlow::CallNode call |
128-
f.hasQualifiedName("github.com/ulikunitz/xz", "NewReader") and call = f.getACall()
129-
|
130-
fromNode = call.getArgument(0) and
131-
toNode = call.getResult(0) and
132-
fromState = "" and
133-
toState = "XzNewReader"
134-
)
135-
or
136-
exists(Function f, DataFlow::CallNode call |
137-
f.hasQualifiedName([
138-
"compress/gzip", "github.com/klauspost/compress/gzip", "github.com/klauspost/pgzip"
139-
], "NewReader") and
140-
call = f.getACall()
141-
|
142-
fromNode = call.getArgument(0) and
143-
toNode = call.getResult(0) and
144-
fromState = "" and
145-
toState = "GzipNewReader"
146-
)
147-
or
148-
exists(Function f, DataFlow::CallNode call |
149-
f.hasQualifiedName([
150-
"compress/bzip2", "github.com/dsnet/compress/bzip2", "github.com/cosnicolaou/pbzip2"
151-
], "NewReader") and
152-
call = f.getACall()
153-
|
154-
fromNode = call.getArgument(0) and
155-
toNode = call.getResult(0) and
156-
fromState = "" and
157-
toState = "Bzip2NewReader"
158-
)
159-
or
160-
exists(Function f, DataFlow::CallNode call |
161-
(
162-
f.hasQualifiedName("github.com/dsnet/compress/flate", "NewReader") or
163-
f.hasQualifiedName(["compress/flate", "github.com/klauspost/compress/flate"],
164-
["NewReaderDict", "NewReader"])
165-
) and
166-
call = f.getACall()
167-
|
168-
fromNode = call.getArgument(0) and
169-
toNode = call.getResult(0) and
170-
fromState = "" and
171-
toState = "FlateNewReader"
172-
)
173-
or
174-
exists(Function f, DataFlow::CallNode call |
175-
f.hasQualifiedName(["compress/zlib", "github.com/klauspost/compress/zlib"], "NewReader") and
176-
call = f.getACall()
177-
|
178-
fromNode = call.getArgument(0) and
179-
toNode = call.getResult(0) and
180-
fromState = "" and
181-
toState = "ZlibNewReader"
182-
)
183-
or
184-
exists(Function f, DataFlow::CallNode call |
185-
f.hasQualifiedName(["github.com/klauspost/compress/zstd", "github.com/DataDog/zstd"],
186-
"NewReader") and
187-
call = f.getACall()
188-
|
189-
fromNode = call.getArgument(0) and
190-
toNode = call.getResult(0) and
191-
fromState = "" and
192-
toState = "ZstdNewReader"
193-
)
194-
or
195-
exists(Function f, DataFlow::CallNode call |
196-
f.hasQualifiedName(["github.com/golang/snappy", "github.com/klauspost/compress/snappy"],
197-
"NewReader") and
198-
call = f.getACall()
199-
|
200-
fromNode = call.getArgument(0) and
201-
toNode = call.getResult(0) and
202-
fromState = "" and
203-
toState = "SnapyNewReader"
204-
)
205-
or
206-
exists(Function f, DataFlow::CallNode call |
207-
f.hasQualifiedName("github.com/klauspost/compress/s2", "NewReader") and
208-
call = f.getACall()
209-
|
210-
fromNode = call.getArgument(0) and
211-
toNode = call.getResult(0) and
212-
fromState = "" and
213-
toState = "S2NewReader"
45+
exists(DecompressionBombs::AdditionalTaintStep addStep |
46+
addStep.isAdditionalFlowStep(fromNode, fromState, toNode, toState)
21447
)
21548
}
21649

0 commit comments

Comments
 (0)