Skip to content

Commit ae98510

Browse files
committed
add more source and sinks and sanitizers
1 parent 430375e commit ae98510

4 files changed

Lines changed: 251 additions & 69 deletions

File tree

cpp/ql/src/experimental/Security/CWE/CWE-409-DecompressionBomb/Bombs.ql

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* @name User-controlled file decompression
3+
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision high
8+
* @id cpp/user-controlled-file-decompression1
9+
* @tags security
10+
* experimental
11+
* external/cwe/cwe-409
12+
*/
13+
14+
import cpp
15+
import semmle.code.cpp.ir.dataflow.TaintTracking
16+
import semmle.code.cpp.security.FlowSources
17+
18+
/**
19+
* A gzFile Variable as a Flow source
20+
*/
21+
private class GzFileVar extends VariableAccess {
22+
GzFileVar() { this.getType().hasName("gzFile") }
23+
}
24+
25+
/**
26+
* The `gzopen` function as a Flow source
27+
*/
28+
private class GzopenFunction extends Function {
29+
GzopenFunction() { hasGlobalName("gzopen") }
30+
}
31+
32+
/**
33+
* The `gzdopen` function as a Flow source
34+
*/
35+
private class GzdopenFunction extends Function {
36+
GzdopenFunction() { hasGlobalName("gzdopen") }
37+
}
38+
39+
/**
40+
* The `gzfread` function is used in Flow sink
41+
*/
42+
private class GzfreadFunction extends Function {
43+
GzfreadFunction() { hasGlobalName("gzfread") }
44+
}
45+
46+
/**
47+
* The `gzread` function is used in Flow sink
48+
*/
49+
private class GzreadFunction extends Function {
50+
GzreadFunction() { hasGlobalName("gzread") }
51+
}
52+
53+
module ZlibTaintConfig implements DataFlow::ConfigSig {
54+
predicate isSource(DataFlow::Node source) {
55+
// gzopen(const char *path, const char *mode);
56+
exists(FunctionCall fc | fc.getTarget() instanceof GzopenFunction |
57+
fc.getArgument(0) = source.asExpr() and
58+
// arg 0 can be a path string whichwe must do following check
59+
not fc.getArgument(0).isConstant()
60+
)
61+
or
62+
//gzdopen(int fd, const char *mode);
63+
// IDK whether it is good to use all file decriptors function returns as source or not
64+
// because we can do more sanitization from fd function sources
65+
exists(FunctionCall fc | fc.getTarget() instanceof GzdopenFunction |
66+
fc.getArgument(0) = source.asExpr()
67+
)
68+
or
69+
source.asExpr() instanceof GzFileVar
70+
}
71+
72+
predicate isSink(DataFlow::Node sink) {
73+
// gzread(gzFile file, voidp buf, unsigned len));
74+
exists(FunctionCall fc | fc.getTarget() instanceof GzreadFunction |
75+
fc.getArgument(0) = sink.asExpr() and
76+
not sanitizer(fc)
77+
// TODO: and not sanitizer2(fc.getArgument(2))
78+
)
79+
or
80+
// gzfread((voidp buf, z_size_t size, z_size_t nitems, gzFile file));
81+
exists(FunctionCall fc | fc.getTarget() instanceof GzfreadFunction |
82+
sink.asExpr() = fc.getArgument(3)
83+
)
84+
}
85+
86+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
87+
// gzopen(const char *path, const char *mode);
88+
// gzdopen(int fd, const char *mode);
89+
exists(FunctionCall fc |
90+
fc.getTarget() instanceof GzopenFunction or fc.getTarget() instanceof GzdopenFunction
91+
|
92+
node1.asExpr() = fc.getArgument(0) and
93+
node2.asExpr() = fc
94+
)
95+
or
96+
// gzread(gzFile file, voidp buf, unsigned len);
97+
exists(FunctionCall fc | fc.getTarget() instanceof GzreadFunction |
98+
node1.asExpr() = fc.getArgument(0) and
99+
node2.asExpr() = fc.getArgument(1)
100+
)
101+
or
102+
// gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file);
103+
exists(FunctionCall fc | fc.getTarget() instanceof GzfreadFunction |
104+
node1.asExpr() = fc.getArgument(3) and
105+
node2.asExpr() = fc.getArgument(0)
106+
)
107+
}
108+
}
109+
110+
predicate sanitizer(FunctionCall fc) {
111+
exists(Expr e |
112+
// a RelationalOperation which isn't compared with a Literal that using for end of read
113+
TaintTracking::localExprTaint(fc, e.(RelationalOperation).getAChild*()) and
114+
not e.getAChild*().(Literal).getValue() = ["0", "1", "-1"]
115+
)
116+
}
117+
118+
// TODO:
119+
// predicate sanitizer2(Expr arg) {
120+
// exists(Expr e |
121+
// // a RelationalOperation which isn't compared with a Literal that using for end of read
122+
// TaintTracking::localExprTaint(arg, e.(RelationalOperation).getAChild*())
123+
// )
124+
// }
125+
// predicate test(FunctionCall fc, Expr sink) {
126+
// exists( | fc.getTarget() instanceof GzreadFunction |
127+
// // a RelationalOperation which isn't compared with a Literal that using for end of read
128+
// TaintTracking::localExprTaint(fc.getArgument(2).(VariableAccess), sink)
129+
// ) and
130+
// sink.getFile().getLocation().toString().matches("%main.cpp%")
131+
// }
132+
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
133+
134+
import ZlibTaint::PathGraph
135+
136+
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
137+
where ZlibTaint::flowPath(source, sink)
138+
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
139+
"potentially untrusted source"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @name User-controlled file decompression
3+
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision high
8+
* @id cpp/user-controlled-file-decompression2
9+
* @tags security
10+
* experimental
11+
* external/cwe/cwe-409
12+
*/
13+
14+
import cpp
15+
import semmle.code.cpp.ir.dataflow.TaintTracking
16+
import semmle.code.cpp.security.FlowSources
17+
18+
/**
19+
* A z_stream Variable as a Flow source
20+
*/
21+
private class ZStreamVar extends VariableAccess {
22+
ZStreamVar() { this.getType().hasName("z_stream") }
23+
}
24+
25+
/**
26+
* The `inflate`/`inflateSync` function is used in Flow sink
27+
*/
28+
private class DeflateFunction extends Function {
29+
DeflateFunction() { hasGlobalName(["inflate", "inflateSync"]) }
30+
}
31+
32+
module ZlibTaintConfig implements DataFlow::ConfigSig {
33+
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof ZStreamVar }
34+
35+
predicate isSink(DataFlow::Node sink) {
36+
exists(FunctionCall fc | fc.getTarget() instanceof DeflateFunction |
37+
fc.getArgument(0) = sink.asExpr()
38+
)
39+
}
40+
41+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
42+
exists(FunctionCall fc | fc.getTarget() instanceof DeflateFunction |
43+
node1.asExpr() = fc.getArgument(0) and
44+
node2.asExpr() = fc
45+
)
46+
}
47+
}
48+
49+
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
50+
51+
import ZlibTaint::PathGraph
52+
53+
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
54+
where ZlibTaint::flowPath(source, sink)
55+
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
56+
"potentially untrusted source"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @name User-controlled file decompression
3+
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision high
8+
* @id cpp/user-controlled-file-decompression3
9+
* @tags security
10+
* experimental
11+
* external/cwe/cwe-409
12+
*/
13+
14+
import cpp
15+
import semmle.code.cpp.ir.dataflow.TaintTracking
16+
import semmle.code.cpp.security.FlowSources
17+
18+
/**
19+
* A Bytef Variable as a Flow source
20+
*/
21+
private class BytefVar extends VariableAccess {
22+
BytefVar() { this.getType().hasName("Bytef") }
23+
}
24+
25+
/**
26+
* The `uncompress`/`uncompress2` function is used in Flow sink
27+
*/
28+
private class UncompressFunction extends Function {
29+
UncompressFunction() { hasGlobalName(["uncompress", "uncompress2"]) }
30+
}
31+
32+
module ZlibTaintConfig implements DataFlow::ConfigSig {
33+
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof BytefVar }
34+
35+
predicate isSink(DataFlow::Node sink) {
36+
exists(FunctionCall fc | fc.getTarget() instanceof UncompressFunction |
37+
fc.getArgument(0) = sink.asExpr()
38+
)
39+
}
40+
41+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
42+
exists(FunctionCall fc | fc.getTarget() instanceof UncompressFunction |
43+
node1.asExpr() = fc.getArgument(0) and
44+
node2.asExpr() = fc
45+
)
46+
}
47+
}
48+
49+
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
50+
51+
import ZlibTaint::PathGraph
52+
53+
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
54+
where ZlibTaint::flowPath(source, sink)
55+
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
56+
"potentially untrusted source"

0 commit comments

Comments
 (0)