@@ -318,7 +318,7 @@ module InvalidPointerToDerefBarrier {
318
318
private module BarrierConfig implements DataFlow:: ConfigSig {
319
319
predicate isSource ( DataFlow:: Node source ) {
320
320
// The sources is the same as in the sources for `InvalidPointerToDerefConfig`.
321
- invalidPointerToDerefSource ( _, source , _)
321
+ invalidPointerToDerefSource ( _, _ , source , _)
322
322
}
323
323
324
324
additional predicate isSink (
@@ -336,7 +336,7 @@ module InvalidPointerToDerefBarrier {
336
336
private int getInvalidPointerToDerefSourceDelta ( DataFlow:: Node node ) {
337
337
exists ( DataFlow:: Node source |
338
338
flow ( source , node ) and
339
- invalidPointerToDerefSource ( _, source , result )
339
+ invalidPointerToDerefSource ( _, _ , source , result )
340
340
)
341
341
}
342
342
@@ -373,7 +373,7 @@ module InvalidPointerToDerefBarrier {
373
373
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
374
374
*/
375
375
module InvalidPointerToDerefConfig implements DataFlow:: ConfigSig {
376
- predicate isSource ( DataFlow:: Node source ) { invalidPointerToDerefSource ( _, source , _) }
376
+ predicate isSource ( DataFlow:: Node source ) { invalidPointerToDerefSource ( _, _ , source , _) }
377
377
378
378
pragma [ inline]
379
379
predicate isSink ( DataFlow:: Node sink ) { isInvalidPointerDerefSink ( sink , _, _, _) }
@@ -388,23 +388,26 @@ module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
388
388
module InvalidPointerToDerefFlow = DataFlow:: Global< InvalidPointerToDerefConfig > ;
389
389
390
390
/**
391
- * Holds if `pai` is a pointer-arithmetic operation and `source` is a dataflow node with a
392
- * pointer-value that is non-strictly upper bounded by `pai + delta`.
391
+ * Holds if `source1` is dataflow node that represents an allocation that flows to the
392
+ * left-hand side of the pointer-arithmetic `pai`, and `source` is a dataflow node with
393
+ * a pointer-value that is non-strictly upper bounded by `pai + delta`.
393
394
*
394
395
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
395
396
* as `(p + size) + 1` and `source` is the node representing `(p + size) + 1`. In this
396
397
* case `delta` is 1.
397
398
*/
398
399
predicate invalidPointerToDerefSource (
399
- PointerArithmeticInstruction pai , DataFlow:: Node source , int delta
400
+ AllocToInvalidPointerFlow:: PathNode1 source1 , PointerArithmeticInstruction pai ,
401
+ DataFlow:: Node source , int delta
400
402
) {
401
403
exists (
402
404
AllocToInvalidPointerFlow:: PathNode1 p1 , AllocToInvalidPointerFlow:: PathNode2 p2 ,
403
405
DataFlow:: Node sink1 , DataFlow:: Node sink2 , int delta0
404
406
|
405
407
pragma [ only_bind_out ] ( p1 .getNode ( ) ) = sink1 and
406
408
pragma [ only_bind_out ] ( p2 .getNode ( ) ) = sink2 and
407
- AllocToInvalidPointerFlow:: flowPath ( _, _, pragma [ only_bind_into ] ( p1 ) , pragma [ only_bind_into ] ( p2 ) ) and
409
+ AllocToInvalidPointerFlow:: flowPath ( source1 , _, pragma [ only_bind_into ] ( p1 ) ,
410
+ pragma [ only_bind_into ] ( p2 ) ) and
408
411
// Note that `delta` is not necessarily equal to `delta0`:
409
412
// `delta0` is the constant offset added to the size of the allocation, and
410
413
// delta is the constant difference between the pointer-arithmetic instruction
@@ -418,9 +421,7 @@ predicate invalidPointerToDerefSource(
418
421
419
422
newtype TMergedPathNode =
420
423
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
421
- TPathNode1 ( AllocToInvalidPointerFlow:: PathNode1 p ) or
422
- // The path nodes computed by `InvalidPointerToDerefConfig`
423
- TPathNode3 ( InvalidPointerToDerefFlow:: PathNode p ) or
424
+ TFinalPathNode ( FinalFlow:: PathNode p ) or
424
425
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
425
426
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
426
427
// pointer, but we want to raise an alert at the dereference.
@@ -435,9 +436,7 @@ newtype TMergedPathNode =
435
436
class MergedPathNode extends TMergedPathNode {
436
437
string toString ( ) { none ( ) }
437
438
438
- final AllocToInvalidPointerFlow:: PathNode1 asPathNode1 ( ) { this = TPathNode1 ( result ) }
439
-
440
- final InvalidPointerToDerefFlow:: PathNode asPathNode3 ( ) { this = TPathNode3 ( result ) }
439
+ final FinalFlow:: PathNode asPathNode ( ) { this = TFinalPathNode ( result ) }
441
440
442
441
final Instruction asSinkNode ( ) { this = TPathNodeSink ( result ) }
443
442
@@ -448,33 +447,18 @@ class MergedPathNode extends TMergedPathNode {
448
447
}
449
448
}
450
449
451
- class PathNode1 extends MergedPathNode , TPathNode1 {
452
- override string toString ( ) {
453
- exists ( AllocToInvalidPointerFlow:: PathNode1 p |
454
- this = TPathNode1 ( p ) and
455
- result = p .toString ( )
456
- )
457
- }
458
-
459
- override predicate hasLocationInfo (
460
- string filepath , int startline , int startcolumn , int endline , int endcolumn
461
- ) {
462
- this .asPathNode1 ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
463
- }
464
- }
465
-
466
- class PathNode3 extends MergedPathNode , TPathNode3 {
450
+ class FinalPathNode extends MergedPathNode , TFinalPathNode {
467
451
override string toString ( ) {
468
- exists ( InvalidPointerToDerefFlow :: PathNode p |
469
- this = TPathNode3 ( p ) and
452
+ exists ( FinalFlow :: PathNode p |
453
+ this = TFinalPathNode ( p ) and
470
454
result = p .toString ( )
471
455
)
472
456
}
473
457
474
458
override predicate hasLocationInfo (
475
459
string filepath , int startline , int startcolumn , int endline , int endcolumn
476
460
) {
477
- this .asPathNode3 ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
461
+ this .asPathNode ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
478
462
}
479
463
}
480
464
@@ -495,65 +479,88 @@ class PathSinkNode extends MergedPathNode, TPathNodeSink {
495
479
}
496
480
}
497
481
482
+ /**
483
+ * A configuration that represents the full dataflow path all the way from
484
+ * the allocation to the dereference. We need this final dataflow traversal
485
+ * to ensure that the transition from the sink in `AllocToInvalidPointerConfig`
486
+ * to the source in `InvalidPointerToDerefFlow` did not make us construct an
487
+ * infeasible path (which can happen since the transition from one configuration
488
+ * to the next does not preserve information about call contexts).
489
+ */
490
+ module FinalConfig implements DataFlow:: StateConfigSig {
491
+ newtype FlowState =
492
+ additional TInitial ( ) or
493
+ additional TPointerArith ( PointerArithmeticInstruction pai , int delta ) {
494
+ invalidPointerToDerefSource ( _, pai , _, delta )
495
+ }
496
+
497
+ predicate isSource ( DataFlow:: Node source , FlowState state ) {
498
+ state = TInitial ( ) and
499
+ exists ( AllocToInvalidPointerFlow:: PathNode1 p , DataFlow:: Node derefSource |
500
+ source = p .getNode ( ) and
501
+ invalidPointerToDerefSource ( p , _, derefSource , _) and
502
+ InvalidPointerToDerefFlow:: flow ( derefSource , _)
503
+ )
504
+ }
505
+
506
+ predicate isSink ( DataFlow:: Node sink , FlowState state ) {
507
+ exists ( DataFlow:: Node source , PointerArithmeticInstruction pai , int delta |
508
+ InvalidPointerToDerefFlow:: flow ( source , sink ) and
509
+ invalidPointerToDerefSource ( _, pai , source , delta ) and
510
+ state = TPointerArith ( pai , delta )
511
+ )
512
+ }
513
+
514
+ predicate isBarrier ( DataFlow:: Node n , FlowState state ) { none ( ) }
515
+
516
+ predicate isAdditionalFlowStep (
517
+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
518
+ ) {
519
+ exists (
520
+ PointerArithmeticInstruction pai , AllocToInvalidPointerFlow:: PathNode1 p1 ,
521
+ InvalidPointerToDerefFlow:: PathNode p2 , int delta
522
+ |
523
+ isSinkImpl ( pai , node1 , _, _) and
524
+ invalidPointerToDerefSource ( _, pai , node2 , delta ) and
525
+ node1 = p1 .getNode ( ) and
526
+ node2 = p2 .getNode ( ) and
527
+ state1 = TInitial ( ) and
528
+ state2 = TPointerArith ( pai , delta )
529
+ )
530
+ }
531
+ }
532
+
533
+ module FinalFlow = DataFlow:: GlobalWithState< FinalConfig > ;
534
+
498
535
query predicate edges ( MergedPathNode node1 , MergedPathNode node2 ) {
499
- node1 .asPathNode1 ( ) .getASuccessor ( ) = node2 .asPathNode1 ( )
500
- or
501
- joinOn1 ( _, node1 .asPathNode1 ( ) , node2 .asPathNode3 ( ) )
536
+ FinalFlow:: PathGraph:: edges ( node1 .asPathNode ( ) , node2 .asPathNode ( ) )
502
537
or
503
- node1 .asPathNode3 ( ) .getASuccessor ( ) = node2 .asPathNode3 ( )
504
- or
505
- joinOn2 ( node1 .asPathNode3 ( ) , node2 .asSinkNode ( ) , _, _)
538
+ isInvalidPointerDerefSink ( node1 .asPathNode ( ) .getNode ( ) , node2 .asSinkNode ( ) , _, _)
506
539
}
507
540
508
541
query predicate nodes ( MergedPathNode n , string key , string val ) {
509
- AllocToInvalidPointerFlow:: PathGraph1:: nodes ( n .asPathNode1 ( ) , key , val )
510
- or
511
- InvalidPointerToDerefFlow:: PathGraph:: nodes ( n .asPathNode3 ( ) , key , val )
542
+ FinalFlow:: PathGraph:: nodes ( n .asPathNode ( ) , key , val )
512
543
or
513
544
key = "semmle.label" and val = n .asSinkNode ( ) .toString ( )
514
545
}
515
546
516
547
query predicate subpaths (
517
548
MergedPathNode arg , MergedPathNode par , MergedPathNode ret , MergedPathNode out
518
549
) {
519
- AllocToInvalidPointerFlow:: PathGraph1:: subpaths ( arg .asPathNode1 ( ) , par .asPathNode1 ( ) ,
520
- ret .asPathNode1 ( ) , out .asPathNode1 ( ) )
521
- or
522
- InvalidPointerToDerefFlow:: PathGraph:: subpaths ( arg .asPathNode3 ( ) , par .asPathNode3 ( ) ,
523
- ret .asPathNode3 ( ) , out .asPathNode3 ( ) )
524
- }
525
-
526
- /**
527
- * Holds if `p1` is a sink of `AllocToInvalidPointerConfig` and `p2` is a source
528
- * of `InvalidPointerToDerefConfig`, and they are connected through `pai`.
529
- */
530
- predicate joinOn1 (
531
- PointerArithmeticInstruction pai , AllocToInvalidPointerFlow:: PathNode1 p1 ,
532
- InvalidPointerToDerefFlow:: PathNode p2
533
- ) {
534
- isSinkImpl ( pai , p1 .getNode ( ) , _, _) and
535
- invalidPointerToDerefSource ( pai , p2 .getNode ( ) , _)
536
- }
537
-
538
- /**
539
- * Holds if `p1` is a sink of `InvalidPointerToDerefConfig` and `i` is the instruction
540
- * that dereferences `p1`. The string `operation` describes whether the `i` is
541
- * a `StoreInstruction` or `LoadInstruction`.
542
- */
543
- pragma [ inline]
544
- predicate joinOn2 ( InvalidPointerToDerefFlow:: PathNode p1 , Instruction i , string operation , int delta ) {
545
- isInvalidPointerDerefSink ( p1 .getNode ( ) , i , operation , delta )
550
+ FinalFlow:: PathGraph:: subpaths ( arg .asPathNode ( ) , par .asPathNode ( ) , ret .asPathNode ( ) ,
551
+ out .asPathNode ( ) )
546
552
}
547
553
548
554
predicate hasFlowPath (
549
- MergedPathNode source1 , MergedPathNode sink , InvalidPointerToDerefFlow:: PathNode source3 ,
555
+ MergedPathNode source , MergedPathNode sink , InvalidPointerToDerefFlow:: PathNode source3 ,
550
556
PointerArithmeticInstruction pai , string operation , int delta
551
557
) {
552
- exists ( InvalidPointerToDerefFlow:: PathNode sink3 , AllocToInvalidPointerFlow:: PathNode1 sink1 |
553
- AllocToInvalidPointerFlow:: flowPath ( source1 .asPathNode1 ( ) , _, sink1 , _) and
554
- joinOn1 ( pai , sink1 , source3 ) and
555
- InvalidPointerToDerefFlow:: flowPath ( source3 , sink3 ) and
556
- joinOn2 ( sink3 , sink .asSinkNode ( ) , operation , delta )
558
+ exists ( FinalFlow:: PathNode sink3 , int delta0 , int delta1 |
559
+ FinalFlow:: flowPath ( source .asPathNode ( ) , sink3 ) and
560
+ invalidPointerToDerefSource ( _, pai , source3 .getNode ( ) , delta0 ) and
561
+ sink3 .getState ( ) = FinalConfig:: TPointerArith ( pai , delta0 ) and
562
+ isInvalidPointerDerefSink ( sink3 .getNode ( ) , sink .asSinkNode ( ) , operation , delta1 ) and
563
+ delta = delta0 + delta1
557
564
)
558
565
}
559
566
@@ -564,12 +571,12 @@ where
564
571
k =
565
572
min ( int k2 , int k3 , InvalidPointerToDerefFlow:: PathNode source3 |
566
573
hasFlowPath ( source , sink , source3 , pai , operation , k3 ) and
567
- invalidPointerToDerefSource ( pai , source3 .getNode ( ) , k2 )
574
+ invalidPointerToDerefSource ( _ , pai , source3 .getNode ( ) , k2 )
568
575
|
569
576
k2 + k3
570
577
) and
571
578
offset = pai .getRight ( ) .getUnconvertedResultExpression ( ) and
572
- n = source .asPathNode1 ( ) .getNode ( ) and
579
+ n = source .asPathNode ( ) .getNode ( ) and
573
580
if k = 0 then kstr = "" else kstr = " + " + k
574
581
select sink , source , sink ,
575
582
"This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
0 commit comments