Skip to content

Commit 83f807f

Browse files
committed
C++: Interprocedural indirection taint tracking
As a temporary workaround in the `DefaultTaintTracking` library, we funnel flow across calls by conflating pointer and object both at the caller and the callee. The three cases in `adjustedSink` were deleted because they are now covered by the one case for `ReadSideEffectInstruction` in `instructionTaintStep`. When enabling `DefaultTaintTracking`, this commit on top of #2736 has the effect effect of recovering two lost results: --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected @@ -1,2 +1,4 @@ | overflowdestination.cpp:30:2:30:8 | call to strncpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. | | overflowdestination.cpp:46:2:46:7 | call to memcpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. | +| overflowdestination.cpp:53:2:53:7 | call to memcpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. | +| overflowdestination.cpp:64:2:64:7 | call to memcpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. | In the internal repo, we recover one lost result. Additionally, there are two queries that gain an extra source for an existing sink. I'll classify that as noise. The new results look like this: foo(argv); // this `argv` is a new source for the sink in `bar` bar(argv); // this `argv` is the existing source for the sink in `bar`
1 parent 72fddaf commit 83f807f

File tree

1 file changed

+28
-17
lines changed

1 file changed

+28
-17
lines changed

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,22 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
151151
// from `a`.
152152
i2.(PointerAddInstruction).getLeft() = i1
153153
or
154+
// Until we have from through indirections across calls, we'll take flow out
155+
// of the parameter and into its indirection.
156+
exists(IRFunction f, Parameter parameter |
157+
initializeParameter(f, parameter, i1) and
158+
initializeIndirection(f, parameter, i2)
159+
)
160+
or
161+
// Until we have flow through indirections across calls, we'll take flow out
162+
// of the indirection and into the argument.
163+
// When we get proper flow through indirections across calls, this code can be
164+
// moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class.
165+
exists(ReadSideEffectInstruction read |
166+
read.getAnOperand().(SideEffectOperand).getAnyDef() = i1 and
167+
read.getArgumentDef() = i2
168+
)
169+
or
154170
// Flow from argument to return value
155171
i2 =
156172
any(CallInstruction call |
@@ -176,6 +192,18 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
176192
)
177193
}
178194

195+
pragma[noinline]
196+
private predicate initializeIndirection(IRFunction f, Parameter p, InitializeIndirectionInstruction instr) {
197+
instr.getParameter() = p and
198+
instr.getEnclosingIRFunction() = f
199+
}
200+
201+
pragma[noinline]
202+
private predicate initializeParameter(IRFunction f, Parameter p, InitializeParameterInstruction instr) {
203+
instr.getParameter() = p and
204+
instr.getEnclosingIRFunction() = f
205+
}
206+
179207
/**
180208
* Get an instruction that goes into argument `argumentIndex` of `call`. This
181209
* can be either directly or through one pointer indirection.
@@ -273,23 +301,6 @@ private Element adjustedSink(DataFlow::Node sink) {
273301
// For compatibility, send flow into a `NotExpr` even if it's part of a
274302
// short-circuiting condition and thus might get skipped.
275303
result.(NotExpr).getOperand() = sink.asExpr()
276-
or
277-
// For compatibility, send flow from argument read side effects to their
278-
// corresponding argument expression
279-
exists(IndirectReadSideEffectInstruction read |
280-
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
281-
read.getArgumentDef().getUnconvertedResultExpression() = result
282-
)
283-
or
284-
exists(BufferReadSideEffectInstruction read |
285-
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
286-
read.getArgumentDef().getUnconvertedResultExpression() = result
287-
)
288-
or
289-
exists(SizedBufferReadSideEffectInstruction read |
290-
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
291-
read.getArgumentDef().getUnconvertedResultExpression() = result
292-
)
293304
}
294305

295306
predicate tainted(Expr source, Element tainted) {

0 commit comments

Comments
 (0)