@@ -216,43 +216,81 @@ private module NodeTracking {
216216 * invokes `cb`, passing `arg` as its `i`th argument. `arg` flows along a path summarized
217217 * by `summary`, while `cb` is only tracked locally.
218218 */
219- private predicate higherOrderCall (
219+ private predicate summarizedHigherOrderCall (
220220 DataFlow:: Node arg , DataFlow:: Node cb , int i , PathSummary summary
221221 ) {
222- exists ( Function f , DataFlow:: InvokeNode outer , DataFlow:: InvokeNode inner , int j ,
223- DataFlow:: Node innerArg , DataFlow:: ParameterNode cbParm , PathSummary oldSummary |
222+ exists (
223+ Function f , DataFlow:: InvokeNode outer , DataFlow:: InvokeNode inner , int j ,
224+ DataFlow:: Node innerArg , DataFlow:: ParameterNode cbParm , PathSummary oldSummary
225+ |
224226 reachableFromInput ( f , outer , arg , innerArg , oldSummary ) and
225227 argumentPassing ( outer , cb , f , cbParm ) and
226- innerArg = inner .getArgument ( j ) |
228+ innerArg = inner .getArgument ( j )
229+ |
227230 // direct higher-order call
228231 cbParm .flowsTo ( inner .getCalleeNode ( ) ) and
229232 i = j and
230233 summary = oldSummary
231234 or
232235 // indirect higher-order call
233- exists ( DataFlow:: Node cbArg , PathSummary newSummary |
236+ exists ( DataFlow:: Node cbArg , PathSummary newSummary |
234237 cbParm .flowsTo ( cbArg ) and
235- higherOrderCall ( innerArg , cbArg , i , newSummary ) and
238+ summarizedHigherOrderCall ( innerArg , cbArg , i , newSummary ) and
236239 summary = oldSummary .append ( PathSummary:: call ( ) ) .append ( newSummary )
237240 )
238241 )
239242 }
240243
244+ /**
245+ * Holds if `arg` is passed as the `i`th argument to `callback` through a callback invocation.
246+ *
247+ * This can be a summarized call, that is, `arg` and `callback` flow into a call,
248+ * `f(arg, callback)`, which performs the invocation.
249+ *
250+ * Alternatively, the callback can flow into a call `f(callback)` which itself provides the `arg`.
251+ * That is, `arg` refers to a value defined in `f` or one of its callees.
252+ */
253+ predicate higherOrderCall (
254+ DataFlow:: Node arg , DataFlow:: SourceNode callback , int i ,
255+ PathSummary summary
256+ ) {
257+ // Summarized call
258+ exists ( DataFlow:: Node cb |
259+ summarizedHigherOrderCall ( arg , cb , i , summary ) and
260+ callback .flowsTo ( cb )
261+ )
262+ or
263+ // Local invocation of a parameter
264+ isRelevant ( arg ) and
265+ exists ( DataFlow:: InvokeNode invoke |
266+ arg = invoke .getArgument ( i ) and
267+ invoke = callback .( DataFlow:: ParameterNode ) .getACall ( ) and
268+ summary = PathSummary:: call ( )
269+ )
270+ or
271+ // Forwarding of the callback parameter (but not the argument).
272+ // We use a return summary since flow moves back towards the call site.
273+ // This ensures that an argument that is only tainted in some contexts cannot flow
274+ // out to every callback.
275+ exists ( DataFlow:: Node cbArg , DataFlow:: SourceNode innerCb , PathSummary oldSummary |
276+ higherOrderCall ( arg , innerCb , i , oldSummary ) and
277+ callStep ( cbArg , innerCb ) and
278+ callback .flowsTo ( cbArg ) and
279+ summary = PathSummary:: return ( ) .append ( oldSummary )
280+ )
281+ }
282+
241283 /**
242284 * Holds if `pred` is passed as an argument to a function `f` which also takes a
243285 * callback parameter `cb` and then invokes `cb`, passing `pred` into parameter `succ`
244286 * of `cb`. `arg` flows along a path summarized by `summary`, while `cb` is only tracked
245287 * locally.
246288 */
247289 private predicate flowIntoHigherOrderCall (
248- DataFlow:: Node pred , DataFlow:: Node succ , PathSummary summary
290+ DataFlow:: Node pred , DataFlow:: Node succ , PathSummary summary
249291 ) {
250- exists (
251- DataFlow:: Node fArg , DataFlow:: FunctionNode cb ,
252- int i , PathSummary oldSummary
253- |
254- higherOrderCall ( pred , fArg , i , oldSummary ) and
255- cb = fArg .getALocalSource ( ) and
292+ exists ( DataFlow:: FunctionNode cb , int i , PathSummary oldSummary |
293+ higherOrderCall ( pred , cb , i , oldSummary ) and
256294 succ = cb .getParameter ( i ) and
257295 summary = oldSummary .append ( PathSummary:: call ( ) )
258296 )
0 commit comments