@@ -6,11 +6,12 @@ import codeql.ruby.dataflow.RemoteFlowSources
6
6
7
7
module DecompressionBomb {
8
8
/**
9
- * The Sinks of uncontrolled data decompression
9
+ * A abstract class responsible for extending new decompression sinks
10
+ *
11
+ * can be a path, stream of compressed data,
12
+ * or a call to function that use pipe
10
13
*/
11
- class Sink extends DataFlow:: Node {
12
- Sink ( ) { this = any ( Range r ) .sink ( ) }
13
- }
14
+ abstract class Sink extends DataFlow:: Node { }
14
15
15
16
/**
16
17
* The additional taint steps that need for creating taint tracking or dataflow.
@@ -23,19 +24,6 @@ module DecompressionBomb {
23
24
*/
24
25
abstract predicate isAdditionalTaintStep ( DataFlow:: Node pred , DataFlow:: Node succ ) ;
25
26
}
26
-
27
- /**
28
- * A abstract class responsible for extending new decompression sinks
29
- */
30
- abstract class Range extends API:: Node {
31
- /**
32
- * Gets the sink of responsible for decompression node
33
- *
34
- * it can be a path, stream of compressed data,
35
- * or a call to function that use pipe
36
- */
37
- abstract DataFlow:: Node sink ( ) ;
38
- }
39
27
}
40
28
41
29
module Zlib {
@@ -54,10 +42,10 @@ module Zlib {
54
42
* `Zlib::GzipReader.zcat`
55
43
* `Zlib::GzipReader.new`
56
44
*/
57
- class DecompressionBombSink extends DecompressionBomb:: Range {
58
- DecompressionBombSink ( ) { this = gzipReaderInstance ( ) . getMethod ( [ "open" , "new" , "zcat" ] ) }
59
-
60
- override DataFlow :: Node sink ( ) { result = this . getReturn ( ) . asSource ( ) }
45
+ class DecompressionBombSink extends DecompressionBomb:: Sink {
46
+ DecompressionBombSink ( ) {
47
+ this = gzipReaderInstance ( ) . getMethod ( [ "open" , "new" , "zcat" ] ) . getReturn ( ) . asSource ( )
48
+ }
61
49
}
62
50
63
51
/**
@@ -94,10 +82,10 @@ module ZipInputStream {
94
82
*
95
83
* as source of decompression bombs, they need an additional taint step for a dataflow or taint tracking query
96
84
*/
97
- class DecompressionBombSink extends DecompressionBomb:: Range {
98
- DecompressionBombSink ( ) { this = zipInputStream ( ) . getMethod ( [ "open" , "new" ] ) }
99
-
100
- override DataFlow :: Node sink ( ) { result = this . getReturn ( ) . asSource ( ) }
85
+ class DecompressionBombSink extends DecompressionBomb:: Sink {
86
+ DecompressionBombSink ( ) {
87
+ this = zipInputStream ( ) . getMethod ( [ "open" , "new" ] ) . getReturn ( ) . asSource ( )
88
+ }
101
89
}
102
90
103
91
/**
@@ -144,12 +132,14 @@ module ZipFile {
144
132
* `ZipEntry.extract`
145
133
* A sanitizer exists inside the nodes which have `entry.size > someOBJ`
146
134
*/
147
- class DecompressionBombSink extends DecompressionBomb:: Range {
148
- DecompressionBombSink ( ) { this = rubyZipNode ( zipFile ( ) ) }
149
-
150
- override DataFlow:: Node sink ( ) {
151
- result = this .getMethod ( [ "extract" , "read" ] ) .getReturn ( ) .asSource ( ) and
152
- not exists ( this .getMethod ( "size" ) .getReturn ( ) .getMethod ( ">" ) .getParameter ( 0 ) )
135
+ class DecompressionBombSink extends DecompressionBomb:: Sink {
136
+ DecompressionBombSink ( ) {
137
+ exists ( API:: Node rubyZip | rubyZip = rubyZipNode ( zipFile ( ) ) |
138
+ this = rubyZip .getMethod ( [ "extract" , "read" ] ) .getReturn ( ) .asSource ( ) and
139
+ not exists (
140
+ rubyZip .getMethod ( "size" ) .getReturn ( ) .getMethod ( [ ">" , " <" , "<=" , " >=" ] ) .getParameter ( 0 )
141
+ )
142
+ )
153
143
}
154
144
}
155
145
@@ -166,4 +156,60 @@ module ZipFile {
166
156
)
167
157
}
168
158
}
159
+
160
+ predicate isAdditionalTaintStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
161
+ exists ( API:: Node zipFile | zipFile = zipFile ( ) .getMethod ( "open" ) |
162
+ nodeFrom = zipFile .getParameter ( 0 ) .asSink ( ) and
163
+ nodeTo = rubyZipNode ( zipFile ) .getMethod ( [ "extract" , "read" ] ) .getReturn ( ) .asSource ( )
164
+ )
165
+ }
166
+ // /**
167
+ // * The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
168
+ // */
169
+ // class AdditionalTaintStep1 extends DecompressionBomb::AdditionalTaintStep {
170
+ // AdditionalTaintStep1() { this = "AdditionalTaintStep" }
171
+ // override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
172
+ // exists(API::Node zipFile | zipFile = zipFile().getMethod("open") |
173
+ // nodeFrom = zipFile.getParameter(0).asSink() and
174
+ // nodeTo = zipFile.asSource()
175
+ // )
176
+ // }
177
+ // }
178
+ // API::Node rubyZipNode2() {
179
+ // result = zipFile().getMethod("open")
180
+ // or
181
+ // result = rubyZipNode2().getMethod(_)
182
+ // or
183
+ // result = rubyZipNode2().getReturn()
184
+ // or
185
+ // result = rubyZipNode2().getParameter(_)
186
+ // or
187
+ // result = rubyZipNode2().getAnElement()
188
+ // or
189
+ // result = rubyZipNode2().getBlock()
190
+ // }
191
+ // /**
192
+ // * The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
193
+ // */
194
+ // class AdditionalTaintStep2 extends DecompressionBomb::AdditionalTaintStep {
195
+ // AdditionalTaintStep2() { this = "AdditionalTaintStep" }
196
+ // override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
197
+ // exists(API::Node zipFileOpen | zipFileOpen = rubyZipNode2() |
198
+ // nodeFrom = zipFileOpen.getReturn().asSource() and
199
+ // nodeTo = zipFileOpen.getMethod(["extract", "read"]).getReturn().asSource()
200
+ // )
201
+ // }
202
+ // }
203
+ // /**
204
+ // * The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
205
+ // */
206
+ // class AdditionalTaintStep3 extends DecompressionBomb::AdditionalTaintStep {
207
+ // AdditionalTaintStep3() { this = "AdditionalTaintStep" }
208
+ // override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
209
+ // exists(API::Node zipFileOpen | zipFileOpen = rubyZipNode2() |
210
+ // nodeFrom = zipFileOpen.asCall() and
211
+ // nodeTo = zipFileOpen.getMethod(["extract", "read"]).getReturn().asSource()
212
+ // )
213
+ // }
214
+ // }
169
215
}
0 commit comments