@@ -121,9 +121,17 @@ class AggregateES2015PromiseDefinition extends PromiseCreationCall {
121121}
122122
123123/**
124- * This module defines how exceptional data-flow propagates into and out a Promise.
124+ * This module defines how data-flow propagates into and out of a Promise.
125+ * The data-flow is based on pseudo-properties rather than tainting the Promise object (which is what `PromiseTaintStep` does).
125126 */
126- private module ExceptionalPromiseFlow {
127+ private module PromiseFlow {
128+ /**
129+ * Gets the pseudo-field used to describe resolved values in a promise.
130+ */
131+ string resolveField ( ) {
132+ result = "$PromiseResolveField$"
133+ }
134+
127135 /**
128136 * Gets the pseudo-field used to describe rejected values in a promise.
129137 */
@@ -134,7 +142,7 @@ private module ExceptionalPromiseFlow {
134142 /**
135143 * A flow step describing a promise definition.
136144 *
137- * The rejected value is written to a pseudo-field on the promise.
145+ * The resolved/ rejected value is written to a pseudo-field on the promise.
138146 */
139147 class PromiseDefitionStep extends DataFlow:: AdditionalFlowStep {
140148 PromiseDefinition promise ;
@@ -143,6 +151,10 @@ private module ExceptionalPromiseFlow {
143151 }
144152
145153 override predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
154+ prop = resolveField ( ) and
155+ pred = promise .getResolveParameter ( ) .getACall ( ) .getArgument ( 0 ) and
156+ succ = this
157+ or
146158 prop = rejectField ( ) and
147159 (
148160 pred = promise .getRejectParameter ( ) .getACall ( ) .getArgument ( 0 ) or
@@ -152,6 +164,23 @@ private module ExceptionalPromiseFlow {
152164 }
153165 }
154166
167+ /**
168+ * A flow step describing the a Promise.resolve (and similar) call.
169+ */
170+ class CreationStep extends DataFlow:: AdditionalFlowStep {
171+ PromiseCreationCall promise ;
172+ CreationStep ( ) {
173+ this = promise
174+ }
175+
176+ override predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
177+ prop = resolveField ( ) and
178+ pred = promise .getValue ( ) and
179+ succ = this
180+ }
181+ }
182+
183+
155184 /**
156185 * A load step loading the pseudo-field describing that the promise is rejected.
157186 * The rejected value is thrown as a exception.
@@ -165,6 +194,10 @@ private module ExceptionalPromiseFlow {
165194 }
166195
167196 override predicate load ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
197+ prop = resolveField ( ) and
198+ succ = this and
199+ pred = operand
200+ or
168201 prop = rejectField ( ) and
169202 succ = await .getExceptionTarget ( ) and
170203 pred = operand
@@ -180,6 +213,10 @@ private module ExceptionalPromiseFlow {
180213 }
181214
182215 override predicate load ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
216+ prop = resolveField ( ) and
217+ pred = getReceiver ( ) and
218+ succ = getCallback ( 0 ) .getParameter ( 0 )
219+ or
183220 prop = rejectField ( ) and
184221 pred = getReceiver ( ) and
185222 succ = getCallback ( 1 ) .getParameter ( 0 )
@@ -193,12 +230,16 @@ private module ExceptionalPromiseFlow {
193230 }
194231
195232 override predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
233+ prop = resolveField ( ) and
234+ pred = getCallback ( [ 0 ..1 ] ) .getAReturn ( ) and
235+ succ = this
236+ or
196237 prop = rejectField ( ) and
197238 pred = getCallback ( [ 0 ..1 ] ) .getExceptionalReturn ( ) and
198239 succ = this
199240 }
200241 }
201-
242+
202243 /**
203244 * A flow step describing the data-flow related to the `.catch` method of a promise.
204245 */
@@ -213,10 +254,20 @@ private module ExceptionalPromiseFlow {
213254 succ = getCallback ( 0 ) .getParameter ( 0 )
214255 }
215256
257+ override predicate copyProperty ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
258+ prop = resolveField ( ) and
259+ pred = getReceiver ( ) .getALocalSource ( ) and
260+ succ = this
261+ }
262+
216263 override predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
217264 prop = rejectField ( ) and
218265 pred = getCallback ( 0 ) .getExceptionalReturn ( ) and
219266 succ = this
267+ or
268+ prop = resolveField ( ) and
269+ pred = getCallback ( 0 ) .getAReturn ( ) and
270+ succ = this
220271 }
221272 }
222273
@@ -229,10 +280,17 @@ private module ExceptionalPromiseFlow {
229280 }
230281
231282 override predicate copyProperty ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
232- prop = rejectField ( ) and
283+ ( prop = resolveField ( ) or prop = rejectField ( ) ) and
233284 pred = getReceiver ( ) and
234285 succ = this
235286 }
287+
288+ // a similar thing can also happen if a rejected promise is returned.
289+ override predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
290+ prop = rejectField ( ) and
291+ pred = getCallback ( 0 ) .getExceptionalReturn ( ) and
292+ succ = this
293+ }
236294 }
237295}
238296
@@ -258,10 +316,14 @@ predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
258316 succ = thn
259317 )
260318 or
261- // from `p` to `p.catch(..)`
262319 exists ( DataFlow:: MethodCallNode catch | catch .getMethodName ( ) = "catch" |
320+ // from `p` to `p.catch(..)`
263321 pred = catch .getReceiver ( ) and
264322 succ = catch
323+ or
324+ // from `v` to `p.catch(x => return v)`
325+ pred = catch .getCallback ( 0 ) .getAReturn ( ) and
326+ succ = catch
265327 )
266328 or
267329 // from `p` to `p.finally(..)`
0 commit comments