@@ -318,7 +318,7 @@ module InvalidPointerToDerefBarrier {
318318 private module BarrierConfig implements DataFlow:: ConfigSig {
319319 predicate isSource ( DataFlow:: Node source ) {
320320 // The sources is the same as in the sources for `InvalidPointerToDerefConfig`.
321- invalidPointerToDerefSource ( _, source , _)
321+ invalidPointerToDerefSource ( _, _ , source , _)
322322 }
323323
324324 additional predicate isSink (
@@ -336,7 +336,7 @@ module InvalidPointerToDerefBarrier {
336336 private int getInvalidPointerToDerefSourceDelta ( DataFlow:: Node node ) {
337337 exists ( DataFlow:: Node source |
338338 flow ( source , node ) and
339- invalidPointerToDerefSource ( _, source , result )
339+ invalidPointerToDerefSource ( _, _ , source , result )
340340 )
341341 }
342342
@@ -373,7 +373,7 @@ module InvalidPointerToDerefBarrier {
373373 * by `AllocToInvalidPointerConfig` to a dereference of the pointer.
374374 */
375375module InvalidPointerToDerefConfig implements DataFlow:: ConfigSig {
376- predicate isSource ( DataFlow:: Node source ) { invalidPointerToDerefSource ( _, source , _) }
376+ predicate isSource ( DataFlow:: Node source ) { invalidPointerToDerefSource ( _, _ , source , _) }
377377
378378 pragma [ inline]
379379 predicate isSink ( DataFlow:: Node sink ) { isInvalidPointerDerefSink ( sink , _, _, _) }
@@ -388,23 +388,26 @@ module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
388388module InvalidPointerToDerefFlow = DataFlow:: Global< InvalidPointerToDerefConfig > ;
389389
390390/**
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`.
393394 *
394395 * For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
395396 * as `(p + size) + 1` and `source` is the node representing `(p + size) + 1`. In this
396397 * case `delta` is 1.
397398 */
398399predicate invalidPointerToDerefSource (
399- PointerArithmeticInstruction pai , DataFlow:: Node source , int delta
400+ AllocToInvalidPointerFlow:: PathNode1 source1 , PointerArithmeticInstruction pai ,
401+ DataFlow:: Node source , int delta
400402) {
401403 exists (
402404 AllocToInvalidPointerFlow:: PathNode1 p1 , AllocToInvalidPointerFlow:: PathNode2 p2 ,
403405 DataFlow:: Node sink1 , DataFlow:: Node sink2 , int delta0
404406 |
405407 pragma [ only_bind_out ] ( p1 .getNode ( ) ) = sink1 and
406408 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
408411 // Note that `delta` is not necessarily equal to `delta0`:
409412 // `delta0` is the constant offset added to the size of the allocation, and
410413 // delta is the constant difference between the pointer-arithmetic instruction
@@ -418,9 +421,7 @@ predicate invalidPointerToDerefSource(
418421
419422newtype TMergedPathNode =
420423 // 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
424425 // The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
425426 // This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
426427 // pointer, but we want to raise an alert at the dereference.
@@ -435,9 +436,7 @@ newtype TMergedPathNode =
435436class MergedPathNode extends TMergedPathNode {
436437 string toString ( ) { none ( ) }
437438
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 ) }
441440
442441 final Instruction asSinkNode ( ) { this = TPathNodeSink ( result ) }
443442
@@ -448,33 +447,18 @@ class MergedPathNode extends TMergedPathNode {
448447 }
449448}
450449
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 {
467451 override string toString ( ) {
468- exists ( InvalidPointerToDerefFlow :: PathNode p |
469- this = TPathNode3 ( p ) and
452+ exists ( FinalFlow :: PathNode p |
453+ this = TFinalPathNode ( p ) and
470454 result = p .toString ( )
471455 )
472456 }
473457
474458 override predicate hasLocationInfo (
475459 string filepath , int startline , int startcolumn , int endline , int endcolumn
476460 ) {
477- this .asPathNode3 ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
461+ this .asPathNode ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
478462 }
479463}
480464
@@ -495,65 +479,88 @@ class PathSinkNode extends MergedPathNode, TPathNodeSink {
495479 }
496480}
497481
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+
498535query 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 ( ) )
502537 or
503- node1 .asPathNode3 ( ) .getASuccessor ( ) = node2 .asPathNode3 ( )
504- or
505- joinOn2 ( node1 .asPathNode3 ( ) , node2 .asSinkNode ( ) , _, _)
538+ isInvalidPointerDerefSink ( node1 .asPathNode ( ) .getNode ( ) , node2 .asSinkNode ( ) , _, _)
506539}
507540
508541query 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 )
512543 or
513544 key = "semmle.label" and val = n .asSinkNode ( ) .toString ( )
514545}
515546
516547query predicate subpaths (
517548 MergedPathNode arg , MergedPathNode par , MergedPathNode ret , MergedPathNode out
518549) {
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 ( ) )
546552}
547553
548554predicate hasFlowPath (
549- MergedPathNode source1 , MergedPathNode sink , InvalidPointerToDerefFlow:: PathNode source3 ,
555+ MergedPathNode source , MergedPathNode sink , InvalidPointerToDerefFlow:: PathNode source3 ,
550556 PointerArithmeticInstruction pai , string operation , int delta
551557) {
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
557564 )
558565}
559566
@@ -564,12 +571,12 @@ where
564571 k =
565572 min ( int k2 , int k3 , InvalidPointerToDerefFlow:: PathNode source3 |
566573 hasFlowPath ( source , sink , source3 , pai , operation , k3 ) and
567- invalidPointerToDerefSource ( pai , source3 .getNode ( ) , k2 )
574+ invalidPointerToDerefSource ( _ , pai , source3 .getNode ( ) , k2 )
568575 |
569576 k2 + k3
570577 ) and
571578 offset = pai .getRight ( ) .getUnconvertedResultExpression ( ) and
572- n = source .asPathNode1 ( ) .getNode ( ) and
579+ n = source .asPathNode ( ) .getNode ( ) and
573580 if k = 0 then kstr = "" else kstr = " + " + k
574581select sink , source , sink ,
575582 "This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
0 commit comments