1515import rust
1616import codeql.rust.dataflow.DataFlow
1717import codeql.rust.dataflow.TaintTracking
18- import codeql.rust.security.AccessAfterLifetimeExtensions
18+ import codeql.rust.security.AccessAfterLifetimeExtensions:: AccessAfterLifetime
1919import AccessAfterLifetimeFlow:: PathGraph
2020
2121/**
@@ -24,14 +24,14 @@ import AccessAfterLifetimeFlow::PathGraph
2424 */
2525module AccessAfterLifetimeConfig implements DataFlow:: ConfigSig {
2626 predicate isSource ( DataFlow:: Node node ) {
27- node instanceof AccessAfterLifetime :: Source and
27+ node instanceof Source and
2828 // exclude cases with sources in macros, since these results are difficult to interpret
2929 not node .asExpr ( ) .isFromMacroExpansion ( ) and
30- AccessAfterLifetime :: sourceValueScope ( node , _, _)
30+ sourceValueScope ( node , _, _)
3131 }
3232
3333 predicate isSink ( DataFlow:: Node node ) {
34- node instanceof AccessAfterLifetime :: Sink and
34+ node instanceof Sink and
3535 // Exclude cases with sinks in macros, since these results are difficult to interpret
3636 not node .asExpr ( ) .isFromMacroExpansion ( ) and
3737 // TODO: Remove this condition if it can be done without negatively
@@ -40,27 +40,77 @@ module AccessAfterLifetimeConfig implements DataFlow::ConfigSig {
4040 exists ( node .asExpr ( ) )
4141 }
4242
43- predicate isBarrier ( DataFlow:: Node barrier ) { barrier instanceof AccessAfterLifetime :: Barrier }
43+ predicate isBarrier ( DataFlow:: Node barrier ) { barrier instanceof Barrier }
4444
4545 predicate observeDiffInformedIncrementalMode ( ) { any ( ) }
4646
4747 Location getASelectedSourceLocation ( DataFlow:: Node source ) {
4848 exists ( Variable target |
49- AccessAfterLifetime :: sourceValueScope ( source , target , _) and
49+ sourceValueScope ( source , target , _) and
5050 result = [ target .getLocation ( ) , source .getLocation ( ) ]
5151 )
5252 }
5353}
5454
5555module AccessAfterLifetimeFlow = TaintTracking:: Global< AccessAfterLifetimeConfig > ;
5656
57+ predicate sourceBlock ( Source s , Variable target , BlockExpr be ) {
58+ AccessAfterLifetimeFlow:: flow ( s , _) and
59+ sourceValueScope ( s , target , be .getEnclosingBlock * ( ) )
60+ }
61+
62+ predicate sinkBlock ( Sink s , BlockExpr be ) {
63+ AccessAfterLifetimeFlow:: flow ( _, s ) and
64+ be = s .asExpr ( ) .getEnclosingBlock ( )
65+ }
66+
67+ private predicate tcStep ( BlockExpr a , BlockExpr b ) {
68+ // propagate through function calls
69+ exists ( Call call |
70+ a = call .getEnclosingBlock ( ) and
71+ call .getARuntimeTarget ( ) = b .getEnclosingCallable ( )
72+ )
73+ }
74+
75+ private predicate isTcSource ( BlockExpr be ) { sourceBlock ( _, _, be ) }
76+
77+ private predicate isTcSink ( BlockExpr be ) { sinkBlock ( _, be ) }
78+
79+ /**
80+ * Holds if block `a` contains block `b`, in the sense that a stack allocated variable in
81+ * `a` may still be on the stack during execution of `b`. This is interprocedural,
82+ * but is an overapproximation that doesn't accurately track call contexts
83+ * (for example if `f` and `g` both call `b`, then depending on the
84+ * caller a variable in `f` or `g` may or may-not be on the stack during `b`).
85+ */
86+ private predicate mayEncloseOnStack ( BlockExpr a , BlockExpr b ) =
87+ doublyBoundedFastTC( tcStep / 2 , isTcSource / 1 , isTcSink / 1 ) ( a , b )
88+
89+ /**
90+ * Holds if the pair `(source, sink)`, that represents a flow from a
91+ * pointer or reference to a dereference, has its dereference outside the
92+ * lifetime of the target variable `target`.
93+ */
94+ predicate dereferenceAfterLifetime ( Source source , Sink sink , Variable target ) {
95+ AccessAfterLifetimeFlow:: flow ( source , sink ) and
96+ sourceValueScope ( source , target , _) and
97+ not exists ( BlockExpr beSource , BlockExpr beSink |
98+ sourceBlock ( source , target , beSource ) and
99+ sinkBlock ( sink , beSink )
100+ |
101+ beSource = beSink
102+ or
103+ mayEncloseOnStack ( beSource , beSink )
104+ )
105+ }
106+
57107from
58108 AccessAfterLifetimeFlow:: PathNode sourceNode , AccessAfterLifetimeFlow:: PathNode sinkNode ,
59109 Variable target
60110where
61111 // flow from a pointer or reference to the dereference
62112 AccessAfterLifetimeFlow:: flowPath ( sourceNode , sinkNode ) and
63113 // check that the dereference is outside the lifetime of the target
64- AccessAfterLifetime :: dereferenceAfterLifetime ( sourceNode .getNode ( ) , sinkNode .getNode ( ) , target )
114+ dereferenceAfterLifetime ( sourceNode .getNode ( ) , sinkNode .getNode ( ) , target )
65115select sinkNode .getNode ( ) , sourceNode , sinkNode ,
66116 "Access of a pointer to $@ after its lifetime has ended." , target , target .toString ( )
0 commit comments