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.ir.dataflow.TaintTracking
import semmle.code.cpp.controlflow.IRGuards import semmle.code.cpp.controlflow.IRGuards
import semmle.code.cpp.security.FlowSources 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 * 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) any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
} }
class OverflowDestinationConfig extends TaintTracking::Configuration { module OverflowDestinationConfig implements DataFlow::ConfigSig {
OverflowDestinationConfig() { this = "OverflowDestinationConfig" } 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()) } predicate isBarrier(DataFlow::Node node) {
override predicate isSanitizer(DataFlow::Node node) {
exists(Variable checkedVar | exists(Variable checkedVar |
readsVariable(node.asInstruction(), checkedVar) and readsVariable(node.asInstruction(), checkedVar) and
hasUpperBoundsCheck(checkedVar) hasUpperBoundsCheck(checkedVar)
@@ -86,11 +84,11 @@ class OverflowDestinationConfig extends TaintTracking::Configuration {
} }
} }
from module OverflowDestination = TaintTracking::Make<OverflowDestinationConfig>;
FunctionCall fc, OverflowDestinationConfig conf, DataFlow::PathNode source,
DataFlow::PathNode sink from FunctionCall fc, OverflowDestination::PathNode source, OverflowDestination::PathNode sink
where where
conf.hasFlowPath(source, sink) and OverflowDestination::hasFlowPath(source, sink) and
sourceSized(fc, sink.getNode().asIndirectConvertedExpr()) sourceSized(fc, sink.getNode().asIndirectConvertedExpr())
select fc, source, sink, select fc, source, sink,
"To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size." "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 cpp
import NtohlArrayNoBound import NtohlArrayNoBound
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink from DataFlow::Node source, DataFlow::Node sink
where bufConfig.hasFlow(source, sink) where NetworkToBufferSizeFlow::hasFlow(source, sink)
select sink, "Unchecked use of data from network function $@.", source, source.toString() 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"]) } NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
} }
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration { deprecated class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
NetworkToBufferSizeConfiguration() { this = "NetworkToBufferSizeConfiguration" } NetworkToBufferSizeConfiguration() { this = "NetworkToBufferSizeConfiguration" }
override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof NetworkFunctionCall } 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. */ /** A node representing untrusted data being passed to an external API. */
class UntrustedExternalApiDataNode extends ExternalApiDataNode { 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. */ /** Gets a source of untrusted data which is passed to this external API data node. */
DataFlow::Node getAnUntrustedSource() { DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::hasFlow(result, this) }
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
}
} }
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ /** DEPRECATED: Alias for UntrustedExternalApiDataNode */

View File

@@ -45,7 +45,7 @@ class ExternalApiDataNode extends DataFlow::Node {
deprecated class ExternalAPIDataNode = ExternalApiDataNode; deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ /** 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" } UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
override predicate isSource(DataFlow::Node source) { override predicate isSource(DataFlow::Node source) {
@@ -60,3 +60,17 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ /** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = 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 semmle.code.cpp.ir.dataflow.TaintTracking
import ir.ExternalAPIs import ir.ExternalAPIs
import semmle.code.cpp.security.FlowSources import semmle.code.cpp.security.FlowSources
import DataFlow::PathGraph import UntrustedDataToExternalApiFlow::PathGraph
from UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink from UntrustedDataToExternalApiFlow::PathNode source, UntrustedDataToExternalApiFlow::PathNode sink
where config.hasFlowPath(source, sink) where UntrustedDataToExternalApiFlow::hasFlowPath(source, sink)
select sink, source, sink, select sink, source, sink,
"Call to " + sink.getNode().(ExternalApiDataNode).getExternalFunction().toString() + "Call to " + sink.getNode().(ExternalApiDataNode).getExternalFunction().toString() +
" with untrusted data from $@.", source, source.getNode().(RemoteFlowSource).getSourceType() " with untrusted data from $@.", source, source.getNode().(RemoteFlowSource).getSourceType()

View File

@@ -12,10 +12,10 @@
import cpp import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import ExternalAPIs import ExternalAPIs
import DataFlow::PathGraph import UntrustedDataToExternalApiFlow::PathGraph
from UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink from UntrustedDataToExternalApiFlow::PathNode source, UntrustedDataToExternalApiFlow::PathNode sink
where config.hasFlowPath(source, sink) where UntrustedDataToExternalApiFlow::hasFlowPath(source, sink)
select sink, source, sink, select sink, source, sink,
"Call to " + sink.getNode().(ExternalApiDataNode).getExternalFunction().toString() + "Call to " + sink.getNode().(ExternalApiDataNode).getExternalFunction().toString() +
" with untrusted data from $@.", source, source.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. */ /** A node representing untrusted data being passed to an external API. */
class UntrustedExternalApiDataNode extends ExternalApiDataNode { 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. */ /** Gets a source of untrusted data which is passed to this external API data node. */
DataFlow::Node getAnUntrustedSource() { DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::hasFlow(result, this) }
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
}
} }
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ /** DEPRECATED: Alias for UntrustedExternalApiDataNode */

