@@ -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,31 +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: This won't work in practice as long as all aliased memory is tracked
307- // together in a single virtual variable.
308- // TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
309- // is a pointer addition expression?
310- i2 =
311- any ( WriteSideEffectInstruction outNode |
312- exists ( CallInstruction call , int indexIn , int indexOut |
313- modelTaintToParameter ( call .getStaticCallTarget ( ) , indexIn , indexOut ) and
314- i1 = getACallArgumentOrIndirection ( call , indexIn ) and
315- outNode .getIndex ( ) = indexOut and
316- outNode .getPrimaryInstruction ( ) = call
317- )
318- )
319337}
320338
321339pragma [ noinline]
@@ -331,15 +349,25 @@ private InitializeParameterInstruction getInitializeParameter(IRFunction f, Para
331349}
332350
333351/**
334- * 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
335363 * can be either directly or through one pointer indirection.
336364 */
337- private Instruction getACallArgumentOrIndirection ( CallInstruction call , int argumentIndex ) {
338- result = call .getPositionalArgument ( argumentIndex )
365+ private Operand getACallArgumentOrIndirection ( CallInstruction call , int argumentIndex ) {
366+ result = call .getPositionalArgumentOperand ( argumentIndex )
339367 or
340368 exists ( ReadSideEffectInstruction readSE |
341369 // TODO: why are read side effect operands imprecise?
342- result = readSE .getSideEffectOperand ( ) . getAnyDef ( ) and
370+ result = readSE .getSideEffectOperand ( ) and
343371 readSE .getPrimaryInstruction ( ) = call and
344372 readSE .getIndex ( ) = argumentIndex
345373 )
@@ -353,7 +381,7 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
353381 f .( TaintFunction ) .hasTaintFlow ( modelIn , modelOut )
354382 ) and
355383 ( modelIn .isParameter ( parameterIn ) or modelIn .isParameterDeref ( parameterIn ) ) and
356- modelOut . isParameterDeref ( parameterOut )
384+ parameterOut = getWriteSideEffectIndex ( modelOut )
357385 )
358386}
359387
@@ -542,7 +570,7 @@ module TaintedWithPath {
542570 }
543571
544572 override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
545- instructionTaintStep ( n1 . asInstruction ( ) , n2 . asInstruction ( ) )
573+ commonTaintStep ( n1 , n2 )
546574 or
547575 exists ( TaintTrackingConfiguration cfg | cfg .taintThroughGlobals ( ) |
548576 writesVariable ( n1 .asInstruction ( ) , n2 .asVariable ( ) .( GlobalOrNamespaceVariable ) )
0 commit comments