@@ -64,14 +64,26 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
6464 or
6565 instrTo instanceof PointerArithmeticInstruction
6666 or
67- instrTo .( FieldAddressInstruction ) .getField ( ) .getDeclaringType ( ) instanceof Union
68- or
6967 // The `CopyInstruction` case is also present in non-taint data flow, but
7068 // that uses `getDef` rather than `getAnyDef`. For taint, we want flow
7169 // from a definition of `myStruct` to a `myStruct.myField` expression.
7270 instrTo instanceof CopyInstruction
7371 )
7472 or
73+ // Unary instructions tend to preserve enough information in practice that we
74+ // want taint to flow through.
75+ // The exception is `FieldAddressInstruction`. Together with the rules below for
76+ // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction`
77+ // could cause flow into one field to come out an unrelated field.
78+ // This would happen across function boundaries, where the IR would not be able to
79+ // match loads to stores.
80+ instrTo .( UnaryInstruction ) .getUnaryOperand ( ) = opFrom and
81+ (
82+ not instrTo instanceof FieldAddressInstruction
83+ or
84+ instrTo .( FieldAddressInstruction ) .getField ( ) .getDeclaringType ( ) instanceof Union
85+ )
86+ or
7587 instrTo .( LoadInstruction ) .getSourceAddressOperand ( ) = opFrom
7688 or
7789 // Flow from an element to an array or union that contains it.
@@ -83,6 +95,29 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
8395 t instanceof ArrayType
8496 )
8597 or
98+ // Until we have flow through indirections across calls, we'll take flow out
99+ // of the indirection and into the argument.
100+ // When we get proper flow through indirections across calls, this code can be
101+ // moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class.
102+ exists ( ReadSideEffectInstruction read |
103+ read .getSideEffectOperand ( ) = opFrom and
104+ read .getArgumentDef ( ) = instrTo
105+ )
106+ or
107+ // Until we have from through indirections across calls, we'll take flow out
108+ // of the parameter and into its indirection.
109+ // `InitializeIndirectionInstruction` only has a single operand: the address of the
110+ // value whose indirection we are initializing. When initializing an indirection of a parameter `p`,
111+ // the IR looks like this:
112+ // ```
113+ // m1 = InitializeParameter[p] : &r1
114+ // r2 = Load[p] : r2, m1
115+ // m3 = InitializeIndirection[p] : &r2
116+ // ```
117+ // So by having flow from `r2` to `m3` we're enabling flow from `m1` to `m3`. This relies on the
118+ // `LoadOperand`'s overlap being exact.
119+ instrTo .( InitializeIndirectionInstruction ) .getAnOperand ( ) = opFrom
120+ or
86121 modeledTaintStep ( opFrom , instrTo )
87122}
88123
0 commit comments