Merge pull request #12435 from jketema/more-config

C++: Convert a number of data flow based queries to use `ConfigSig`
This commit is contained in:
Mathias Vorreiter Pedersen
2023-03-08 13:25:54 +00:00
committed by GitHub
22 changed files with 198 additions and 169 deletions

View File

@@ -17,7 +17,7 @@ import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.controlflow.IRGuards
import semmle.code.cpp.security.FlowSources
import DataFlow::PathGraph
import OverflowDestination::PathGraph
/**
* Holds if `fc` is a call to a copy operation where the size argument contains
@@ -66,14 +66,12 @@ predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Va
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
}
class OverflowDestinationConfig extends TaintTracking::Configuration {
OverflowDestinationConfig() { this = "OverflowDestinationConfig" }
module OverflowDestinationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
predicate isSink(DataFlow::Node sink) { sourceSized(_, sink.asIndirectConvertedExpr()) }
override predicate isSink(DataFlow::Node sink) { sourceSized(_, sink.asIndirectConvertedExpr()) }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
exists(Variable checkedVar |
readsVariable(node.asInstruction(), checkedVar) and
hasUpperBoundsCheck(checkedVar)
@@ -86,11 +84,11 @@ class OverflowDestinationConfig extends TaintTracking::Configuration {
}
}
from
FunctionCall fc, OverflowDestinationConfig conf, DataFlow::PathNode source,
DataFlow::PathNode sink
module OverflowDestination = TaintTracking::Make<OverflowDestinationConfig>;
from FunctionCall fc, OverflowDestination::PathNode source, OverflowDestination::PathNode sink
where
conf.hasFlowPath(source, sink) and
OverflowDestination::hasFlowPath(source, sink) and
sourceSized(fc, sink.getNode().asIndirectConvertedExpr())
select fc, source, sink,
"To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size."

View File

@@ -11,6 +11,6 @@
import cpp
import NtohlArrayNoBound
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
where bufConfig.hasFlow(source, sink)
from DataFlow::Node source, DataFlow::Node sink
where NetworkToBufferSizeFlow::hasFlow(source, sink)
select sink, "Unchecked use of data from network function $@.", source, source.toString()

View File

@@ -129,7 +129,7 @@ class NetworkFunctionCall extends FunctionCall {
NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
}
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
deprecated class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
NetworkToBufferSizeConfiguration() { this = "NetworkToBufferSizeConfiguration" }
override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof NetworkFunctionCall }
@@ -146,3 +146,19 @@ class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
)
}
}
private module NetworkToBufferSizeConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof NetworkFunctionCall }
predicate isSink(DataFlow::Node node) { node.asExpr() = any(BufferAccess ba).getAccessedLength() }
predicate isBarrier(DataFlow::Node node) {
exists(GuardCondition gc, GVN gvn |
gc.getAChild*() = gvn.getAnExpr() and
globalValueNumber(node.asExpr()) = gvn and
gc.controls(node.asExpr().getBasicBlock(), _)
)
}
}
module NetworkToBufferSizeFlow = DataFlow::Make<NetworkToBufferSizeConfiguration>;

View File

@@ -10,12 +10,10 @@ import ExternalAPIsSpecific
/** A node representing untrusted data being passed to an external API. */
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) }
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::hasFlow(_, this) }
/** Gets a source of untrusted data which is passed to this external API data node. */
DataFlow::Node getAnUntrustedSource() {
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
}
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::hasFlow(result, this) }
}
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */

View File

@@ -45,7 +45,7 @@ class ExternalApiDataNode extends DataFlow::Node {
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
override predicate isSource(DataFlow::Node source) {
@@ -60,3 +60,17 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(RemoteFlowSourceFunction remoteFlow |
remoteFlow = source.asExpr().(Call).getTarget() and
remoteFlow.hasRemoteFlowSource(_, _)
)
}
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
}
module UntrustedDataToExternalApiFlow = TaintTracking::Make<UntrustedDataToExternalApiConfig>;

View File

@@ -13,10 +13,10 @@ import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import ir.ExternalAPIs
import semmle.code.cpp.security.FlowSources
import DataFlow::PathGraph
import UntrustedDataToExternalApiFlow::PathGraph
from UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
from UntrustedDataToExternalApiFlow::PathNode source, UntrustedDataToExternalApiFlow::PathNode sink
where UntrustedDataToExternalApiFlow::hasFlowPath(source, sink)
select sink, source, sink,
"Call to " + sink.getNode().(ExternalApiDataNode).getExternalFunction().toString() +
" with untrusted data from $@.", source, source.getNode().(RemoteFlowSource).getSourceType()

