@@ -192,14 +192,6 @@ string unsafePropName() {
192
192
result = "constructor"
193
193
}
194
194
195
- /**
196
- * A flow label representing an unsafe property name, or an object obtained
197
- * by using such a property in a dynamic read.
198
- */
199
- class UnsafePropLabel extends DataFlow:: FlowLabel {
200
- UnsafePropLabel ( ) { this = unsafePropName ( ) }
201
- }
202
-
203
195
/**
204
196
* Tracks data from property enumerations to dynamic property writes.
205
197
*
@@ -233,49 +225,50 @@ class UnsafePropLabel extends DataFlow::FlowLabel {
233
225
* a standalone configuration like in most path queries.
234
226
*/
235
227
module PropNameTrackingConfig implements DataFlow:: StateConfigSig {
236
- class FlowState = DataFlow:: FlowLabel ;
228
+ class FlowState extends string {
229
+ FlowState ( ) { this = unsafePropName ( ) }
230
+ }
237
231
238
- predicate isSource ( DataFlow:: Node node , DataFlow :: FlowLabel label ) {
239
- label instanceof UnsafePropLabel and
232
+ predicate isSource ( DataFlow:: Node node , FlowState state ) {
233
+ exists ( state ) and
240
234
(
241
235
isPollutedPropNameSource ( node )
242
236
or
243
237
node = any ( EnumeratedPropName prop ) .getASourceProp ( )
244
238
)
245
239
}
246
240
247
- predicate isSink ( DataFlow:: Node node , DataFlow :: FlowLabel label ) {
248
- label instanceof UnsafePropLabel and
241
+ predicate isSink ( DataFlow:: Node node , FlowState state ) {
242
+ exists ( state ) and
249
243
(
250
244
dynamicPropWrite ( node , _, _) or
251
245
dynamicPropWrite ( _, node , _) or
252
246
dynamicPropWrite ( _, _, node )
253
247
)
254
248
}
255
249
256
- predicate isBarrier ( DataFlow:: Node node , DataFlow :: FlowLabel label ) {
257
- node = DataFlow:: MakeLabeledBarrierGuard < BarrierGuard > :: getABarrierNode ( label )
250
+ predicate isBarrier ( DataFlow:: Node node , FlowState state ) {
251
+ node = DataFlow:: MakeStateBarrierGuard < FlowState , BarrierGuard > :: getABarrierNode ( state )
258
252
}
259
253
260
254
predicate isAdditionalFlowStep (
261
- DataFlow:: Node pred , DataFlow:: FlowLabel predlbl , DataFlow:: Node succ ,
262
- DataFlow:: FlowLabel succlbl
255
+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
263
256
) {
264
- predlbl instanceof UnsafePropLabel and
265
- succlbl = predlbl and
257
+ exists ( state1 ) and
258
+ state2 = state1 and
266
259
(
267
260
// Step through `p -> x[p]`
268
261
exists ( DataFlow:: PropRead read |
269
- pred = read .getPropertyNameExpr ( ) .flow ( ) and
262
+ node1 = read .getPropertyNameExpr ( ) .flow ( ) and
270
263
not read .( DynamicPropRead ) .hasDominatingAssignment ( ) and
271
- succ = read
264
+ node2 = read
272
265
)
273
266
or
274
267
// Step through `x -> x[p]`
275
268
exists ( DynamicPropRead read |
276
269
not read .hasDominatingAssignment ( ) and
277
- pred = read .getBase ( ) and
278
- succ = read
270
+ node1 = read .getBase ( ) and
271
+ node2 = read
279
272
)
280
273
)
281
274
}
@@ -286,6 +279,8 @@ module PropNameTrackingConfig implements DataFlow::StateConfigSig {
286
279
}
287
280
}
288
281
282
+ class FlowState = PropNameTrackingConfig:: FlowState ;
283
+
289
284
module PropNameTracking = DataFlow:: GlobalWithState< PropNameTrackingConfig > ;
290
285
291
286
/**
@@ -298,9 +293,9 @@ abstract class BarrierGuard extends DataFlow::Node {
298
293
predicate blocksExpr ( boolean outcome , Expr e ) { none ( ) }
299
294
300
295
/**
301
- * Holds if this node acts as a barrier for `label `, blocking further flow from `e` if `this` evaluates to `outcome`.
296
+ * Holds if this node acts as a barrier for `state `, blocking further flow from `e` if `this` evaluates to `outcome`.
302
297
*/
303
- predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel label ) { none ( ) }
298
+ predicate blocksExpr ( boolean outcome , Expr e , FlowState state ) { none ( ) }
304
299
}
305
300
306
301
/**
@@ -315,10 +310,10 @@ class DenyListEqualityGuard extends BarrierGuard, DataFlow::ValueNode {
315
310
propName = unsafePropName ( )
316
311
}
317
312
318
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel label ) {
313
+ override predicate blocksExpr ( boolean outcome , Expr e , FlowState state ) {
319
314
e = astNode .getAnOperand ( ) and
320
315
outcome = astNode .getPolarity ( ) .booleanNot ( ) and
321
- label = propName
316
+ state = propName
322
317
}
323
318
}
324
319
@@ -333,10 +328,9 @@ class AllowListEqualityGuard extends BarrierGuard, DataFlow::ValueNode {
333
328
astNode .getAnOperand ( ) instanceof Literal
334
329
}
335
330
336
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel label ) {
331
+ override predicate blocksExpr ( boolean outcome , Expr e ) {
337
332
e = astNode .getAnOperand ( ) and
338
- outcome = astNode .getPolarity ( ) and
339
- label instanceof UnsafePropLabel
333
+ outcome = astNode .getPolarity ( )
340
334
}
341
335
}
342
336
@@ -382,24 +376,24 @@ class InExprGuard extends BarrierGuard, DataFlow::ValueNode {
382
376
/**
383
377
* A sanitizer guard for `instanceof` expressions.
384
378
*
385
- * `Object.prototype instanceof X` is never true, so this blocks the `__proto__` label .
379
+ * `Object.prototype instanceof X` is never true, so this blocks the `__proto__` state .
386
380
*
387
381
* It is still possible to get to `Function.prototype` through `constructor.constructor.prototype`
388
- * so we do not block the `constructor` label .
382
+ * so we do not block the `constructor` state .
389
383
*/
390
384
class InstanceOfGuard extends BarrierGuard , DataFlow:: ValueNode {
391
385
override InstanceOfExpr astNode ;
392
386
393
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel label ) {
394
- e = astNode .getLeftOperand ( ) and outcome = true and label = "__proto__"
387
+ override predicate blocksExpr ( boolean outcome , Expr e , FlowState state ) {
388
+ e = astNode .getLeftOperand ( ) and outcome = true and state = "__proto__"
395
389
}
396
390
}
397
391
398
392
/**
399
393
* Sanitizer guard of form `typeof x === "object"` or `typeof x === "function"`.
400
394
*
401
- * The former blocks the `constructor` label as that payload must pass through a function,
402
- * and the latter blocks the `__proto__` label as that only passes through objects.
395
+ * The former blocks the `constructor` state as that payload must pass through a function,
396
+ * and the latter blocks the `__proto__` state as that only passes through objects.
403
397
*/
404
398
class TypeofGuard extends BarrierGuard , DataFlow:: ValueNode {
405
399
override EqualityTest astNode ;
@@ -408,15 +402,15 @@ class TypeofGuard extends BarrierGuard, DataFlow::ValueNode {
408
402
409
403
TypeofGuard ( ) { TaintTracking:: isTypeofGuard ( astNode , operand , tag ) }
410
404
411
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel label ) {
405
+ override predicate blocksExpr ( boolean outcome , Expr e , FlowState state ) {
412
406
e = operand and
413
407
outcome = astNode .getPolarity ( ) and
414
408
(
415
409
tag = "object" and
416
- label = "constructor"
410
+ state = "constructor"
417
411
or
418
412
tag = "function" and
419
- label = "__proto__"
413
+ state = "__proto__"
420
414
)
421
415
or
422
416
e = operand and
@@ -425,10 +419,10 @@ class TypeofGuard extends BarrierGuard, DataFlow::ValueNode {
425
419
// If something is not an object, sanitize object, as both must end
426
420
// in non-function prototype object.
427
421
tag = "object" and
428
- label instanceof UnsafePropLabel
422
+ exists ( state )
429
423
or
430
424
tag = "function" and
431
- label = "constructor"
425
+ state = "constructor"
432
426
)
433
427
}
434
428
}
@@ -437,19 +431,19 @@ class TypeofGuard extends BarrierGuard, DataFlow::ValueNode {
437
431
* A check of form `["__proto__"].includes(x)` or similar.
438
432
*/
439
433
class DenyListInclusionGuard extends BarrierGuard , InclusionTest {
440
- UnsafePropLabel label ;
434
+ string blockedProp ;
441
435
442
436
DenyListInclusionGuard ( ) {
443
437
exists ( DataFlow:: ArrayCreationNode array |
444
- array .getAnElement ( ) .getStringValue ( ) = label and
438
+ array .getAnElement ( ) .getStringValue ( ) = blockedProp and
445
439
array .flowsTo ( this .getContainerNode ( ) )
446
440
)
447
441
}
448
442
449
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel lbl ) {
443
+ override predicate blocksExpr ( boolean outcome , Expr e , FlowState state ) {
450
444
outcome = this .getPolarity ( ) .booleanNot ( ) and
451
445
e = this .getContainedNode ( ) .asExpr ( ) and
452
- label = lbl
446
+ blockedProp = state
453
447
}
454
448
}
455
449
@@ -464,9 +458,8 @@ class AllowListInclusionGuard extends BarrierGuard {
464
458
not this = any ( MembershipCandidate:: ObjectPropertyNameMembershipCandidate c ) .getTest ( ) // handled with more precision in `HasOwnPropertyGuard`
465
459
}
466
460
467
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow:: FlowLabel lbl ) {
468
- this .( TaintTracking:: AdditionalBarrierGuard ) .blocksExpr ( outcome , e ) and
469
- lbl instanceof UnsafePropLabel
461
+ override predicate blocksExpr ( boolean outcome , Expr e ) {
462
+ this .( TaintTracking:: AdditionalBarrierGuard ) .blocksExpr ( outcome , e )
470
463
}
471
464
}
472
465
@@ -482,10 +475,10 @@ class IsPlainObjectGuard extends BarrierGuard, DataFlow::CallNode {
482
475
)
483
476
}
484
477
485
- override predicate blocksExpr ( boolean outcome , Expr e , DataFlow :: FlowLabel lbl ) {
478
+ override predicate blocksExpr ( boolean outcome , Expr e , FlowState state ) {
486
479
e = this .getArgument ( 0 ) .asExpr ( ) and
487
480
outcome = true and
488
- lbl = "constructor"
481
+ state = "constructor"
489
482
}
490
483
}
491
484
0 commit comments