Skip to content

Commit ccbfaa7

Browse files
committed
JS: explain return step more thoroughly
1 parent c48b529 commit ccbfaa7

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

javascript/ql/src/semmle/javascript/dataflow/Configuration.qll

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -689,10 +689,24 @@ private predicate summarizedHigherOrderCall(
689689
* Holds if `arg` is passed as the `i`th argument to `callback` through a callback invocation.
690690
*
691691
* This can be a summarized call, that is, `arg` and `callback` flow into a call,
692-
* `f(arg, callback)`, which performs the invocation.
692+
* `f(arg, callback)`, which performs the invocation.
693693
*
694694
* Alternatively, the callback can flow into a call `f(callback)` which itself provides the `arg`.
695695
* That is, `arg` refers to a value defined in `f` or one of its callees.
696+
*
697+
* In the latter case, the summary will consists of both a `return` and `call` step, for the following reasons:
698+
*
699+
* - Having `return` in the summary ensures that arguments passsed to `f` can't propagate back out along this edge.
700+
* This is, `arg` should be defined in `f` or one of its callees, since a context-dependent value (i.e. parameter)
701+
* should not propagate to every callback passed to `f`.
702+
* In reality, `arg` may refer to a parameter, but in that case, the `return` summary prevents the edge from ever
703+
* being used.
704+
*
705+
* - Having `call` in the summary ensures that values we propagate into the callback definition along this edge
706+
* can't propagate out to other callers of that function through a return statement.
707+
*
708+
* - The flow label mapping of the summary corresponds to the transformation from `arg` to the
709+
* invocation of the callback.
696710
*/
697711
predicate higherOrderCall(
698712
DataFlow::Node arg, DataFlow::SourceNode callback, int i, DataFlow::Configuration cfg,
@@ -713,13 +727,11 @@ predicate higherOrderCall(
713727
)
714728
or
715729
// Forwarding of the callback parameter (but not the argument).
716-
// We use a return summary since flow moves back towards the call site.
717-
// This ensures that an argument that is only tainted in some contexts cannot flow
718-
// out to every callback.
719730
exists(DataFlow::Node cbArg, DataFlow::SourceNode innerCb, PathSummary oldSummary |
720731
higherOrderCall(arg, innerCb, i, cfg, oldSummary) and
721732
callStep(cbArg, innerCb) and
722733
callback.flowsTo(cbArg) and
734+
// Prepend a 'return' summary to prevent context-dependent values (i.e. parameters) from using this edge.
723735
summary = PathSummary::return().append(oldSummary)
724736
)
725737
}

0 commit comments

Comments
 (0)