View File

@@ -12,10 +12,10 @@
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import ExternalAPIs
import DataFlow::PathGraph
import UntrustedDataToExternalApiFlow::PathGraph
from UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
from UntrustedDataToExternalApiFlow::PathNode source, UntrustedDataToExternalApiFlow::PathNode sink
where UntrustedDataToExternalApiFlow::hasFlowPath(source, sink)
select sink, source, sink,
"Call to " + sink.getNode().(ExternalApiDataNode).getExternalFunction().toString() +
" with untrusted data from $@.", source, source.toString()

View File

@@ -10,12 +10,10 @@ import ExternalAPIsSpecific
/** A node representing untrusted data being passed to an external API. */
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) }
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::hasFlow(_, this) }
/** Gets a source of untrusted data which is passed to this external API data node. */
DataFlow::Node getAnUntrustedSource() {
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
}
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::hasFlow(result, this) }
}
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */

View File

@@ -45,7 +45,7 @@ class ExternalApiDataNode extends DataFlow::Node {
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfigIR" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
@@ -55,3 +55,12 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
}
module UntrustedDataToExternalApiFlow = TaintTracking::Make<UntrustedDataToExternalApiConfig>;

View File

@@ -17,7 +17,7 @@ import semmle.code.cpp.controlflow.IRGuards
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import DataFlow::PathGraph
import ImproperArrayIndexValidation::PathGraph
import semmle.code.cpp.security.Security
predicate hasUpperBound(VariableAccess offsetExpr) {
@@ -65,12 +65,10 @@ predicate predictableInstruction(Instruction instr) {
predictableInstruction(instr.(UnaryInstruction).getUnary())
}
class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
ImproperArrayIndexValidationConfig() { this = "ImproperArrayIndexValidationConfig" }
module ImproperArrayIndexValidationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
override predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
hasUpperBound(node.asExpr())
or
// These barriers are ported from `DefaultTaintTracking` because this query is quite noisy
@@ -107,7 +105,7 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(ArrayExpr arrayExpr, VariableAccess offsetExpr |
offsetExpr = arrayExpr.getArrayOffset() and
sink.asExpr() = offsetExpr and
@@ -116,11 +114,13 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
}
}
module ImproperArrayIndexValidation = TaintTracking::Make<ImproperArrayIndexValidationConfig>;
from
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
ImproperArrayIndexValidation::PathNode source, ImproperArrayIndexValidation::PathNode sink,
string sourceType
where
conf.hasFlowPath(source, sink) and
ImproperArrayIndexValidation::hasFlowPath(source, sink) and
isFlowSource(source.getNode(), sourceType)
select sink.getNode(), source, sink,
"An array indexing expression depends on $@ that might be outside the bounds of the array.",

View File

@@ -17,7 +17,7 @@ import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph
import UncontrolledArith::PathGraph
import Bounded
/**
@@ -90,10 +90,8 @@ predicate missingGuard(VariableAccess va, string effect) {
)
}
class UncontrolledArithConfiguration extends TaintTracking::Configuration {
UncontrolledArithConfiguration() { this = "UncontrolledArithConfiguration" }
override predicate isSource(DataFlow::Node source) {
module UncontrolledArithConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(RandomFunction rand, Call call | call.getTarget() = rand |
rand.getFunctionOutput().isReturnValue() and
source.asExpr() = call
@@ -105,9 +103,9 @@ class UncontrolledArithConfiguration extends TaintTracking::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) { missingGuard(sink.asExpr(), _) }
predicate isSink(DataFlow::Node sink) { missingGuard(sink.asExpr(), _) }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
bounded(node.asExpr())
or
// If this expression is part of bitwise 'and' or 'or' operation it's likely that the value is
@@ -124,14 +122,16 @@ class UncontrolledArithConfiguration extends TaintTracking::Configuration {
}
}
module UncontrolledArith = TaintTracking::Make<UncontrolledArithConfiguration>;
/** Gets the expression that corresponds to `node`, if any. */
Expr getExpr(DataFlow::Node node) { result = [node.asExpr(), node.asDefiningArgument()] }
from
UncontrolledArithConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
VariableAccess va, string effect
UncontrolledArith::PathNode source, UncontrolledArith::PathNode sink, VariableAccess va,
string effect
where
config.hasFlowPath(source, sink) and
UncontrolledArith::hasFlowPath(source, sink) and
sink.getNode().asExpr() = va and
missingGuard(va, effect)
select sink.getNode(), source, sink,

