mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
add more source and sinks and sanitizers
This commit is contained in:
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user