Skip to content

Commit d4c5877

Browse files
authored
Merge pull request #3 from MathiasVP/fix-exec-tainted
C++: Use refactored dataflow library in `cpp/command-line-injection`
2 parents 0addcfa + 907e629 commit d4c5877

File tree

2 files changed

+34
-36
lines changed

2 files changed

+34
-36
lines changed

cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import semmle.code.cpp.ir.dataflow.TaintTracking
2222
import semmle.code.cpp.ir.dataflow.TaintTracking2
2323
import semmle.code.cpp.security.FlowSources
2424
import semmle.code.cpp.models.implementations.Strcat
25-
import DataFlow::PathGraph
25+
import ExecTaint::PathGraph
2626

2727
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
2828
result =
@@ -67,74 +67,71 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
6767
)
6868
}
6969

70-
class ConcatState extends DataFlow::FlowState {
71-
ConcatState() { this = "ConcatState" }
70+
newtype TState =
71+
TConcatState() or
72+
TExecState(DataFlow::Node fst, DataFlow::Node snd) { interestingConcatenation(fst, snd) }
73+
74+
class ConcatState extends TConcatState {
75+
string toString() { result = "ConcatState" }
7276
}
7377

74-
class ExecState extends DataFlow::FlowState {
78+
class ExecState extends TExecState {
7579
DataFlow::Node fst;
7680
DataFlow::Node snd;
7781

78-
ExecState() {
79-
this =
80-
"ExecState (" + fst.getLocation() + " | " + fst + ", " + snd.getLocation() + " | " + snd + ")" and
81-
interestingConcatenation(pragma[only_bind_into](fst), pragma[only_bind_into](snd))
82-
}
82+
ExecState() { this = TExecState(fst, snd) }
8383

8484
DataFlow::Node getFstNode() { result = fst }
8585

8686
DataFlow::Node getSndNode() { result = snd }
8787

8888
/** Holds if this is a possible `ExecState` for `sink`. */
89-
predicate isFeasibleForSink(DataFlow::Node sink) {
90-
any(ExecStateConfiguration conf).hasFlow(snd, sink)
91-
}
89+
predicate isFeasibleForSink(DataFlow::Node sink) { ExecState::hasFlow(snd, sink) }
90+
91+
string toString() { result = "ExecState" }
9292
}
9393

9494
/**
9595
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
9696
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
9797
* `ExecTaintConfiguration::isSink`.
9898
*/
99-
class ExecStateConfiguration extends TaintTracking2::Configuration {
100-
ExecStateConfiguration() { this = "ExecStateConfiguration" }
101-
102-
override predicate isSource(DataFlow::Node source) {
99+
module ExecStateConfiguration implements DataFlow::ConfigSig {
100+
predicate isSource(DataFlow::Node source) {
103101
exists(ExecState state | state.getSndNode() = source)
104102
}
105103

106-
override predicate isSink(DataFlow::Node sink) {
107-
shellCommand(sinkAsArgumentIndirection(sink), _)
108-
}
104+
predicate isSink(DataFlow::Node sink) { shellCommand(sinkAsArgumentIndirection(sink), _) }
109105

110-
override predicate isSanitizerOut(DataFlow::Node node) {
111-
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
106+
predicate isBarrierOut(DataFlow::Node node) {
107+
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
112108
}
113109
}
114110

115-
class ExecTaintConfiguration extends TaintTracking::Configuration {
116-
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
111+
module ExecState = TaintTracking::Make<ExecStateConfiguration>;
117112

118-
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
113+
module ExecTaintConfiguration implements DataFlow::StateConfigSig {
114+
class FlowState = TState;
115+
116+
predicate isSource(DataFlow::Node source, FlowState state) {
119117
source instanceof FlowSource and
120118
state instanceof ConcatState
121119
}
122120

123-
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
124-
any(ExecStateConfiguration conf).isSink(sink) and
121+
predicate isSink(DataFlow::Node sink, FlowState state) {
122+
ExecStateConfiguration::isSink(sink) and
125123
state.(ExecState).isFeasibleForSink(sink)
126124
}
127125

128-
override predicate isAdditionalTaintStep(
129-
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
130-
DataFlow::FlowState state2
126+
predicate isAdditionalFlowStep(
127+
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
131128
) {
132129
state1 instanceof ConcatState and
133130
state2.(ExecState).getFstNode() = node1 and
134131
state2.(ExecState).getSndNode() = node2
135132
}
136133

137-
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
134+
predicate isBarrier(DataFlow::Node node, FlowState state) {
138135
(
139136
node.asInstruction().getResultType() instanceof IntegralType
140137
or
@@ -143,16 +140,18 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
143140
state instanceof ConcatState
144141
}
145142

146-
override predicate isSanitizerOut(DataFlow::Node node) {
143+
predicate isBarrierOut(DataFlow::Node node) {
147144
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
148145
}
149146
}
150147

148+
module ExecTaint = TaintTracking::MakeWithState<ExecTaintConfiguration>;
149+
151150
from
152-
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
153-
string taintCause, string callChain, DataFlow::Node concatResult
151+
ExecTaint::PathNode sourceNode, ExecTaint::PathNode sinkNode, string taintCause, string callChain,
152+
DataFlow::Node concatResult
154153
where
155-
conf.hasFlowPath(sourceNode, sinkNode) and
154+
ExecTaint::hasFlowPath(sourceNode, sinkNode) and
156155
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
157156
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain) and
158157
concatResult = sinkNode.getState().(ExecState).getSndNode()

cpp/ql/test/query-tests/Security/CWE/CWE-078/semmle/ExecTainted/ExecTainted.expected

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ edges
7171
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
7272
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
7373
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
74-
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
75-
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
7674
nodes
7775
| test.cpp:15:27:15:30 | argv | semmle.label | argv |
7876
| test.cpp:22:13:22:20 | sprintf output argument | semmle.label | sprintf output argument |
@@ -151,6 +149,7 @@ nodes
151149
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
152150
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
153151
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |
152+
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |
154153
subpaths
155154
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
156155
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |

0 commit comments

Comments
 (0)