View File

@@ -25,24 +25,22 @@ class SslGetVerifyResultCall extends FunctionCall {
* Data flow from a call to `SSL_get_verify_result` to a guard condition
* that references the result.
*/
class VerifyResultConfig extends DataFlow::Configuration {
VerifyResultConfig() { this = "VerifyResultConfig" }
module VerifyResultConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SslGetVerifyResultCall }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SslGetVerifyResultCall
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
}
}
module VerifyResult = DataFlow::Make<VerifyResultConfig>;
from
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2,
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue
DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2, GuardCondition guard, Expr c1,
Expr c2, boolean testIsTrue
where
config.hasFlow(source, sink1) and
config.hasFlow(source, sink2) and
VerifyResult::hasFlow(source, sink1) and
VerifyResult::hasFlow(source, sink2) and
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
c1.getValue().toInt() = 0 and

View File

@@ -16,7 +16,7 @@ import semmle.code.cpp.security.BufferWrite as BufferWrite
import semmle.code.cpp.security.SensitiveExprs
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph
import ToBufferFlow::PathGraph
/**
* A buffer write into a sensitive expression.
@@ -39,27 +39,27 @@ class SensitiveBufferWrite extends Expr instanceof BufferWrite::BufferWrite {
* A taint flow configuration for flow from user input to a buffer write
* into a sensitive expression.
*/
class ToBufferConfiguration extends TaintTracking::Configuration {
ToBufferConfiguration() { this = "ToBufferConfiguration" }
module ToBufferConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
override predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _) }
predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _) }
}
module ToBufferFlow = TaintTracking::Make<ToBufferConfiguration>;
predicate isSinkImpl(DataFlow::Node sink, SensitiveBufferWrite w) {
w.getASource() = sink.asIndirectExpr()
}
from
ToBufferConfiguration config, SensitiveBufferWrite w, DataFlow::PathNode sourceNode,
DataFlow::PathNode sinkNode, FlowSource source
SensitiveBufferWrite w, ToBufferFlow::PathNode sourceNode, ToBufferFlow::PathNode sinkNode,
FlowSource source
where
config.hasFlowPath(sourceNode, sinkNode) and
ToBufferFlow::hasFlowPath(sourceNode, sinkNode) and
sourceNode.getNode() = source and
isSinkImpl(sinkNode.getNode(), w)
select w, sourceNode, sinkNode,

View File

