@@ -83,7 +83,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
8383 override predicate isSink ( DataFlow:: Node sink ) { exists ( adjustedSink ( sink ) ) }
8484
8585 override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
86- instructionTaintStep ( n1 . asInstruction ( ) , n2 . asInstruction ( ) )
86+ commonTaintStep ( n1 , n2 )
8787 }
8888
8989 override predicate isBarrier ( DataFlow:: Node node ) { nodeIsBarrier ( node ) }
@@ -101,7 +101,7 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
101101 }
102102
103103 override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
104- instructionTaintStep ( n1 . asInstruction ( ) , n2 . asInstruction ( ) )
104+ commonTaintStep ( n1 , n2 )
105105 or
106106 writesVariable ( n1 .asInstruction ( ) , n2 .asVariable ( ) .( GlobalOrNamespaceVariable ) )
107107 or
@@ -125,7 +125,7 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
125125 override predicate isSink ( DataFlow:: Node sink ) { exists ( adjustedSink ( sink ) ) }
126126
127127 override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
128- instructionTaintStep ( n1 . asInstruction ( ) , n2 . asInstruction ( ) )
128+ commonTaintStep ( n1 , n2 )
129129 or
130130 // Additional step for flow out of variables. There is no flow _into_
131131 // variables in this configuration, so this step only serves to take flow
@@ -215,19 +215,62 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) {
215215}
216216
217217cached
218- private predicate instructionTaintStep ( Instruction i1 , Instruction i2 ) {
218+ private predicate commonTaintStep ( DataFlow:: Node fromNode , DataFlow:: Node toNode ) {
219+ instructionToInstructionTaintStep ( fromNode .asInstruction ( ) , toNode .asInstruction ( ) )
220+ or
221+ operandToInstructionTaintStep ( fromNode .asOperand ( ) , toNode .asInstruction ( ) )
222+ or
223+ operandToOperandTaintStep ( fromNode .asOperand ( ) , toNode .asOperand ( ) )
224+ }
225+
226+ private predicate operandToOperandTaintStep ( Operand fromOperand , Operand toOperand ) {
227+ exists ( ReadSideEffectInstruction readInstr |
228+ fromOperand = readInstr .getArgumentOperand ( ) and
229+ toOperand = readInstr .getSideEffectOperand ( )
230+ )
231+ }
232+
233+ private predicate operandToInstructionTaintStep ( Operand fromOperand , Instruction toInstr ) {
219234 // Expressions computed from tainted data are also tainted
220- exists ( CallInstruction call , int argIndex | call = i2 |
235+ exists ( CallInstruction call , int argIndex | call = toInstr |
221236 isPureFunction ( call .getStaticCallTarget ( ) .getName ( ) ) and
222- i1 = getACallArgumentOrIndirection ( call , argIndex ) and
223- forall ( Instruction arg | arg = call .getAnArgument ( ) |
224- arg = getACallArgumentOrIndirection ( call , argIndex ) or predictableInstruction ( arg )
237+ fromOperand = getACallArgumentOrIndirection ( call , argIndex ) and
238+ forall ( Operand argOperand | argOperand = call .getAnArgumentOperand ( ) |
239+ argOperand = getACallArgumentOrIndirection ( call , argIndex ) or
240+ predictableInstruction ( argOperand .getAnyDef ( ) )
225241 ) and
226242 // flow through `strlen` tends to cause dubious results, if the length is
227243 // bounded.
228244 not call .getStaticCallTarget ( ) .getName ( ) = "strlen"
229245 )
230246 or
247+ // Flow from argument to return value
248+ toInstr =
249+ any ( CallInstruction call |
250+ exists ( int indexIn |
251+ modelTaintToReturnValue ( call .getStaticCallTarget ( ) , indexIn ) and
252+ fromOperand = getACallArgumentOrIndirection ( call , indexIn ) and
253+ not predictableOnlyFlow ( call .getStaticCallTarget ( ) .getName ( ) )
254+ )
255+ )
256+ or
257+ // Flow from input argument to output argument
258+ // TODO: This won't work in practice as long as all aliased memory is tracked
259+ // together in a single virtual variable.
260+ // TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
261+ // is a pointer addition expression?
262+ toInstr =
263+ any ( WriteSideEffectInstruction outInstr |
264+ exists ( CallInstruction call , int indexIn , int indexOut |
265+ modelTaintToParameter ( call .getStaticCallTarget ( ) , indexIn , indexOut ) and
266+ fromOperand = getACallArgumentOrIndirection ( call , indexIn ) and
267+ outInstr .getIndex ( ) = indexOut and
268+ outInstr .getPrimaryInstruction ( ) = call
269+ )
270+ )
271+ }
272+
273+ private predicate instructionToInstructionTaintStep ( Instruction i1 , Instruction i2 ) {
231274 // Flow through pointer dereference
232275 i2 .( LoadInstruction ) .getSourceAddress ( ) = i1
233276 or
@@ -291,29 +334,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
291334 read .getAnOperand ( ) .( SideEffectOperand ) .getAnyDef ( ) = i1 and
292335 read .getArgumentDef ( ) = i2
293336 )
294- or
295- // Flow from argument to return value
296- i2 =
297- any ( CallInstruction call |
298- exists ( int indexIn |
299- modelTaintToReturnValue ( call .getStaticCallTarget ( ) , indexIn ) and
300- i1 = getACallArgumentOrIndirection ( call , indexIn ) and
301- not predictableOnlyFlow ( call .getStaticCallTarget ( ) .getName ( ) )
302- )
303- )
304- or
305- // Flow from input argument to output argument
306- // TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
307- // is a pointer addition expression?
308- i2 =
309- any ( WriteSideEffectInstruction outNode |
310- exists ( CallInstruction call , int indexIn , int indexOut |
311- modelTaintToParameter ( call .getStaticCallTarget ( ) , indexIn , indexOut ) and
312- i1 = getACallArgumentOrIndirection ( call , indexIn ) and
313- outNode .getIndex ( ) = indexOut and
314- outNode .getPrimaryInstruction ( ) = call
315- )
316- )
317337}
318338
319339pragma [ noinline]
@@ -329,15 +349,25 @@ private InitializeParameterInstruction getInitializeParameter(IRFunction f, Para
329349}
330350
331351/**
332- * Get an instruction that goes into argument `argumentIndex` of `call`. This
352+ * Returns the index of the side effect instruction corresponding to the specified function output,
353+ * if one exists.
354+ */
355+ private int getWriteSideEffectIndex ( FunctionOutput output ) {
356+ output .isParameterDeref ( result )
357+ or
358+ output .isQualifierObject ( ) and result = - 1
359+ }
360+
361+ /**
362+ * Get an operand that goes into argument `argumentIndex` of `call`. This
333363 * can be either directly or through one pointer indirection.
334364 */
335- private Instruction getACallArgumentOrIndirection ( CallInstruction call , int argumentIndex ) {
336- result = call .getPositionalArgument ( argumentIndex )
365+ private Operand getACallArgumentOrIndirection ( CallInstruction call , int argumentIndex ) {
366+ result = call .getPositionalArgumentOperand ( argumentIndex )
337367 or
338368 exists ( ReadSideEffectInstruction readSE |
339369 // TODO: why are read side effect operands imprecise?
340- result = readSE .getSideEffectOperand ( ) . getAnyDef ( ) and
370+ result = readSE .getSideEffectOperand ( ) and
341371 readSE .getPrimaryInstruction ( ) = call and
342372 readSE .getIndex ( ) = argumentIndex
343373 )
@@ -351,7 +381,7 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
351381 f .( TaintFunction ) .hasTaintFlow ( modelIn , modelOut )
352382 ) and
353383 ( modelIn .isParameter ( parameterIn ) or modelIn .isParameterDeref ( parameterIn ) ) and
354- modelOut . isParameterDeref ( parameterOut )
384+ parameterOut = getWriteSideEffectIndex ( modelOut )
355385 )
356386}
357387
@@ -540,7 +570,7 @@ module TaintedWithPath {
540570 }
541571
542572 override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
543- instructionTaintStep ( n1 . asInstruction ( ) , n2 . asInstruction ( ) )
573+ commonTaintStep ( n1 , n2 )
544574 or
545575 exists ( TaintTrackingConfiguration cfg | cfg .taintThroughGlobals ( ) |
546576 writesVariable ( n1 .asInstruction ( ) , n2 .asVariable ( ) .( GlobalOrNamespaceVariable ) )
0 commit comments