add more source and sinks and sanitizers

This commit is contained in:
amammad
2023-06-26 00:21:55 +10:00
parent 430375e2f0
commit ae98510f77
4 changed files with 251 additions and 69 deletions

View File

@@ -1,69 +0,0 @@
/**
* @name User-controlled file decompression
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision medium
* @id cpp/user-controlled-file-decompression
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
/**
* The `gzopen` function, which can perform command substitution.
*/
private class GzopenFunction extends Function {
GzopenFunction() { hasGlobalName("gzopen") }
}
/**
* The `gzread` function, which can perform command substitution.
*/
private class GzreadFunction extends Function {
GzreadFunction() { hasGlobalName("gzread") }
}
module ZlibTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(FunctionCall fc | fc.getTarget() instanceof GzopenFunction |
fc.getArgument(0) = source.asExpr()
)
}
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc | fc.getTarget() instanceof GzreadFunction |
fc.getArgument(0) = sink.asExpr() and
not sanitizer(fc)
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget() instanceof GzopenFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
predicate sanitizer(FunctionCall fc) {
exists(Expr e | fc.getTarget() instanceof GzreadFunction |
// a RelationalOperation which isn't compared with a Literal that using for end of read
TaintTracking::localExprTaint(fc, e.(RelationalOperation).getAChild*()) and
not e.getAChild*().(Literal).getValue() = ["0", "1", "-1"]
)
}
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
import ZlibTaint::PathGraph
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
where ZlibTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This file extraction depends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,139 @@
/**
* @name User-controlled file decompression
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id cpp/user-controlled-file-decompression1
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
/**
* A gzFile Variable as a Flow source
*/
private class GzFileVar extends VariableAccess {
GzFileVar() { this.getType().hasName("gzFile") }
}
/**
* The `gzopen` function as a Flow source
*/
private class GzopenFunction extends Function {
GzopenFunction() { hasGlobalName("gzopen") }
}
/**
* The `gzdopen` function as a Flow source
*/
private class GzdopenFunction extends Function {
GzdopenFunction() { hasGlobalName("gzdopen") }
}
/**
* The `gzfread` function is used in Flow sink
*/
private class GzfreadFunction extends Function {
GzfreadFunction() { hasGlobalName("gzfread") }
}
/**
* The `gzread` function is used in Flow sink
*/
private class GzreadFunction extends Function {
GzreadFunction() { hasGlobalName("gzread") }
}
module ZlibTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// gzopen(const char *path, const char *mode);
exists(FunctionCall fc | fc.getTarget() instanceof GzopenFunction |
fc.getArgument(0) = source.asExpr() and
// arg 0 can be a path string whichwe must do following check
not fc.getArgument(0).isConstant()
)
or
//gzdopen(int fd, const char *mode);
// IDK whether it is good to use all file decriptors function returns as source or not
// because we can do more sanitization from fd function sources
exists(FunctionCall fc | fc.getTarget() instanceof GzdopenFunction |
fc.getArgument(0) = source.asExpr()
)
or
source.asExpr() instanceof GzFileVar
}
predicate isSink(DataFlow::Node sink) {
// gzread(gzFile file, voidp buf, unsigned len));
exists(FunctionCall fc | fc.getTarget() instanceof GzreadFunction |
fc.getArgument(0) = sink.asExpr() and
not sanitizer(fc)
// TODO: and not sanitizer2(fc.getArgument(2))
)
or
// gzfread((voidp buf, z_size_t size, z_size_t nitems, gzFile file));
exists(FunctionCall fc | fc.getTarget() instanceof GzfreadFunction |
sink.asExpr() = fc.getArgument(3)
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
// gzopen(const char *path, const char *mode);
// gzdopen(int fd, const char *mode);
exists(FunctionCall fc |
fc.getTarget() instanceof GzopenFunction or fc.getTarget() instanceof GzdopenFunction
|
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
or
// gzread(gzFile file, voidp buf, unsigned len);
exists(FunctionCall fc | fc.getTarget() instanceof GzreadFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc.getArgument(1)
)
or
// gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file);
exists(FunctionCall fc | fc.getTarget() instanceof GzfreadFunction |
node1.asExpr() = fc.getArgument(3) and
node2.asExpr() = fc.getArgument(0)
)
}
}
predicate sanitizer(FunctionCall fc) {
exists(Expr e |
// a RelationalOperation which isn't compared with a Literal that using for end of read
TaintTracking::localExprTaint(fc, e.(RelationalOperation).getAChild*()) and
not e.getAChild*().(Literal).getValue() = ["0", "1", "-1"]
)
}
// TODO:
// predicate sanitizer2(Expr arg) {
// exists(Expr e |
// // a RelationalOperation which isn't compared with a Literal that using for end of read
// TaintTracking::localExprTaint(arg, e.(RelationalOperation).getAChild*())
// )
// }
// predicate test(FunctionCall fc, Expr sink) {
// exists( | fc.getTarget() instanceof GzreadFunction |
// // a RelationalOperation which isn't compared with a Literal that using for end of read
// TaintTracking::localExprTaint(fc.getArgument(2).(VariableAccess), sink)
// ) and
// sink.getFile().getLocation().toString().matches("%main.cpp%")
// }
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
import ZlibTaint::PathGraph
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
where ZlibTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,56 @@
/**
* @name User-controlled file decompression
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id cpp/user-controlled-file-decompression2
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
/**
* A z_stream Variable as a Flow source
*/
private class ZStreamVar extends VariableAccess {
ZStreamVar() { this.getType().hasName("z_stream") }
}
/**
* The `inflate`/`inflateSync` function is used in Flow sink
*/
private class DeflateFunction extends Function {
DeflateFunction() { hasGlobalName(["inflate", "inflateSync"]) }
}
module ZlibTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof ZStreamVar }
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc | fc.getTarget() instanceof DeflateFunction |
fc.getArgument(0) = sink.asExpr()
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget() instanceof DeflateFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
import ZlibTaint::PathGraph
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
where ZlibTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,56 @@
/**
* @name User-controlled file decompression
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id cpp/user-controlled-file-decompression3
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
/**
* A Bytef Variable as a Flow source
*/
private class BytefVar extends VariableAccess {
BytefVar() { this.getType().hasName("Bytef") }
}
/**
* The `uncompress`/`uncompress2` function is used in Flow sink
*/
private class UncompressFunction extends Function {
UncompressFunction() { hasGlobalName(["uncompress", "uncompress2"]) }
}
module ZlibTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof BytefVar }
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc | fc.getTarget() instanceof UncompressFunction |
fc.getArgument(0) = sink.asExpr()
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget() instanceof UncompressFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;
import ZlibTaint::PathGraph
from ZlibTaint::PathNode source, ZlibTaint::PathNode sink
where ZlibTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
"potentially untrusted source"