@@ -18,23 +18,23 @@ import semmle.code.cpp.security.FileWrite
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph
import FromSensitiveFlow::PathGraph
/**
* A taint flow configuration for flow from a sensitive expression to a `FileWrite` sink.
*/
class FromSensitiveConfiguration extends TaintTracking::Configuration {
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
module FromSensitiveConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSourceImpl(source, _) }
override predicate isSource(DataFlow::Node source) { isSourceImpl(source, _) }
predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _, _) }
override predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _, _) }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
}
module FromSensitiveFlow = TaintTracking::Make<FromSensitiveConfiguration>;
predicate isSinkImpl(DataFlow::Node sink, FileWrite w, Expr dest) {
exists(Expr e |
e = [sink.asExpr(), sink.asIndirectExpr()] and
@@ -78,10 +78,10 @@ predicate isFileName(GVN gvn) {
}
from
FromSensitiveConfiguration config, SensitiveExpr source, DataFlow::PathNode sourceNode,
DataFlow::PathNode midNode, FileWrite w, Expr dest
SensitiveExpr source, FromSensitiveFlow::PathNode sourceNode, FromSensitiveFlow::PathNode midNode,
FileWrite w, Expr dest
where
config.hasFlowPath(sourceNode, midNode) and
FromSensitiveFlow::hasFlowPath(sourceNode, midNode) and
isSourceImpl(sourceNode.getNode(), source) and
isSinkImpl(midNode.getNode(), w, dest)
select w, sourceNode, midNode,

View File

@@ -16,11 +16,9 @@ import cpp
import semmle.code.cpp.security.SensitiveExprs
import semmle.code.cpp.security.PrivateData
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.ir.dataflow.TaintTracking3
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.commons.File
import DataFlow::PathGraph
import FromSensitiveFlow::PathGraph
class SourceVariable extends Variable {
SourceVariable() {
@@ -236,72 +234,70 @@ predicate isSourceImpl(DataFlow::Node source) {
* A taint flow configuration for flow from a sensitive expression to a network
* operation.
*/
class FromSensitiveConfiguration extends TaintTracking::Configuration {
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
module FromSensitiveConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSourceImpl(source) }
override predicate isSource(DataFlow::Node source) { isSourceImpl(source) }
predicate isSink(DataFlow::Node sink) { isSinkSendRecv(sink, _) }
override predicate isSink(DataFlow::Node sink) { isSinkSendRecv(sink, _) }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
override predicate isSanitizerIn(DataFlow::Node node) {
predicate isBarrierIn(DataFlow::Node node) {
// As any use of a sensitive variable is a potential source, we need to block flow into
// sources to not get path duplication.
this.isSource(node)
isSource(node)
}
}
module FromSensitiveFlow = TaintTracking::Make<FromSensitiveConfiguration>;
/**
* A taint flow configuration for flow from a sensitive expression to an encryption operation.
*/
class ToEncryptionConfiguration extends TaintTracking2::Configuration {
ToEncryptionConfiguration() { this = "ToEncryptionConfiguration" }
module ToEncryptionConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { FromSensitiveFlow::hasFlow(source, _) }
override predicate isSource(DataFlow::Node source) {
any(FromSensitiveConfiguration config).hasFlow(source, _)
}
predicate isSink(DataFlow::Node sink) { isSinkEncrypt(sink, _) }
override predicate isSink(DataFlow::Node sink) { isSinkEncrypt(sink, _) }
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
override predicate isSanitizerIn(DataFlow::Node node) {
predicate isBarrierIn(DataFlow::Node node) {
// As any use of a sensitive variable is a potential source, we need to block flow into
// sources to not get path duplication.
this.isSource(node)
isSource(node)
}
}
module ToEncryptionFlow = TaintTracking::Make<ToEncryptionConfiguration>;
/**
* A taint flow configuration for flow from an encryption operation to a network operation.
*/
class FromEncryptionConfiguration extends TaintTracking3::Configuration {
FromEncryptionConfiguration() { this = "FromEncryptionConfiguration" }
module FromEncryptionConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSinkEncrypt(source, _) }
override predicate isSource(DataFlow::Node source) { isSinkEncrypt(source, _) }
predicate isSink(DataFlow::Node sink) { FromSensitiveFlow::hasFlowTo(sink) }
override predicate isSink(DataFlow::Node sink) {
any(FromSensitiveConfiguration config).hasFlowTo(sink)
}
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, NetworkSendRecv networkSendRecv, string msg
module FromEncryptionFlow = TaintTracking::Make<FromEncryptionConfiguration>;
from
FromSensitiveFlow::PathNode source, FromSensitiveFlow::PathNode sink,
NetworkSendRecv networkSendRecv, string msg
where
// flow from sensitive -> network data
any(FromSensitiveConfiguration config).hasFlowPath(source, sink) and
FromSensitiveFlow::hasFlowPath(source, sink) and
isSinkSendRecv(sink.getNode(), networkSendRecv) and
// no flow from sensitive -> evidence of encryption
not any(ToEncryptionConfiguration config).hasFlow(source.getNode(), _) and
not any(FromEncryptionConfiguration config).hasFlowTo(sink.getNode()) and
not ToEncryptionFlow::hasFlow(source.getNode(), _) and
not FromEncryptionFlow::hasFlowTo(sink.getNode()) and
// construct result
if networkSendRecv instanceof NetworkSend
then

View File

@@ -14,7 +14,7 @@
import cpp
import semmle.code.cpp.security.SensitiveExprs
import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph
import FromSensitiveFlow::PathGraph
class SqliteFunctionCall extends FunctionCall {
SqliteFunctionCall() { this.getTarget().getName().matches("sqlite%") }
@@ -56,21 +56,19 @@ predicate isSinkImpl(DataFlow::Node sink, SqliteFunctionCall c, Type t) {
/**
* A taint flow configuration for flow from a sensitive expression to a `SqliteFunctionCall` sink.
*/
class FromSensitiveConfiguration extends TaintTracking::Configuration {
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
module FromSensitiveConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSourceImpl(source, _) }
override predicate isSource(DataFlow::Node source) { isSourceImpl(source, _) }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
isSinkImpl(sink, _, _) and
not sqlite_encryption_used()
}
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet content) {
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet content) {
// flow out from fields at the sink (only).
// constrain `content` to a field inside the node.
exists(Type t |
@@ -80,11 +78,13 @@ class FromSensitiveConfiguration extends TaintTracking::Configuration {
}
}
module FromSensitiveFlow = TaintTracking::Make<FromSensitiveConfiguration>;
from
FromSensitiveConfiguration config, SensitiveExpr sensitive, DataFlow::PathNode source,
DataFlow::PathNode sink, SqliteFunctionCall sqliteCall
SensitiveExpr sensitive, FromSensitiveFlow::PathNode source, FromSensitiveFlow::PathNode sink,
SqliteFunctionCall sqliteCall
where
config.hasFlowPath(source, sink) and
FromSensitiveFlow::hasFlowPath(source, sink) and
isSourceImpl(source.getNode(), sensitive) and
isSinkImpl(sink.getNode(), sqliteCall, _)
select sqliteCall, source, sink,

View File

@@ -14,7 +14,7 @@
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import DataFlow::PathGraph
import HttpStringToUrlOpen::PathGraph
/**
* A string matching private host names of IPv4 and IPv6, which only matches
@@ -54,10 +54,8 @@ class HttpStringLiteral extends StringLiteral {
/**
* Taint tracking configuration for HTTP connections.
*/
class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
HttpStringToUrlOpenConfig() { this = "HttpStringToUrlOpenConfig" }
override predicate isSource(DataFlow::Node src) {
module HttpStringToUrlOpenConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
// Sources are strings containing an HTTP URL not in a private domain.
src.asIndirectExpr() instanceof HttpStringLiteral and
// block taint starting at `strstr`, which is likely testing an existing URL, rather than constructing an HTTP URL.
@@ -67,7 +65,7 @@ class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
// Sinks can be anything that demonstrates the string is likely to be
// accessed as a URL, for example using it in a network access. Some
// URLs are only ever displayed or used for data processing.
@@ -91,10 +89,10 @@ class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
}
}
from
HttpStringToUrlOpenConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
HttpStringLiteral str
module HttpStringToUrlOpen = TaintTracking::Make<HttpStringToUrlOpenConfig>;
from HttpStringToUrlOpen::PathNode source, HttpStringToUrlOpen::PathNode sink, HttpStringLiteral str
where
config.hasFlowPath(source, sink) and
HttpStringToUrlOpen::hasFlowPath(source, sink) and
str = source.getNode().asIndirectExpr()
select str, source, sink, "This URL may be constructed with the HTTP protocol."

View File

@@ -14,7 +14,7 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.IR
import DataFlow::PathGraph
import KeyStrengthFlow::PathGraph
// Gets the recommended minimum key size (in bits) of `func`, the name of an encryption function that accepts a key size as parameter `paramIndex`
int getMinimumKeyStrength(string func, int paramIndex) {
@@ -28,10 +28,8 @@ int getMinimumKeyStrength(string func, int paramIndex) {
result = 2048
}
class KeyStrengthFlow extends DataFlow::Configuration {
KeyStrengthFlow() { this = "KeyStrengthFlow" }
override predicate isSource(DataFlow::Node node) {
module KeyStrengthFlowConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
exists(int bits |
node.asInstruction().(IntegerConstantInstruction).getValue().toInt() = bits and
bits < getMinimumKeyStrength(_, _) and
@@ -39,7 +37,7 @@ class KeyStrengthFlow extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node node) {
predicate isSink(DataFlow::Node node) {
exists(FunctionCall fc, string name, int param |
node.asExpr() = fc.getArgument(param) and
fc.getTarget().hasGlobalName(name) and
@@ -48,11 +46,13 @@ class KeyStrengthFlow extends DataFlow::Configuration {
}
}
module KeyStrengthFlow = DataFlow::Make<KeyStrengthFlowConfiguration>;
from
DataFlow::PathNode source, DataFlow::PathNode sink, KeyStrengthFlow conf, FunctionCall fc,
int param, string name, int minimumBits, int bits
KeyStrengthFlow::PathNode source, KeyStrengthFlow::PathNode sink, FunctionCall fc, int param,
string name, int minimumBits, int bits
where
conf.hasFlowPath(source, sink) and
KeyStrengthFlow::hasFlowPath(source, sink) and
sink.getNode().asExpr() = fc.getArgument(param) and
fc.getTarget().hasGlobalName(name) and
minimumBits = getMinimumKeyStrength(name, param) and

View File

@@ -15,15 +15,13 @@
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource
import DataFlow::PathGraph
import ExposedSystemData::PathGraph
import SystemData
class ExposedSystemDataConfiguration extends TaintTracking::Configuration {
ExposedSystemDataConfiguration() { this = "ExposedSystemDataConfiguration" }
module ExposedSystemDataConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
override predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc, FunctionInput input, int arg |
fc.getTarget().(RemoteFlowSinkFunction).hasRemoteFlowSink(input, _) and
input.isParameterDeref(arg) and
@@ -32,13 +30,15 @@ class ExposedSystemDataConfiguration extends TaintTracking::Configuration {
}
}
from ExposedSystemDataConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
module ExposedSystemData = TaintTracking::Make<ExposedSystemDataConfiguration>;
from ExposedSystemData::PathNode source, ExposedSystemData::PathNode sink
where
config.hasFlowPath(source, sink) and
ExposedSystemData::hasFlowPath(source, sink) and
not exists(
DataFlow::Node alt // remove duplicate results on conversions
|
config.hasFlow(source.getNode(), alt) and
ExposedSystemData::hasFlow(source.getNode(), alt) and
alt.asConvertedExpr() = sink.getNode().asIndirectExpr() and
alt != sink.getNode()
)

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `NetworkToBufferSizeConfiguration` and `UntrustedDataToExternalApiConfig` dataflow configurations have been deprecated. Please use `NetworkToBufferSizeFlow` and `UntrustedDataToExternalApiFlow`.

View File

@@ -15,7 +15,7 @@
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
import DataFlow::PathGraph
import WordexpTaint::PathGraph
/**
* The `wordexp` function, which can perform command substitution.
@@ -35,24 +35,24 @@ private predicate isCommandSubstitutionDisabled(FunctionCall fc) {
/**
* A configuration to track user-supplied data to the `wordexp` function.
*/
class WordexpTaintConfiguration extends TaintTracking::Configuration {
WordexpTaintConfiguration() { this = "WordexpTaintConfiguration" }
module WordexpTaintConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc | fc.getTarget() instanceof WordexpFunction |
fc.getArgument(0) = sink.asExpr() and
not isCommandSubstitutionDisabled(fc)
)
}
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
}
from WordexpTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
where conf.hasFlowPath(sourceNode, sinkNode)
module WordexpTaint = TaintTracking::Make<WordexpTaintConfiguration>;
from WordexpTaint::PathNode sourceNode, WordexpTaint::PathNode sinkNode
where WordexpTaint::hasFlowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,
"Using user-supplied data in a `wordexp` command, without disabling command substitution, can make code vulnerable to command injection."

View File

@@ -15,12 +15,10 @@
import cpp
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.ir.dataflow.DataFlow
import DataFlow::PathGraph
import MultToAlloc::PathGraph
class MultToAllocConfig extends DataFlow::Configuration {
MultToAllocConfig() { this = "MultToAllocConfig" }
override predicate isSource(DataFlow::Node node) {
module MultToAllocConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
// a multiplication of two non-constant expressions
exists(MulExpr me |
me = node.asExpr() and
@@ -28,14 +26,16 @@ class MultToAllocConfig extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node node) {
predicate isSink(DataFlow::Node node) {
// something that affects an allocation size
node.asExpr() = any(HeuristicAllocationExpr ae).getSizeExpr().getAChild*()
}
}
from MultToAllocConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
module MultToAlloc = DataFlow::Make<MultToAllocConfig>;
from MultToAlloc::PathNode source, MultToAlloc::PathNode sink
where MultToAlloc::hasFlowPath(source, sink)
select sink, source, sink,
"Potentially overflowing value from $@ is used in the size of this allocation.", source,
"multiplication"