Skip to content

Commit d94dc40

Browse files
committed
Rust: Derive source/sink/barrier MaD implementation models from trait models
1 parent 572ceaf commit d94dc40

15 files changed

Lines changed: 552 additions & 301 deletions

File tree

rust/ql/lib/codeql/rust/dataflow/FlowBarrier.qll

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ module FlowBarrier {
4444
Range() { any() }
4545

4646
override predicate isBarrier(
47-
string output, string kind, Impl::Public::Provenance provenance, string model
47+
string output, string kind, Impl::Public::Provenance provenance, boolean isExact, string model
4848
) {
49-
this.isBarrier(output, kind) and provenance = "manual" and model = ""
49+
this.isBarrier(output, kind) and provenance = "manual" and isExact = true and model = ""
5050
}
5151

5252
/**
@@ -67,9 +67,13 @@ module FlowBarrierGuard {
6767
Range() { any() }
6868

6969
override predicate isBarrierGuard(
70-
string input, string branch, string kind, Impl::Public::Provenance provenance, string model
70+
string input, string branch, string kind, Impl::Public::Provenance provenance,
71+
boolean isExact, string model
7172
) {
72-
this.isBarrierGuard(input, branch, kind) and provenance = "manual" and model = ""
73+
this.isBarrierGuard(input, branch, kind) and
74+
provenance = "manual" and
75+
isExact = true and
76+
model = ""
7377
}
7478

7579
/**

rust/ql/lib/codeql/rust/dataflow/FlowSink.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ module FlowSink {
3636
Range() { any() }
3737

3838
override predicate isSink(
39-
string input, string kind, Impl::Public::Provenance provenance, string model
39+
string input, string kind, Impl::Public::Provenance provenance, boolean isExact, string model
4040
) {
41-
this.isSink(input, kind) and provenance = "manual" and model = ""
41+
this.isSink(input, kind) and provenance = "manual" and isExact = true and model = ""
4242
}
4343

4444
/**

rust/ql/lib/codeql/rust/dataflow/FlowSource.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ module FlowSource {
4242
Range() { any() }
4343

4444
override predicate isSource(
45-
string output, string kind, Impl::Public::Provenance provenance, string model
45+
string output, string kind, Impl::Public::Provenance provenance, boolean isExact, string model
4646
) {
47-
this.isSource(output, kind) and provenance = "manual" and model = ""
47+
this.isSource(output, kind) and provenance = "manual" and isExact = true and model = ""
4848
}
4949

5050
/**

rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,12 @@ module Input implements InputSig<Location, RustDataFlow> {
4343
result.asSummarizedCallable() = c
4444
}
4545

46-
class SourceBase = Function;
47-
48-
class SinkBase = Function;
49-
5046
predicate neutralElement(
5147
Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact
5248
) {
53-
exists(string path |
54-
neutralModel(path, kind, provenance, _) and
55-
c.getCanonicalPath() = path and
56-
isExact = true
49+
exists(string path, Provenance orig |
50+
neutralModel(path, kind, orig, _) and
51+
interpretPath(path, c, orig, provenance, isExact)
5752
)
5853
}
5954

@@ -170,7 +165,7 @@ module Input2 implements Impl::Private::InputSig2 {
170165
}
171166

172167
SourceSinkReportingElement getASourceReportingElement(
173-
Input::SourceBase source, Impl::Private::SummaryComponent sc
168+
Input::SummarizedCallableBase source, Impl::Private::SummaryComponent sc
174169
) {
175170
exists(Call call | call.getResolvedTarget() = source |
176171
sc = Impl::Private::SummaryComponent::return(_) and
@@ -200,7 +195,7 @@ module Input2 implements Impl::Private::InputSig2 {
200195
}
201196

202197
SourceSinkReportingElement getASinkReportingElement(
203-
Input::SinkBase sink, Impl::Private::SummaryComponent sc
198+
Input::SummarizedCallableBase sink, Impl::Private::SummaryComponent sc
204199
) {
205200
exists(Call call |
206201
call.getResolvedTarget() = sink and

rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,26 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
174174
)
175175
}
176176

177+
bindingset[path]
178+
pragma[inline_late]
179+
private Function interpretPath0(string path) { path = result.getCanonicalPath() }
180+
181+
bindingset[path, orig]
182+
pragma[inline_late]
183+
predicate interpretPath(string path, Function f, Provenance orig, Provenance p, boolean isExact) {
184+
exists(Function f0 | f0 = interpretPath0(path) |
185+
f = f0 and
186+
isExact = true and
187+
p = orig
188+
or
189+
f.implements(f0) and
190+
isExact = false and
191+
// making inherited models generated means that source code definitions and
192+
// exact generated models take precedence
193+
p = "hq-generated"
194+
)
195+
}
196+
177197
private class SummarizedCallableFromModel extends SummarizedCallable::Range {
178198
string input_;
179199
string output_;
@@ -183,19 +203,9 @@ private class SummarizedCallableFromModel extends SummarizedCallable::Range {
183203
QlBuiltins::ExtensionId madId;
184204

185205
SummarizedCallableFromModel() {
186-
exists(string path, Function f, Provenance p |
206+
exists(string path, Provenance p |
187207
summaryModel(path, input_, output_, kind, p, madId) and
188-
f.getCanonicalPath() = path
189-
|
190-
this = f and
191-
isExact_ = true and
192-
p_ = p
193-
or
194-
this.implements(f) and
195-
isExact_ = false and
196-
// making inherited models generated means that source code definitions and
197-
// exact generated models take precedence
198-
p_ = "hq-generated"
208+
interpretPath(path, this, p, p_, isExact_)
199209
)
200210
}
201211

@@ -246,78 +256,97 @@ private class SummarizedCallableWithCallback extends SummarizedCallable::Range {
246256

247257
private class FlowSourceFromModel extends FlowSource::Range {
248258
private string path;
259+
private string kind_;
260+
private Provenance orig;
261+
private Provenance p_;
262+
private boolean isExact_;
249263

250264
FlowSourceFromModel() {
251-
sourceModel(path, _, _, _, _) and
252-
this.getCanonicalPath() = path
265+
sourceModel(path, _, kind_, orig, _) and
266+
interpretPath(path, this, orig, p_, isExact_)
253267
}
254268

255-
override predicate isSource(string output, string kind, Provenance provenance, string model) {
269+
override predicate isSource(
270+
string output, string kind, Provenance provenance, boolean isExact, string model
271+
) {
256272
exists(QlBuiltins::ExtensionId madId |
257-
sourceModel(path, output, kind, provenance, madId) and
258-
model = "MaD:" + madId.toString()
259-
) and
260-
// Only apply generated models when no neutral model exists
261-
// (the shared code only applies neutral models to summaries at present)
262-
not (
263-
provenance.isGenerated() and
264-
neutralModel(path, "source", _, _)
273+
sourceModel(path, output, kind, orig, madId) and
274+
model = "MaD:" + madId.toString() and
275+
kind = kind_ and
276+
provenance = p_ and
277+
isExact = isExact_
265278
)
266279
}
267280
}
268281

269282
private class FlowSinkFromModel extends FlowSink::Range {
270283
private string path;
284+
private string kind_;
285+
private Provenance orig;
286+
private Provenance p_;
287+
private boolean isExact_;
271288

272289
FlowSinkFromModel() {
273-
sinkModel(path, _, _, _, _) and
274-
this.getCanonicalPath() = path
290+
sinkModel(path, _, kind_, orig, _) and
291+
interpretPath(path, this, orig, p_, isExact_)
275292
}
276293

277-
override predicate isSink(string input, string kind, Provenance provenance, string model) {
294+
override predicate isSink(
295+
string input, string kind, Provenance provenance, boolean isExact, string model
296+
) {
278297
exists(QlBuiltins::ExtensionId madId |
279-
sinkModel(path, input, kind, provenance, madId) and
280-
model = "MaD:" + madId.toString()
281-
) and
282-
// Only apply generated models when no neutral model exists
283-
// (the shared code only applies neutral models to summaries at present)
284-
not (
285-
provenance.isGenerated() and
286-
neutralModel(path, "sink", _, _)
298+
sinkModel(path, input, kind, orig, madId) and
299+
model = "MaD:" + madId.toString() and
300+
kind = kind_ and
301+
provenance = p_ and
302+
isExact = isExact_
287303
)
288304
}
289305
}
290306

291307
private class FlowBarrierFromModel extends FlowBarrier::Range {
292308
private string path;
309+
private Provenance orig;
310+
private Provenance p_;
311+
private boolean isExact_;
293312

294313
FlowBarrierFromModel() {
295-
barrierModel(path, _, _, _, _) and
296-
this.getCanonicalPath() = path
314+
barrierModel(path, _, _, orig, _) and
315+
interpretPath(path, this, orig, p_, isExact_)
297316
}
298317

299-
override predicate isBarrier(string output, string kind, Provenance provenance, string model) {
318+
override predicate isBarrier(
319+
string output, string kind, Provenance provenance, boolean isExact, string model
320+
) {
300321
exists(QlBuiltins::ExtensionId madId |
301-
barrierModel(path, output, kind, provenance, madId) and
302-
model = "MaD:" + madId.toString()
322+
barrierModel(path, output, kind, orig, madId) and
323+
model = "MaD:" + madId.toString() and
324+
provenance = p_ and
325+
isExact = isExact_
303326
)
304327
}
305328
}
306329

307330
private class FlowBarrierGuardFromModel extends FlowBarrierGuard::Range {
308331
private string path;
332+
private Provenance orig;
333+
private Provenance p_;
334+
private boolean isExact_;
309335

310336
FlowBarrierGuardFromModel() {
311-
barrierGuardModel(path, _, _, _, _, _) and
312-
this.getCanonicalPath() = path
337+
barrierGuardModel(path, _, _, _, orig, _) and
338+
interpretPath(path, this, orig, p_, isExact_)
313339
}
314340

315341
override predicate isBarrierGuard(
316-
string input, string acceptingValue, string kind, Provenance provenance, string model
342+
string input, string acceptingValue, string kind, Provenance provenance, boolean isExact,
343+
string model
317344
) {
318345
exists(QlBuiltins::ExtensionId madId |
319-
barrierGuardModel(path, input, acceptingValue, kind, provenance, madId) and
320-
model = "MaD:" + madId.toString()
346+
barrierGuardModel(path, input, acceptingValue, kind, orig, madId) and
347+
model = "MaD:" + madId.toString() and
348+
provenance = p_ and
349+
isExact = isExact_
321350
)
322351
}
323352
}

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2409,4 +2409,10 @@ private module Debug {
24092409
result = i.getCanonicalPath(c) and
24102410
i = getRelevantLocatable()
24112411
}
2412+
2413+
predicate debugCallTargetCanonicalPath(Call call, Function f, string path) {
2414+
call = getRelevantLocatable() and
2415+
f = call.getStaticTarget() and
2416+
path = f.getCanonicalPath()
2417+
}
24122418
}

rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ edges
44
| main.rs:21:13:21:21 | source(...) | main.rs:21:9:21:9 | s | provenance | |
55
| main.rs:32:9:32:9 | s | main.rs:33:10:33:10 | s | provenance | |
66
| main.rs:32:13:32:21 | source(...) | main.rs:32:9:32:9 | s | provenance | |
7-
| main.rs:63:9:63:9 | s | main.rs:65:10:65:10 | s | provenance | |
8-
| main.rs:63:13:63:21 | source(...) | main.rs:63:9:63:9 | s | provenance | |
97
nodes
108
| main.rs:17:10:17:18 | source(...) | semmle.label | source(...) |
119
| main.rs:21:9:21:9 | s | semmle.label | s |
@@ -14,13 +12,9 @@ nodes
1412
| main.rs:32:9:32:9 | s | semmle.label | s |
1513
| main.rs:32:13:32:21 | source(...) | semmle.label | source(...) |
1614
| main.rs:33:10:33:10 | s | semmle.label | s |
17-
| main.rs:63:9:63:9 | s | semmle.label | s |
18-
| main.rs:63:13:63:21 | source(...) | semmle.label | source(...) |
19-
| main.rs:65:10:65:10 | s | semmle.label | s |
2015
subpaths
2116
testFailures
2217
#select
2318
| main.rs:17:10:17:18 | source(...) | main.rs:17:10:17:18 | source(...) | main.rs:17:10:17:18 | source(...) | $@ | main.rs:17:10:17:18 | source(...) | source(...) |
2419
| main.rs:22:10:22:10 | s | main.rs:21:13:21:21 | source(...) | main.rs:22:10:22:10 | s | $@ | main.rs:21:13:21:21 | source(...) | source(...) |
2520
| main.rs:33:10:33:10 | s | main.rs:32:13:32:21 | source(...) | main.rs:33:10:33:10 | s | $@ | main.rs:32:13:32:21 | source(...) | source(...) |
26-
| main.rs:65:10:65:10 | s | main.rs:63:13:63:21 | source(...) | main.rs:65:10:65:10 | s | $@ | main.rs:63:13:63:21 | source(...) | source(...) |

rust/ql/test/library-tests/dataflow/barrier/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<T> MyBarrierTrait3 for T {
6262
fn with_trait_barriers() {
6363
let s = source(2);
6464
<()>::sanitize2(s);
65-
sink(s); // $ SPURIOUS: hasValueFlow=2
65+
sink(s);
6666
<()>::sanitize3(s);
6767
sink(s);
6868
}

rust/ql/test/library-tests/dataflow/models/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,12 @@ fn test_trait_model<T: Ord>(x: T) {
527527
sink(x9); // $ hasValueFlow=30
528528

529529
let x10 = <()>::produce2(31);
530-
sink(x10); // $ MISSING: hasValueFlow=31
530+
sink(x10); // $ hasValueFlow=31
531531

532532
let x11 = <()>::produce3(32);
533533
sink(x11); // $ hasValueFlow=32
534534

535-
<()>::consume2(source(33)); // $ MISSING: hasValueFlow=33
535+
<()>::consume2(source(33)); // $ hasValueFlow=33
536536

537537
<()>::consume3(source(34)); // $ hasValueFlow=34
538538
}

0 commit comments

Comments
 (0)