@@ -5,6 +5,7 @@ private import semmle.javascript.dataflow.internal.Contents::Public
55private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
66private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
77private import semmle.javascript.dataflow.internal.BarrierGuards
8+ private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
89
910cached
1011predicate defaultAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
@@ -44,13 +45,51 @@ private class SanitizerGuardAdapter extends DataFlow::Node instanceof TaintTrack
4445 predicate blocksExpr ( boolean outcome , Expr e ) { super .sanitizes ( outcome , e ) }
4546}
4647
48+ bindingset [ node]
49+ pragma [ inline_late]
50+ private BasicBlock getBasicBlockFromSsa2 ( Ssa2:: Node node ) {
51+ result = node .( Ssa2:: ExprNode ) .getExpr ( ) .getBasicBlock ( )
52+ or
53+ node .( Ssa2:: SsaInputNode ) .isInputInto ( _, result )
54+ }
55+
56+ /**
57+ * Holds if `node` should act as a taint barrier, as it occurs after a variable has been checked to be falsy.
58+ *
59+ * For example:
60+ * ```js
61+ * if (!x) {
62+ * use(x); // <-- 'x' is a varAccessBarrier
63+ * }
64+ * ```
65+ *
66+ * This is particularly important for ensuring that query-specific barrier guards work when they
67+ * occur after a truthiness-check:
68+ * ```js
69+ * if (x && !isSafe(x)) {
70+ * throw new Error()
71+ * }
72+ * use(x); // both inputs to the phi-read for 'x' are blocked (one by varAccessBarrier, one by isSafe(x))
73+ * ```
74+ */
75+ private predicate varAccessBarrier ( DataFlow:: Node node ) {
76+ exists ( ConditionGuardNode guard , Ssa2:: ExprNode nodeFrom , Ssa2:: Node nodeTo |
77+ guard .getOutcome ( ) = false and
78+ guard .getTest ( ) .( VarAccess ) = nodeFrom .getExpr ( ) and
79+ Ssa2:: localFlowStep ( _, nodeFrom , nodeTo , true ) and
80+ guard .dominates ( getBasicBlockFromSsa2 ( nodeTo ) ) and
81+ node = getNodeFromSsa2 ( nodeTo )
82+ )
83+ }
84+
4785/**
4886 * Holds if `node` should be a sanitizer in all global taint flow configurations
4987 * but not in local taint.
5088 */
5189cached
5290predicate defaultTaintSanitizer ( DataFlow:: Node node ) {
5391 node instanceof DataFlow:: VarAccessBarrier or
92+ varAccessBarrier ( node ) or
5493 node = MakeBarrierGuard< SanitizerGuardAdapter > :: getABarrierNode ( )
5594}
5695
0 commit comments