Skip to content

Commit d23c8fd

Browse files
authored
Merge pull request #19001 from MathiasVP/add-uncertain-api-for-dataflow
C++: Refine `Node.asDefinition`
2 parents 28d1152 + 6f4e9ed commit d23c8fd

File tree

7 files changed

+81
-9
lines changed

7 files changed

+81
-9
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Added `Node.asUncertainDefinition` and `Node.asCertainDefinition` to the `DataFlow::Node` class for querying whether a definition overwrites the entire destination buffer.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,79 @@ class Node extends TIRDataFlowNode {
313313
* `n.asExpr() instanceof IncrementOperation` since the result of evaluating
314314
* the expression `x++` is passed to `sink`.
315315
*/
316-
Expr asDefinition() {
317-
exists(StoreInstruction store |
316+
Expr asDefinition() { result = this.asDefinition(_) }
317+
318+
/**
319+
* Gets the definition associated with this node, if any.
320+
*
321+
* For example, consider the following example
322+
* ```cpp
323+
* int x = 42; // 1
324+
* x = 34; // 2
325+
* ++x; // 3
326+
* x++; // 4
327+
* x += 1; // 5
328+
* int y = x += 2; // 6
329+
* ```
330+
* - For (1) the result is `42`.
331+
* - For (2) the result is `x = 34`.
332+
* - For (3) the result is `++x`.
333+
* - For (4) the result is `x++`.
334+
* - For (5) the result is `x += 1`.
335+
* - For (6) there are two results:
336+
* - For the definition generated by `x += 2` the result is `x += 2`
337+
* - For the definition generated by `int y = ...` the result is
338+
* also `x += 2`.
339+
*
340+
* For assignments, `node.asDefinition(_)` and `node.asExpr()` will both exist
341+
* for the same dataflow node. However, for expression such as `x++` that
342+
* both write to `x` and read the current value of `x`, `node.asDefinition(_)`
343+
* will give the node corresponding to the value after the increment, and
344+
* `node.asExpr()` will give the node corresponding to the value before the
345+
* increment. For an example of this, consider the following:
346+
*
347+
* ```cpp
348+
* sink(x++);
349+
* ```
350+
* in the above program, there will not be flow from a node `n` such that
351+
* `n.asDefinition(_) instanceof IncrementOperation` to the argument of `sink`
352+
* since the value passed to `sink` is the value before to the increment.
353+
* However, there will be dataflow from a node `n` such that
354+
* `n.asExpr() instanceof IncrementOperation` since the result of evaluating
355+
* the expression `x++` is passed to `sink`.
356+
*
357+
* If `uncertain = false` then the definition is guaranteed to overwrite
358+
* the entire buffer pointed to by the destination address of the definition.
359+
* Otherwise, `uncertain = true`.
360+
*
361+
* For example, the write `int x; x = 42;` is guaranteed to overwrite all the
362+
* bytes allocated to `x`, while the assignment `int p[10]; p[3] = 42;` has
363+
* `uncertain = true` since the write will not overwrite the entire buffer
364+
* pointed to by `p`.
365+
*/
366+
Expr asDefinition(boolean uncertain) {
367+
exists(StoreInstruction store, Ssa::DefinitionExt def |
318368
store = this.asInstruction() and
319-
result = asDefinitionImpl(store)
369+
result = asDefinitionImpl(store) and
370+
Ssa::defToNode(this, def, _, _, _, _) and
371+
if def.isCertain() then uncertain = false else uncertain = true
320372
)
321373
}
322374

375+
/**
376+
* Gets the definition associated with this node, if this node is a certain definition.
377+
*
378+
* See `Node.asDefinition/1` for a description of certain and uncertain definitions.
379+
*/
380+
Expr asCertainDefinition() { result = this.asDefinition(false) }
381+
382+
/**
383+
* Gets the definition associated with this node, if this node is an uncertain definition.
384+
*
385+
* See `Node.asDefinition/1` for a description of certain and uncertain definitions.
386+
*/
387+
Expr asUncertainDefinition() { result = this.asDefinition(true) }
388+
323389
/**
324390
* Gets the indirect definition at a given indirection corresponding to this
325391
* node, if any.

cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module Config implements DataFlow::ConfigSig {
3737
predicate isBarrier(DataFlow::Node node) {
3838
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
3939
or
40-
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
40+
node.asCertainDefinition().getUnspecifiedType() instanceof ArithmeticType
4141
}
4242
}
4343

cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module Config implements DataFlow::ConfigSig {
3737
predicate isBarrier(DataFlow::Node node) {
3838
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
3939
or
40-
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
40+
node.asCertainDefinition().getUnspecifiedType() instanceof ArithmeticType
4141
}
4242
}
4343

cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ module Config implements DataFlow::ConfigSig {
4242
predicate isBarrier(DataFlow::Node node) {
4343
isSink(node) and isArithmeticNonCharType(node.asExpr().getUnspecifiedType())
4444
or
45-
isArithmeticNonCharType(node.asInstruction().(StoreInstruction).getResultType())
45+
isArithmeticNonCharType(node.asCertainDefinition().getUnspecifiedType())
4646
}
4747
}
4848

cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ private module Config implements DataFlow::ConfigSig {
3737
predicate isBarrier(DataFlow::Node node) {
3838
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
3939
or
40-
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
40+
node.asCertainDefinition().getUnspecifiedType() instanceof ArithmeticType
4141
or
4242
mayAddNullTerminator(_, node.asIndirectExpr())
4343
}

cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@ module Config implements DataFlow::ConfigSig {
7575
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
7676

7777
predicate isBarrier(DataFlow::Node node) {
78-
exists(StoreInstruction store | store = node.asInstruction() |
78+
exists(StoreInstruction store, Expr e |
79+
store = node.asInstruction() and e = node.asCertainDefinition()
80+
|
7981
// Block flow to "likely small expressions"
80-
bounded(store.getSourceValue().getUnconvertedResultExpression())
82+
bounded(e)
8183
or
8284
// Block flow to "small types"
8385
store.getResultType().getUnspecifiedType().(IntegralType).getSize() <= 1

0 commit comments

Comments
 (0)