mirror of
https://github.com/github/codeql.git
synced 2026-03-05 23:26:51 +01:00
Merge pull request #12408 from jketema/merge-main
C++: use-use dataflow merge main
This commit is contained in:
@@ -19,7 +19,7 @@ import semmle.code.cpp.security.FunctionWithWrappers
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
import TaintedPath::PathGraph
|
||||
|
||||
/**
|
||||
* A function for opening a file.
|
||||
@@ -70,18 +70,16 @@ predicate hasUpperBoundsCheck(Variable var) {
|
||||
)
|
||||
}
|
||||
|
||||
class TaintedPathConfiguration extends TaintTracking::Configuration {
|
||||
TaintedPathConfiguration() { this = "TaintedPathConfiguration" }
|
||||
module TaintedPathConfiguration implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(FileFunction fileFunction |
|
||||
fileFunction.outermostWrapperFunctionCall(node.asIndirectArgument(), _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.asExpr().(Call).getTarget().getUnspecifiedType() instanceof ArithmeticType
|
||||
or
|
||||
exists(LoadInstruction load, Variable checkedVar |
|
||||
@@ -92,13 +90,15 @@ class TaintedPathConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedPath = TaintTracking::Make<TaintedPathConfiguration>;
|
||||
|
||||
from
|
||||
FileFunction fileFunction, Expr taintedArg, FlowSource taintSource, TaintedPathConfiguration cfg,
|
||||
DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string callChain
|
||||
FileFunction fileFunction, Expr taintedArg, FlowSource taintSource,
|
||||
TaintedPath::PathNode sourceNode, TaintedPath::PathNode sinkNode, string callChain
|
||||
where
|
||||
taintedArg = sinkNode.getNode().asIndirectArgument() and
|
||||
fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and
|
||||
cfg.hasFlowPath(sourceNode, sinkNode) and
|
||||
TaintedPath::hasFlowPath(sourceNode, sinkNode) and
|
||||
taintSource = sourceNode.getNode()
|
||||
select taintedArg, sourceNode, sinkNode,
|
||||
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
|
||||
|
||||
@@ -22,7 +22,7 @@ import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import DataFlow::PathGraph
|
||||
import ExecTaint::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `incoming` is a string that is used in a format or concatenation function resulting
|
||||
@@ -55,29 +55,30 @@ predicate interestingConcatenation(DataFlow::Node incoming, DataFlow::Node outgo
|
||||
)
|
||||
}
|
||||
|
||||
class ConcatState extends DataFlow::FlowState {
|
||||
ConcatState() { this = "ConcatState" }
|
||||
newtype TState =
|
||||
TConcatState() or
|
||||
TExecState(DataFlow::Node incoming, DataFlow::Node outgoing) {
|
||||
interestingConcatenation(pragma[only_bind_into](incoming), pragma[only_bind_into](outgoing))
|
||||
}
|
||||
|
||||
class ConcatState extends TConcatState {
|
||||
string toString() { result = "ConcatState" }
|
||||
}
|
||||
|
||||
class ExecState extends DataFlow::FlowState {
|
||||
class ExecState extends TExecState {
|
||||
DataFlow::Node incoming;
|
||||
DataFlow::Node outgoing;
|
||||
|
||||
ExecState() {
|
||||
this =
|
||||
"ExecState (" + incoming.getLocation() + " | " + incoming + ", " + outgoing.getLocation() +
|
||||
" | " + outgoing + ")" and
|
||||
interestingConcatenation(pragma[only_bind_into](incoming), pragma[only_bind_into](outgoing))
|
||||
}
|
||||
ExecState() { this = TExecState(incoming, outgoing) }
|
||||
|
||||
DataFlow::Node getIncomingNode() { result = incoming }
|
||||
|
||||
DataFlow::Node getOutgoingNode() { result = outgoing }
|
||||
|
||||
/** Holds if this is a possible `ExecState` for `sink`. */
|
||||
predicate isFeasibleForSink(DataFlow::Node sink) {
|
||||
any(ExecStateConfiguration conf).hasFlow(outgoing, sink)
|
||||
}
|
||||
predicate isFeasibleForSink(DataFlow::Node sink) { ExecState::hasFlow(outgoing, sink) }
|
||||
|
||||
string toString() { result = "ExecState" }
|
||||
}
|
||||
|
||||
predicate isSinkImpl(DataFlow::Node sink, Expr command, string callChain) {
|
||||
@@ -85,7 +86,7 @@ predicate isSinkImpl(DataFlow::Node sink, Expr command, string callChain) {
|
||||
shellCommand(command, callChain)
|
||||
}
|
||||
|
||||
predicate isSanitizerImpl(DataFlow::Node node) {
|
||||
predicate isBarrierImpl(DataFlow::Node node) {
|
||||
node.asExpr().getUnspecifiedType() instanceof IntegralType
|
||||
or
|
||||
node.asExpr().getUnspecifiedType() instanceof FloatingPointType
|
||||
@@ -96,56 +97,57 @@ predicate isSanitizerImpl(DataFlow::Node node) {
|
||||
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
|
||||
* `ExecTaintConfiguration::isSink`.
|
||||
*/
|
||||
class ExecStateConfiguration extends TaintTracking2::Configuration {
|
||||
ExecStateConfiguration() { this = "ExecStateConfiguration" }
|
||||
module ExecStateConfiguration implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { any(ExecState state).getOutgoingNode() = source }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
any(ExecState state).getOutgoingNode() = source
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _, _) }
|
||||
predicate isBarrier(DataFlow::Node node) { isBarrierImpl(node) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { isSanitizerImpl(node) }
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||
module ExecState = TaintTracking::Make<ExecStateConfiguration>;
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
module ExecTaintConfiguration implements DataFlow::StateConfigSig {
|
||||
class FlowState = TState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof FlowSource and
|
||||
state instanceof ConcatState
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
any(ExecStateConfiguration conf).isSink(sink) and
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
ExecStateConfiguration::isSink(sink) and
|
||||
state.(ExecState).isFeasibleForSink(sink)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
state1 instanceof ConcatState and
|
||||
state2.(ExecState).getIncomingNode() = node1 and
|
||||
state2.(ExecState).getOutgoingNode() = node2
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { isSanitizerImpl(node) }
|
||||
predicate isBarrier(DataFlow::Node node) { isBarrierImpl(node) }
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
module ExecTaint = TaintTracking::MakeWithState<ExecTaintConfiguration>;
|
||||
|
||||
from
|
||||
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
|
||||
string taintCause, string callChain, DataFlow::Node concatResult, Expr command
|
||||
ExecTaint::PathNode sourceNode, ExecTaint::PathNode sinkNode, string taintCause, string callChain,
|
||||
DataFlow::Node concatResult, Expr command
|
||||
where
|
||||
conf.hasFlowPath(sourceNode, sinkNode) and
|
||||
ExecTaint::hasFlowPath(sourceNode, sinkNode) and
|
||||
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
|
||||
isSinkImpl(sinkNode.getNode(), command, callChain) and
|
||||
concatResult = sinkNode.getState().(ExecState).getOutgoingNode()
|
||||
|
||||
@@ -19,7 +19,7 @@ import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import TaintedAllocationSize::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `alloc` is an allocation, and `tainted` is a child of it that is a
|
||||
@@ -54,14 +54,12 @@ predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Va
|
||||
|
||||
predicate isFlowSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
class TaintedAllocationSizeConfiguration extends TaintTracking::Configuration {
|
||||
TaintedAllocationSizeConfiguration() { this = "TaintedAllocationSizeConfiguration" }
|
||||
module TaintedAllocationSizeConfiguration implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
|
||||
predicate isSink(DataFlow::Node sink) { allocSink(_, sink) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { allocSink(_, sink) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(Expr e | e = node.asExpr() |
|
||||
// There can be two separate reasons for `convertedExprMightOverflow` not holding:
|
||||
// 1. `e` really cannot overflow.
|
||||
@@ -97,12 +95,14 @@ class TaintedAllocationSizeConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedAllocationSize = TaintTracking::Make<TaintedAllocationSizeConfiguration>;
|
||||
|
||||
from
|
||||
Expr alloc, DataFlow::PathNode source, DataFlow::PathNode sink, string taintCause,
|
||||
TaintedAllocationSizeConfiguration conf
|
||||
Expr alloc, TaintedAllocationSize::PathNode source, TaintedAllocationSize::PathNode sink,
|
||||
string taintCause
|
||||
where
|
||||
isFlowSource(source.getNode(), taintCause) and
|
||||
conf.hasFlowPath(source, sink) and
|
||||
TaintedAllocationSize::hasFlowPath(source, sink) and
|
||||
allocSink(alloc, sink.getNode())
|
||||
select alloc, source, sink, "This allocation size is derived from $@ and might overflow.",
|
||||
source.getNode(), "user input (" + taintCause + ")"
|
||||
|
||||
Reference in New Issue
Block a user