|
1 | 1 | private import semmle.code.cpp.ir.IR
|
2 | 2 | private import semmle.code.cpp.ir.dataflow.DataFlow
|
| 3 | +private import ModelUtil |
| 4 | +private import semmle.code.cpp.models.interfaces.DataFlow |
| 5 | +private import semmle.code.cpp.models.interfaces.SideEffect |
3 | 6 |
|
4 | 7 | /**
|
5 | 8 | * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
@@ -45,6 +48,25 @@ private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction no
|
45 | 48 | )
|
46 | 49 | or
|
47 | 50 | nodeTo.(LoadInstruction).getSourceAddress() = nodeFrom
|
| 51 | + or |
| 52 | + modeledInstructionTaintStep(nodeFrom, nodeTo) |
| 53 | + or |
| 54 | + // Flow through partial reads of arrays and unions |
| 55 | + nodeTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = nodeFrom and |
| 56 | + not nodeFrom.isResultConflated() and |
| 57 | + ( |
| 58 | + nodeFrom.getResultType() instanceof ArrayType or |
| 59 | + nodeFrom.getResultType() instanceof Union |
| 60 | + ) |
| 61 | + or |
| 62 | + // Flow from an element to an array or union that contains it. |
| 63 | + nodeTo.(ChiInstruction).getPartial() = nodeFrom and |
| 64 | + not nodeTo.isResultConflated() and |
| 65 | + exists(Type t | nodeTo.getResultLanguageType().hasType(t, false) | |
| 66 | + t instanceof Union |
| 67 | + or |
| 68 | + t instanceof ArrayType |
| 69 | + ) |
48 | 70 | }
|
49 | 71 |
|
50 | 72 | /**
|
@@ -82,3 +104,34 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
82 | 104 | * but not in local taint.
|
83 | 105 | */
|
84 | 106 | predicate defaultTaintBarrier(DataFlow::Node node) { none() }
|
| 107 | + |
| 108 | +/** |
| 109 | + * Holds if taint can flow from `instrIn` to `instrOut` through a call to a |
| 110 | + * modeled function. |
| 111 | + */ |
| 112 | +predicate modeledInstructionTaintStep(Instruction instrIn, Instruction instrOut) { |
| 113 | + exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut | |
| 114 | + instrIn = callInput(call, modelIn) and |
| 115 | + instrOut = callOutput(call, modelOut) and |
| 116 | + call.getStaticCallTarget() = func and |
| 117 | + func.hasTaintFlow(modelIn, modelOut) |
| 118 | + ) |
| 119 | + or |
| 120 | + // Taint flow from one argument to another and data flow from an argument to a |
| 121 | + // return value. This happens in functions like `strcat` and `memcpy`. We |
| 122 | + // could model this flow in two separate steps, but that would add reverse |
| 123 | + // flow from the write side-effect to the call instruction, which may not be |
| 124 | + // desirable. |
| 125 | + exists( |
| 126 | + CallInstruction call, Function func, FunctionInput modelIn, OutParameterDeref modelMidOut, |
| 127 | + int indexMid, InParameter modelMidIn, OutReturnValue modelOut |
| 128 | + | |
| 129 | + instrIn = callInput(call, modelIn) and |
| 130 | + instrOut = callOutput(call, modelOut) and |
| 131 | + call.getStaticCallTarget() = func and |
| 132 | + func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and |
| 133 | + func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and |
| 134 | + modelMidOut.isParameterDeref(indexMid) and |
| 135 | + modelMidIn.isParameter(indexMid) |
| 136 | + ) |
| 137 | +} |
0 commit comments