Skip to content

Commit b5bf1c5

Browse files
authored
Merge pull request #21404 from hvitved/dataflow/no-enclosing-stack-flow-feature
Data flow: Add `FeatureEscapesSourceCallContext(OrEqualSourceSinkCallContext)` flow feature
2 parents f389832 + db491fc commit b5bf1c5

File tree

7 files changed

+201
-115
lines changed

7 files changed

+201
-115
lines changed

rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ module AccessAfterLifetimeConfig implements DataFlow::ConfigSig {
5050
result = [target.getLocation(), source.getLocation()]
5151
)
5252
}
53+
54+
DataFlow::FlowFeature getAFeature() {
55+
result instanceof DataFlow::FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext
56+
}
5357
}
5458

5559
module AccessAfterLifetimeFlow = TaintTracking::Global<AccessAfterLifetimeConfig>;
@@ -64,53 +68,22 @@ predicate sinkBlock(Sink s, BlockExpr be) {
6468
be = s.asExpr().getEnclosingBlock()
6569
}
6670

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-
10771
from
10872
AccessAfterLifetimeFlow::PathNode sourceNode, AccessAfterLifetimeFlow::PathNode sinkNode,
109-
Variable target
73+
Source source, Sink sink, Variable target
11074
where
11175
// flow from a pointer or reference to the dereference
11276
AccessAfterLifetimeFlow::flowPath(sourceNode, sinkNode) and
113-
// check that the dereference is outside the lifetime of the target
114-
dereferenceAfterLifetime(sourceNode.getNode(), sinkNode.getNode(), target)
77+
source = sourceNode.getNode() and
78+
sink = sinkNode.getNode() and
79+
sourceValueScope(source, target, _) and
80+
// check that the dereference is outside the lifetime of the target, when the source
81+
// and the sink are in the same callable
82+
// (`FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext` handles the case when
83+
// they are not)
84+
not exists(BlockExpr be |
85+
sourceBlock(source, target, be) and
86+
sinkBlock(sink, be)
87+
)
11588
select sinkNode.getNode(), sourceNode, sinkNode,
11689
"Access of a pointer to $@ after its lifetime has ended.", target, target.toString()

rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| lifetime.rs:76:4:76:5 | p2 | lifetime.rs:27:9:27:22 | &mut my_local2 | lifetime.rs:76:4:76:5 | p2 | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:25:10:25:18 | my_local2 | my_local2 |
1010
| lifetime.rs:77:4:77:5 | p4 | lifetime.rs:39:9:39:26 | &raw mut my_local4 | lifetime.rs:77:4:77:5 | p4 | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:37:10:37:18 | my_local4 | my_local4 |
1111
| lifetime.rs:172:13:172:15 | ptr | lifetime.rs:187:12:187:21 | &my_local1 | lifetime.rs:172:13:172:15 | ptr | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:186:6:186:14 | my_local1 | my_local1 |
12+
| lifetime.rs:180:13:180:15 | ptr | lifetime.rs:187:12:187:21 | &my_local1 | lifetime.rs:180:13:180:15 | ptr | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:186:6:186:14 | my_local1 | my_local1 |
1213
| lifetime.rs:255:14:255:17 | prev | lifetime.rs:251:10:251:19 | &my_local2 | lifetime.rs:255:14:255:17 | prev | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:242:7:242:15 | my_local2 | my_local2 |
1314
| lifetime.rs:310:31:310:32 | e1 | lifetime.rs:272:30:272:32 | &e1 | lifetime.rs:310:31:310:32 | e1 | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:271:6:271:7 | e1 | e1 |
1415
| lifetime.rs:314:23:314:24 | p2 | lifetime.rs:279:28:279:30 | &v2 | lifetime.rs:314:23:314:24 | p2 | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:278:6:278:7 | v2 | v2 |
@@ -55,39 +56,23 @@ edges
5556
| lifetime.rs:59:11:59:36 | get_local_field_dangling(...) | lifetime.rs:59:6:59:7 | p6 | provenance | |
5657
| lifetime.rs:63:3:63:4 | p7 | lifetime.rs:75:13:75:14 | p7 | provenance | |
5758
| lifetime.rs:63:8:63:27 | &raw const my_local7 | lifetime.rs:63:3:63:4 | p7 | provenance | |
58-
| lifetime.rs:91:17:91:30 | ...: ... | lifetime.rs:101:14:101:15 | p1 | provenance | |
59-
| lifetime.rs:91:33:91:44 | ...: ... | lifetime.rs:102:14:102:15 | p2 | provenance | |
60-
| lifetime.rs:91:33:91:44 | ...: ... | lifetime.rs:110:5:110:6 | p2 | provenance | |
6159
| lifetime.rs:94:2:94:3 | p3 | lifetime.rs:103:14:103:15 | p3 | provenance | |
6260
| lifetime.rs:94:7:94:16 | &my_local1 | lifetime.rs:94:2:94:3 | p3 | provenance | |
63-
| lifetime.rs:119:15:119:24 | &my_local3 | lifetime.rs:91:17:91:30 | ...: ... | provenance | |
64-
| lifetime.rs:119:27:119:44 | &mut my_local_mut4 | lifetime.rs:91:33:91:44 | ...: ... | provenance | |
65-
| lifetime.rs:161:17:161:31 | ...: ... | lifetime.rs:164:13:164:15 | ptr | provenance | |
6661
| lifetime.rs:169:17:169:31 | ...: ... | lifetime.rs:172:13:172:15 | ptr | provenance | |
6762
| lifetime.rs:177:17:177:31 | ...: ... | lifetime.rs:180:13:180:15 | ptr | provenance | |
68-
| lifetime.rs:187:6:187:8 | ptr | lifetime.rs:189:15:189:17 | ptr | provenance | |
69-
| lifetime.rs:187:6:187:8 | ptr | lifetime.rs:190:15:190:17 | ptr | provenance | |
7063
| lifetime.rs:187:6:187:8 | ptr | lifetime.rs:192:2:192:11 | return ptr | provenance | |
7164
| lifetime.rs:187:12:187:21 | &my_local1 | lifetime.rs:187:6:187:8 | ptr | provenance | |
72-
| lifetime.rs:189:15:189:17 | ptr | lifetime.rs:161:17:161:31 | ...: ... | provenance | |
73-
| lifetime.rs:190:15:190:17 | ptr | lifetime.rs:177:17:177:31 | ...: ... | provenance | |
7465
| lifetime.rs:192:2:192:11 | return ptr | lifetime.rs:196:12:196:36 | access_and_get_dangling(...) | provenance | |
7566
| lifetime.rs:196:6:196:8 | ptr | lifetime.rs:200:15:200:17 | ptr | provenance | |
7667
| lifetime.rs:196:6:196:8 | ptr | lifetime.rs:201:15:201:17 | ptr | provenance | |
7768
| lifetime.rs:196:12:196:36 | access_and_get_dangling(...) | lifetime.rs:196:6:196:8 | ptr | provenance | |
7869
| lifetime.rs:200:15:200:17 | ptr | lifetime.rs:169:17:169:31 | ...: ... | provenance | |
7970
| lifetime.rs:201:15:201:17 | ptr | lifetime.rs:177:17:177:31 | ...: ... | provenance | |
80-
| lifetime.rs:206:19:206:36 | ...: ... | lifetime.rs:216:16:216:21 | ptr_up | provenance | |
81-
| lifetime.rs:208:6:208:13 | ptr_ours | lifetime.rs:211:33:211:40 | ptr_ours | provenance | |
8271
| lifetime.rs:208:6:208:13 | ptr_ours | lifetime.rs:225:2:225:16 | return ptr_ours | provenance | |
8372
| lifetime.rs:208:17:208:29 | &my_local_rec | lifetime.rs:208:6:208:13 | ptr_ours | provenance | |
8473
| lifetime.rs:211:7:211:14 | ptr_down | lifetime.rs:218:18:218:25 | ptr_down | provenance | |
8574
| lifetime.rs:211:18:211:52 | access_ptr_rec(...) | lifetime.rs:211:7:211:14 | ptr_down | provenance | |
86-
| lifetime.rs:211:33:211:40 | ptr_ours | lifetime.rs:206:19:206:36 | ...: ... | provenance | |
8775
| lifetime.rs:225:2:225:16 | return ptr_ours | lifetime.rs:211:18:211:52 | access_ptr_rec(...) | provenance | |
88-
| lifetime.rs:230:6:230:14 | ptr_start | lifetime.rs:232:21:232:29 | ptr_start | provenance | |
89-
| lifetime.rs:230:18:230:31 | &my_local_rec2 | lifetime.rs:230:6:230:14 | ptr_start | provenance | |
90-
| lifetime.rs:232:21:232:29 | ptr_start | lifetime.rs:206:19:206:36 | ...: ... | provenance | |
9176
| lifetime.rs:239:6:239:13 | mut prev | lifetime.rs:247:15:247:18 | prev | provenance | |
9277
| lifetime.rs:239:6:239:13 | mut prev | lifetime.rs:255:14:255:17 | prev | provenance | |
9378
| lifetime.rs:239:34:239:43 | &my_local1 | lifetime.rs:239:6:239:13 | mut prev | provenance | |
@@ -215,43 +200,26 @@ nodes
215200
| lifetime.rs:75:13:75:14 | p7 | semmle.label | p7 |
216201
| lifetime.rs:76:4:76:5 | p2 | semmle.label | p2 |
217202
| lifetime.rs:77:4:77:5 | p4 | semmle.label | p4 |
218-
| lifetime.rs:91:17:91:30 | ...: ... | semmle.label | ...: ... |
219-
| lifetime.rs:91:33:91:44 | ...: ... | semmle.label | ...: ... |
220203
| lifetime.rs:94:2:94:3 | p3 | semmle.label | p3 |
221204
| lifetime.rs:94:7:94:16 | &my_local1 | semmle.label | &my_local1 |
222-
| lifetime.rs:101:14:101:15 | p1 | semmle.label | p1 |
223-
| lifetime.rs:102:14:102:15 | p2 | semmle.label | p2 |
224205
| lifetime.rs:103:14:103:15 | p3 | semmle.label | p3 |
225-
| lifetime.rs:110:5:110:6 | p2 | semmle.label | p2 |
226-
| lifetime.rs:119:15:119:24 | &my_local3 | semmle.label | &my_local3 |
227-
| lifetime.rs:119:27:119:44 | &mut my_local_mut4 | semmle.label | &mut my_local_mut4 |
228-
| lifetime.rs:161:17:161:31 | ...: ... | semmle.label | ...: ... |
229-
| lifetime.rs:164:13:164:15 | ptr | semmle.label | ptr |
230206
| lifetime.rs:169:17:169:31 | ...: ... | semmle.label | ...: ... |
231207
| lifetime.rs:172:13:172:15 | ptr | semmle.label | ptr |
232208
| lifetime.rs:177:17:177:31 | ...: ... | semmle.label | ...: ... |
233209
| lifetime.rs:180:13:180:15 | ptr | semmle.label | ptr |
234210
| lifetime.rs:187:6:187:8 | ptr | semmle.label | ptr |
235211
| lifetime.rs:187:12:187:21 | &my_local1 | semmle.label | &my_local1 |
236-
| lifetime.rs:189:15:189:17 | ptr | semmle.label | ptr |
237-
| lifetime.rs:190:15:190:17 | ptr | semmle.label | ptr |
238212
| lifetime.rs:192:2:192:11 | return ptr | semmle.label | return ptr |
239213
| lifetime.rs:196:6:196:8 | ptr | semmle.label | ptr |
240214
| lifetime.rs:196:12:196:36 | access_and_get_dangling(...) | semmle.label | access_and_get_dangling(...) |
241215
| lifetime.rs:200:15:200:17 | ptr | semmle.label | ptr |
242216
| lifetime.rs:201:15:201:17 | ptr | semmle.label | ptr |
243-
| lifetime.rs:206:19:206:36 | ...: ... | semmle.label | ...: ... |
244217
| lifetime.rs:208:6:208:13 | ptr_ours | semmle.label | ptr_ours |
245218
| lifetime.rs:208:17:208:29 | &my_local_rec | semmle.label | &my_local_rec |
246219
| lifetime.rs:211:7:211:14 | ptr_down | semmle.label | ptr_down |
247220
| lifetime.rs:211:18:211:52 | access_ptr_rec(...) | semmle.label | access_ptr_rec(...) |
248-
| lifetime.rs:211:33:211:40 | ptr_ours | semmle.label | ptr_ours |
249-
| lifetime.rs:216:16:216:21 | ptr_up | semmle.label | ptr_up |
250221
| lifetime.rs:218:18:218:25 | ptr_down | semmle.label | ptr_down |
251222
| lifetime.rs:225:2:225:16 | return ptr_ours | semmle.label | return ptr_ours |
252-
| lifetime.rs:230:6:230:14 | ptr_start | semmle.label | ptr_start |
253-
| lifetime.rs:230:18:230:31 | &my_local_rec2 | semmle.label | &my_local_rec2 |
254-
| lifetime.rs:232:21:232:29 | ptr_start | semmle.label | ptr_start |
255223
| lifetime.rs:239:6:239:13 | mut prev | semmle.label | mut prev |
256224
| lifetime.rs:239:34:239:43 | &my_local1 | semmle.label | &my_local1 |
257225
| lifetime.rs:247:15:247:18 | prev | semmle.label | prev |

rust/ql/test/query-tests/security/CWE-825/lifetime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ fn access_ptr_2(ptr: *const i64) {
177177
fn access_ptr_3(ptr: *const i64) {
178178
// called from contexts with `ptr` safe and dangling
179179
unsafe {
180-
let v3 = *ptr; // $ MISSING: Alert
180+
let v3 = *ptr; // $ Alert[rust/access-after-lifetime-ended]=local1
181181
println!(" v3 = {v3} (!)"); // corrupt in practice (in one context)
182182
}
183183
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Two new flow features `FeatureEscapesSourceCallContext` and `FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext` have been added. The former implies that the sink must be reached from the source by escaping the source call context, that is, flow must either return from the callable containing the source or use a jump-step before reaching the sink. The latter is the disjunction of the former and the existing `FeatureEqualSourceSinkCallContext` flow feature.

0 commit comments

Comments
 (0)