View File

@@ -45,7 +45,7 @@ class ExternalApiDataNode extends DataFlow::Node {
deprecated class ExternalAPIDataNode = ExternalApiDataNode; deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ /** 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" } UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfigIR" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
@@ -55,3 +55,12 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ /** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = 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.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import DataFlow::PathGraph import ImproperArrayIndexValidation::PathGraph
import semmle.code.cpp.security.Security import semmle.code.cpp.security.Security
predicate hasUpperBound(VariableAccess offsetExpr) { predicate hasUpperBound(VariableAccess offsetExpr) {
@@ -65,12 +65,10 @@ predicate predictableInstruction(Instruction instr) {
predictableInstruction(instr.(UnaryInstruction).getUnary()) predictableInstruction(instr.(UnaryInstruction).getUnary())
} }
class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration { module ImproperArrayIndexValidationConfig implements DataFlow::ConfigSig {
ImproperArrayIndexValidationConfig() { this = "ImproperArrayIndexValidationConfig" } predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
override predicate isSource(DataFlow::Node source) { isFlowSource(source, _) } predicate isBarrier(DataFlow::Node node) {
override predicate isSanitizer(DataFlow::Node node) {
hasUpperBound(node.asExpr()) hasUpperBound(node.asExpr())
or or
// These barriers are ported from `DefaultTaintTracking` because this query is quite noisy // 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 | exists(ArrayExpr arrayExpr, VariableAccess offsetExpr |
offsetExpr = arrayExpr.getArrayOffset() and offsetExpr = arrayExpr.getArrayOffset() and
sink.asExpr() = offsetExpr and sink.asExpr() = offsetExpr and
@@ -116,11 +114,13 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
} }
} }
module ImproperArrayIndexValidation = TaintTracking::Make<ImproperArrayIndexValidationConfig>;
from from
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink, ImproperArrayIndexValidation::PathNode source, ImproperArrayIndexValidation::PathNode sink,
string sourceType string sourceType
where where
conf.hasFlowPath(source, sink) and ImproperArrayIndexValidation::hasFlowPath(source, sink) and
isFlowSource(source.getNode(), sourceType) isFlowSource(source.getNode(), sourceType)
select sink.getNode(), source, sink, select sink.getNode(), source, sink,
"An array indexing expression depends on $@ that might be outside the bounds of the array.", "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.Security
import semmle.code.cpp.security.FlowSources import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph import UncontrolledArith::PathGraph
import Bounded import Bounded
/** /**
@@ -90,10 +90,8 @@ predicate missingGuard(VariableAccess va, string effect) {
) )
} }
class UncontrolledArithConfiguration extends TaintTracking::Configuration { module UncontrolledArithConfiguration implements DataFlow::ConfigSig {
UncontrolledArithConfiguration() { this = "UncontrolledArithConfiguration" } predicate isSource(DataFlow::Node source) {
override predicate isSource(DataFlow::Node source) {
exists(RandomFunction rand, Call call | call.getTarget() = rand | exists(RandomFunction rand, Call call | call.getTarget() = rand |
rand.getFunctionOutput().isReturnValue() and rand.getFunctionOutput().isReturnValue() and
source.asExpr() = call 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()) bounded(node.asExpr())
or or
// If this expression is part of bitwise 'and' or 'or' operation it's likely that the value is // 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. */ /** Gets the expression that corresponds to `node`, if any. */
Expr getExpr(DataFlow::Node node) { result = [node.asExpr(), node.asDefiningArgument()] } Expr getExpr(DataFlow::Node node) { result = [node.asExpr(), node.asDefiningArgument()] }
from from
UncontrolledArithConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink, UncontrolledArith::PathNode source, UncontrolledArith::PathNode sink, VariableAccess va,
VariableAccess va, string effect string effect
where where
config.hasFlowPath(source, sink) and UncontrolledArith::hasFlowPath(source, sink) and
sink.getNode().asExpr() = va and sink.getNode().asExpr() = va and
missingGuard(va, effect) missingGuard(va, effect)
select sink.getNode(), source, sink, 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 * Data flow from a call to `SSL_get_verify_result` to a guard condition
* that references the result. * that references the result.
*/ */
class VerifyResultConfig extends DataFlow::Configuration { module VerifyResultConfig implements DataFlow::ConfigSig {
VerifyResultConfig() { this = "VerifyResultConfig" } predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SslGetVerifyResultCall }
override predicate isSource(DataFlow::Node source) { predicate isSink(DataFlow::Node sink) {
source.asExpr() instanceof SslGetVerifyResultCall
}
override predicate isSink(DataFlow::Node sink) {
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr()) exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
} }
} }
module VerifyResult = DataFlow::Make<VerifyResultConfig>;
from from
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2, GuardCondition guard, Expr c1,
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue Expr c2, boolean testIsTrue
where where
config.hasFlow(source, sink1) and VerifyResult::hasFlow(source, sink1) and
config.hasFlow(source, sink2) and VerifyResult::hasFlow(source, sink2) and
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
c1.getValue().toInt() = 0 and 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.SensitiveExprs
import semmle.code.cpp.security.FlowSources import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph import ToBufferFlow::PathGraph
/** /**
* A buffer write into a sensitive expression. * 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 * A taint flow configuration for flow from user input to a buffer write
* into a sensitive expression. * into a sensitive expression.
*/ */
class ToBufferConfiguration extends TaintTracking::Configuration { module ToBufferConfiguration implements DataFlow::ConfigSig {
ToBufferConfiguration() { this = "ToBufferConfiguration" } predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource } predicate isBarrier(DataFlow::Node node) {
override predicate isSanitizer(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType 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) { predicate isSinkImpl(DataFlow::Node sink, SensitiveBufferWrite w) {
w.getASource() = sink.asIndirectExpr() w.getASource() = sink.asIndirectExpr()
} }
from from
ToBufferConfiguration config, SensitiveBufferWrite w, DataFlow::PathNode sourceNode, SensitiveBufferWrite w, ToBufferFlow::PathNode sourceNode, ToBufferFlow::PathNode sinkNode,
DataFlow::PathNode sinkNode, FlowSource source FlowSource source
where where
config.hasFlowPath(sourceNode, sinkNode) and ToBufferFlow::hasFlowPath(sourceNode, sinkNode) and
sourceNode.getNode() = source and sourceNode.getNode() = source and
isSinkImpl(sinkNode.getNode(), w) isSinkImpl(sinkNode.getNode(), w)
select w, sourceNode, sinkNode, 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.ir.dataflow.DataFlow
import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.dataflow.TaintTracking 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. * A taint flow configuration for flow from a sensitive expression to a `FileWrite` sink.
*/ */
class FromSensitiveConfiguration extends TaintTracking::Configuration { module FromSensitiveConfiguration implements DataFlow::ConfigSig {
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" } 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, _, _) } predicate isBarrier(DataFlow::Node node) {
override predicate isSanitizer(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType node.asExpr().getUnspecifiedType() instanceof IntegralType
} }
} }
module FromSensitiveFlow = TaintTracking::Make<FromSensitiveConfiguration>;
predicate isSinkImpl(DataFlow::Node sink, FileWrite w, Expr dest) { predicate isSinkImpl(DataFlow::Node sink, FileWrite w, Expr dest) {
exists(Expr e | exists(Expr e |
e = [sink.asExpr(), sink.asIndirectExpr()] and e = [sink.asExpr(), sink.asIndirectExpr()] and
@@ -78,10 +78,10 @@ predicate isFileName(GVN gvn) {
} }
from from
FromSensitiveConfiguration config, SensitiveExpr source, DataFlow::PathNode sourceNode, SensitiveExpr source, FromSensitiveFlow::PathNode sourceNode, FromSensitiveFlow::PathNode midNode,
DataFlow::PathNode midNode, FileWrite w, Expr dest FileWrite w, Expr dest
where where
config.hasFlowPath(sourceNode, midNode) and FromSensitiveFlow::hasFlowPath(sourceNode, midNode) and
isSourceImpl(sourceNode.getNode(), source) and isSourceImpl(sourceNode.getNode(), source) and
isSinkImpl(midNode.getNode(), w, dest) isSinkImpl(midNode.getNode(), w, dest)
select w, sourceNode, midNode, select w, sourceNode, midNode,

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@
import cpp import cpp
import semmle.code.cpp.ir.dataflow.DataFlow import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.IR 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` // 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) { int getMinimumKeyStrength(string func, int paramIndex) {
@@ -28,10 +28,8 @@ int getMinimumKeyStrength(string func, int paramIndex) {
result = 2048 result = 2048
} }
class KeyStrengthFlow extends DataFlow::Configuration { module KeyStrengthFlowConfiguration implements DataFlow::ConfigSig {
KeyStrengthFlow() { this = "KeyStrengthFlow" } predicate isSource(DataFlow::Node node) {
override predicate isSource(DataFlow::Node node) {
exists(int bits | exists(int bits |
node.asInstruction().(IntegerConstantInstruction).getValue().toInt() = bits and node.asInstruction().(IntegerConstantInstruction).getValue().toInt() = bits and
bits < getMinimumKeyStrength(_, _) 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 | exists(FunctionCall fc, string name, int param |
node.asExpr() = fc.getArgument(param) and node.asExpr() = fc.getArgument(param) and
fc.getTarget().hasGlobalName(name) and fc.getTarget().hasGlobalName(name) and
@@ -48,11 +46,13 @@ class KeyStrengthFlow extends DataFlow::Configuration {
} }
} }
module KeyStrengthFlow = DataFlow::Make<KeyStrengthFlowConfiguration>;
from from
DataFlow::PathNode source, DataFlow::PathNode sink, KeyStrengthFlow conf, FunctionCall fc, KeyStrengthFlow::PathNode source, KeyStrengthFlow::PathNode sink, FunctionCall fc, int param,
int param, string name, int minimumBits, int bits string name, int minimumBits, int bits
where where
conf.hasFlowPath(source, sink) and KeyStrengthFlow::hasFlowPath(source, sink) and
sink.getNode().asExpr() = fc.getArgument(param) and sink.getNode().asExpr() = fc.getArgument(param) and
fc.getTarget().hasGlobalName(name) and fc.getTarget().hasGlobalName(name) and
minimumBits = getMinimumKeyStrength(name, param) and minimumBits = getMinimumKeyStrength(name, param) and

View File

@@ -15,15 +15,13 @@
import cpp import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource import semmle.code.cpp.models.interfaces.FlowSource
import DataFlow::PathGraph import ExposedSystemData::PathGraph
import SystemData import SystemData
class ExposedSystemDataConfiguration extends TaintTracking::Configuration { module ExposedSystemDataConfiguration implements DataFlow::ConfigSig {
ExposedSystemDataConfiguration() { this = "ExposedSystemDataConfiguration" } predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
override predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc, FunctionInput input, int arg | exists(FunctionCall fc, FunctionInput input, int arg |
fc.getTarget().(RemoteFlowSinkFunction).hasRemoteFlowSink(input, _) and fc.getTarget().(RemoteFlowSinkFunction).hasRemoteFlowSink(input, _) and
input.isParameterDeref(arg) 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 where
config.hasFlowPath(source, sink) and ExposedSystemData::hasFlowPath(source, sink) and
not exists( not exists(
DataFlow::Node alt // remove duplicate results on conversions 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.asConvertedExpr() = sink.getNode().asIndirectExpr() and
alt != sink.getNode() 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 cpp
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources import semmle.code.cpp.security.FlowSources
import DataFlow::PathGraph import WordexpTaint::PathGraph
/** /**
* The `wordexp` function, which can perform command substitution. * 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. * A configuration to track user-supplied data to the `wordexp` function.
*/ */
class WordexpTaintConfiguration extends TaintTracking::Configuration { module WordexpTaintConfiguration implements DataFlow::ConfigSig {
WordexpTaintConfiguration() { this = "WordexpTaintConfiguration" } predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc | fc.getTarget() instanceof WordexpFunction | exists(FunctionCall fc | fc.getTarget() instanceof WordexpFunction |
fc.getArgument(0) = sink.asExpr() and fc.getArgument(0) = sink.asExpr() and
not isCommandSubstitutionDisabled(fc) not isCommandSubstitutionDisabled(fc)
) )
} }
override predicate isSanitizer(DataFlow::Node node) { predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType node.asExpr().getUnspecifiedType() instanceof IntegralType
} }
} }
from WordexpTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode module WordexpTaint = TaintTracking::Make<WordexpTaintConfiguration>;
where conf.hasFlowPath(sourceNode, sinkNode)
from WordexpTaint::PathNode sourceNode, WordexpTaint::PathNode sinkNode
where WordexpTaint::hasFlowPath(sourceNode, sinkNode)
select sinkNode.getNode(), 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." "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 cpp
import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.ir.dataflow.DataFlow import semmle.code.cpp.ir.dataflow.DataFlow
import DataFlow::PathGraph import MultToAlloc::PathGraph
class MultToAllocConfig extends DataFlow::Configuration { module MultToAllocConfig implements DataFlow::ConfigSig {
MultToAllocConfig() { this = "MultToAllocConfig" } predicate isSource(DataFlow::Node node) {
override predicate isSource(DataFlow::Node node) {
// a multiplication of two non-constant expressions // a multiplication of two non-constant expressions
exists(MulExpr me | exists(MulExpr me |
me = node.asExpr() and 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 // something that affects an allocation size
node.asExpr() = any(HeuristicAllocationExpr ae).getSizeExpr().getAChild*() node.asExpr() = any(HeuristicAllocationExpr ae).getSizeExpr().getAChild*()
} }
} }
from MultToAllocConfig config, DataFlow::PathNode source, DataFlow::PathNode sink module MultToAlloc = DataFlow::Make<MultToAllocConfig>;
where config.hasFlowPath(source, sink)
from MultToAlloc::PathNode source, MultToAlloc::PathNode sink
where MultToAlloc::hasFlowPath(source, sink)
select sink, source, sink, select sink, source, sink,
"Potentially overflowing value from $@ is used in the size of this allocation.", source, "Potentially overflowing value from $@ is used in the size of this allocation.", source,
"multiplication" "multiplication"