Skip to content

Commit 218a3cf

Browse files
committed
C++: Remove field conflation
1 parent e983919 commit 218a3cf

File tree

2 files changed

+42
-23
lines changed

2 files changed

+42
-23
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cpp
22
import semmle.code.cpp.security.Security
33
private import semmle.code.cpp.ir.dataflow.DataFlow
4+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
45
private import semmle.code.cpp.ir.dataflow.DataFlow2
56
private import semmle.code.cpp.ir.dataflow.DataFlow3
67
private import semmle.code.cpp.ir.IR
@@ -228,6 +229,7 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
228229
// Flow from an element to an array or union that contains it.
229230
i2.(ChiInstruction).getPartial() = i1 and
230231
not i2.isResultConflated() and
232+
not exists(PartialDefinitionNode n | n.asInstruction() = i2) and
231233
exists(Type t | i2.getResultLanguageType().hasType(t, false) |
232234
t instanceof Union
233235
or

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

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ abstract class PostUpdateNode extends InstructionNode {
239239
}
240240

241241
/**
242+
* INTERNAL: do not use.
243+
*
242244
* The base class for nodes that perform "partial definitions".
243245
*
244246
* In contrast to a normal "definition", which provides a new value for
@@ -251,7 +253,7 @@ abstract class PostUpdateNode extends InstructionNode {
251253
* setY(&x); // a partial definition of the object `x`.
252254
* ```
253255
*/
254-
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
256+
abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
255257

256258
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
257259
override ChiInstruction instr;
@@ -270,6 +272,17 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
270272
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
271273
}
272274

275+
private class FieldStoreWriteSideEffectNode extends PartialDefinitionNode {
276+
override ChiInstruction instr;
277+
278+
FieldStoreWriteSideEffectNode() {
279+
not instr.isResultConflated() and
280+
exists(WriteSideEffectInstruction sideEffect | instr.getPartial() = sideEffect)
281+
}
282+
283+
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
284+
}
285+
273286
/**
274287
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
275288
* For instance, an update to a field of a struct containing only one field. For these cases we
@@ -421,6 +434,32 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
421434
*/
422435
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
423436
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
437+
or
438+
// The next two rules allow flow from partial definitions in setters to succeeding loads in the caller.
439+
// First, we add flow from write side-effects to non-conflated chi instructions through their
440+
// partial operands. Consider the following example:
441+
// ```
442+
// void setX(Point* p, int new_x) {
443+
// p->x = new_x;
444+
// }
445+
// ...
446+
// setX(&p, taint());
447+
// ```
448+
// Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to
449+
// `setX`, which will be melded into `p` through a chi instruction.
450+
nodeTo instanceof FieldStoreWriteSideEffectNode and
451+
exists(ChiInstruction chi | chi = nodeTo.asInstruction() |
452+
chi.getPartialOperand().getDef() = nodeFrom.asInstruction().(WriteSideEffectInstruction) and
453+
not chi.isResultConflated()
454+
)
455+
or
456+
// Next, we add flow from non-conflated chi instructions to loads (even when they are not precise).
457+
// This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above.
458+
nodeFrom instanceof FieldStoreWriteSideEffectNode and
459+
exists(ChiInstruction chi | chi = nodeFrom.asInstruction() |
460+
not chi.isResultConflated() and
461+
nodeTo.asInstruction().(LoadInstruction).getSourceValueOperand().getAnyDef() = chi
462+
)
424463
}
425464

426465
pragma[noinline]
@@ -458,28 +497,6 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
458497
// for now.
459498
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
460499
or
461-
// The next two rules allow flow from partial definitions in setters to succeeding loads in the caller.
462-
// First, we add flow from write side-effects to non-conflated chi instructions through their
463-
// partial operands. Consider the following example:
464-
// ```
465-
// void setX(Point* p, int new_x) {
466-
// p->x = new_x;
467-
// }
468-
// ...
469-
// setX(&p, taint());
470-
// ```
471-
// Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to
472-
// `setX`, which will be melded into `p` through a chi instruction.
473-
iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and
474-
not iTo.isResultConflated()
475-
or
476-
// Next, we add flow from non-conflated chi instructions to loads (even when they are not precise).
477-
// This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above.
478-
exists(ChiInstruction chi | iFrom = chi |
479-
not chi.isResultConflated() and
480-
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi
481-
)
482-
or
483500
// Flow from stores to structs with a single field to a load of that field.
484501
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and
485502
exists(int size, Type type |

0 commit comments

Comments
 (0)