Skip to content

Commit 98319be

Browse files
authored
Merge pull request github#16985 from geoffw0/madprov
C++: Support MaD alert provenance
2 parents 45ba0c3 + e39e765 commit 98319be

File tree

6 files changed

+137
-59
lines changed

6 files changed

+137
-59
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.

cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
146146
/** Holds if a source model exists for the given parameters. */
147147
predicate sourceModel(
148148
string namespace, string type, boolean subtypes, string name, string signature, string ext,
149-
string output, string kind, string provenance
149+
string output, string kind, string provenance, string model
150150
) {
151151
exists(string row |
152152
sourceModel(row) and
@@ -160,16 +160,20 @@ predicate sourceModel(
160160
row.splitAt(";", 6) = output and
161161
row.splitAt(";", 7) = kind
162162
) and
163-
provenance = "manual"
163+
provenance = "manual" and
164+
model = ""
164165
or
165-
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance,
166-
_)
166+
exists(QlBuiltins::ExtensionId madId |
167+
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
168+
provenance, madId) and
169+
model = "MaD:" + madId.toString()
170+
)
167171
}
168172

169173
/** Holds if a sink model exists for the given parameters. */
170174
predicate sinkModel(
171175
string namespace, string type, boolean subtypes, string name, string signature, string ext,
172-
string input, string kind, string provenance
176+
string input, string kind, string provenance, string model
173177
) {
174178
exists(string row |
175179
sinkModel(row) and
@@ -183,9 +187,14 @@ predicate sinkModel(
183187
row.splitAt(";", 6) = input and
184188
row.splitAt(";", 7) = kind
185189
) and
186-
provenance = "manual"
190+
provenance = "manual" and
191+
model = ""
187192
or
188-
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, _)
193+
exists(QlBuiltins::ExtensionId madId |
194+
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
195+
madId) and
196+
model = "MaD:" + madId.toString()
197+
)
189198
}
190199

191200
/**
@@ -195,7 +204,7 @@ predicate sinkModel(
195204
*/
196205
private predicate summaryModel0(
197206
string namespace, string type, boolean subtypes, string name, string signature, string ext,
198-
string input, string output, string kind, string provenance
207+
string input, string output, string kind, string provenance, string model
199208
) {
200209
exists(string row |
201210
summaryModel(row) and
@@ -210,10 +219,14 @@ private predicate summaryModel0(
210219
row.splitAt(";", 7) = output and
211220
row.splitAt(";", 8) = kind
212221
) and
213-
provenance = "manual"
222+
provenance = "manual" and
223+
model = ""
214224
or
215-
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
216-
provenance, _)
225+
exists(QlBuiltins::ExtensionId madId |
226+
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
227+
provenance, madId) and
228+
model = "MaD:" + madId.toString()
229+
)
217230
}
218231

219232
/**
@@ -234,19 +247,20 @@ private predicate expandInputAndOutput(
234247
*/
235248
predicate summaryModel(
236249
string namespace, string type, boolean subtypes, string name, string signature, string ext,
237-
string input, string output, string kind, string provenance
250+
string input, string output, string kind, string provenance, string model
238251
) {
239252
exists(string input0, string output0 |
240-
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind, provenance) and
253+
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
254+
provenance, model) and
241255
expandInputAndOutput(input0, input, output0, output,
242256
[0 .. Private::getMaxElementContentIndirectionIndex() - 1])
243257
)
244258
}
245259

246260
private predicate relevantNamespace(string namespace) {
247-
sourceModel(namespace, _, _, _, _, _, _, _, _) or
248-
sinkModel(namespace, _, _, _, _, _, _, _, _) or
249-
summaryModel(namespace, _, _, _, _, _, _, _, _, _)
261+
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or
262+
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or
263+
summaryModel(namespace, _, _, _, _, _, _, _, _, _, _)
250264
}
251265

252266
private predicate namespaceLink(string shortns, string longns) {
@@ -276,25 +290,25 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
276290
part = "source" and
277291
n =
278292
strictcount(string subns, string type, boolean subtypes, string name, string signature,
279-
string ext, string output, string provenance |
293+
string ext, string output, string provenance, string model |
280294
canonicalNamespaceLink(namespace, subns) and
281-
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance)
295+
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance, model)
282296
)
283297
or
284298
part = "sink" and
285299
n =
286300
strictcount(string subns, string type, boolean subtypes, string name, string signature,
287-
string ext, string input, string provenance |
301+
string ext, string input, string provenance, string model |
288302
canonicalNamespaceLink(namespace, subns) and
289-
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance)
303+
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance, model)
290304
)
291305
or
292306
part = "summary" and
293307
n =
294308
strictcount(string subns, string type, boolean subtypes, string name, string signature,
295309
string ext, string input, string output, string provenance |
296310
canonicalNamespaceLink(namespace, subns) and
297-
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance)
311+
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
298312
)
299313
)
300314
}
@@ -303,9 +317,9 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
303317
module CsvValidation {
304318
private string getInvalidModelInput() {
305319
exists(string pred, AccessPath input, string part |
306-
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
320+
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
307321
or
308-
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
322+
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
309323
|
310324
(
311325
invalidSpecComponent(input, part) and
@@ -322,9 +336,9 @@ module CsvValidation {
322336

323337
private string getInvalidModelOutput() {
324338
exists(string pred, string output, string part |
325-
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
339+
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source"
326340
or
327-
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
341+
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary"
328342
|
329343
invalidSpecComponent(output, part) and
330344
not part = "" and
@@ -334,11 +348,11 @@ module CsvValidation {
334348
}
335349

336350
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
337-
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) }
351+
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _, _) }
338352

339-
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) }
353+
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _, _) }
340354

341-
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) }
355+
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
342356
}
343357

344358
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
@@ -379,11 +393,11 @@ module CsvValidation {
379393

380394
private string getInvalidModelSignature() {
381395
exists(string pred, string namespace, string type, string name, string signature, string ext |
382-
sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
396+
sourceModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "source"
383397
or
384-
sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
398+
sinkModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "sink"
385399
or
386-
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
400+
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _, _) and pred = "summary"
387401
|
388402
not namespace.regexpMatch("[a-zA-Z0-9_\\.:]*") and
389403
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
@@ -415,9 +429,9 @@ module CsvValidation {
415429
private predicate elementSpec(
416430
string namespace, string type, boolean subtypes, string name, string signature, string ext
417431
) {
418-
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
419-
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
420-
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
432+
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
433+
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
434+
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
421435
}
422436

423437
/** Gets the fully templated version of `f`. */
@@ -867,9 +881,9 @@ private module Cached {
867881
* model.
868882
*/
869883
cached
870-
predicate sourceNode(DataFlow::Node node, string kind) {
884+
predicate sourceNode(DataFlow::Node node, string kind, string model) {
871885
exists(SourceSinkInterpretationInput::InterpretNode n |
872-
isSourceNode(n, kind, _) and n.asNode() = node // TODO
886+
isSourceNode(n, kind, model) and n.asNode() = node
873887
)
874888
}
875889

@@ -878,40 +892,57 @@ private module Cached {
878892
* model.
879893
*/
880894
cached
881-
predicate sinkNode(DataFlow::Node node, string kind) {
895+
predicate sinkNode(DataFlow::Node node, string kind, string model) {
882896
exists(SourceSinkInterpretationInput::InterpretNode n |
883-
isSinkNode(n, kind, _) and n.asNode() = node // TODO
897+
isSinkNode(n, kind, model) and n.asNode() = node
884898
)
885899
}
886900
}
887901

888902
import Cached
889903

904+
/**
905+
* Holds if `node` is specified as a source with the given kind in a MaD flow
906+
* model.
907+
*/
908+
predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind, _) }
909+
910+
/**
911+
* Holds if `node` is specified as a sink with the given kind in a MaD flow
912+
* model.
913+
*/
914+
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
915+
890916
private predicate interpretSummary(
891-
Function f, string input, string output, string kind, string provenance
917+
Function f, string input, string output, string kind, string provenance, string model
892918
) {
893919
exists(
894920
string namespace, string type, boolean subtypes, string name, string signature, string ext
895921
|
896-
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
922+
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
923+
model) and
897924
f = interpretElement(namespace, type, subtypes, name, signature, ext)
898925
)
899926
}
900927

901928
// adapter class for converting Mad summaries to `SummarizedCallable`s
902929
private class SummarizedCallableAdapter extends SummarizedCallable {
903-
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
930+
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
904931

905-
private predicate relevantSummaryElementManual(string input, string output, string kind) {
932+
private predicate relevantSummaryElementManual(
933+
string input, string output, string kind, string model
934+
) {
906935
exists(Provenance provenance |
907-
interpretSummary(this, input, output, kind, provenance) and
936+
interpretSummary(this, input, output, kind, provenance, model) and
908937
provenance.isManual()
909938
)
910939
}
911940

912-
private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
941+
private predicate relevantSummaryElementGenerated(
942+
string input, string output, string kind, string model
943+
) {
913944
exists(Provenance provenance |
914-
interpretSummary(this, input, output, kind, provenance) and
945+
interpretSummary(this, input, output, kind, provenance, model) and
915946
provenance.isGenerated()
916947
)
917948
}
@@ -920,18 +951,17 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
920951
string input, string output, boolean preservesValue, string model
921952
) {
922953
exists(string kind |
923-
this.relevantSummaryElementManual(input, output, kind)
954+
this.relevantSummaryElementManual(input, output, kind, model)
924955
or
925-
not this.relevantSummaryElementManual(_, _, _) and
926-
this.relevantSummaryElementGenerated(input, output, kind)
956+
not this.relevantSummaryElementManual(_, _, _, _) and
957+
this.relevantSummaryElementGenerated(input, output, kind, model)
927958
|
928959
if kind = "value" then preservesValue = true else preservesValue = false
929-
) and
930-
model = "" // TODO
960+
)
931961
}
932962

933963
override predicate hasProvenance(Provenance provenance) {
934-
interpretSummary(this, _, _, _, provenance)
964+
interpretSummary(this, _, _, _, provenance, _)
935965
}
936966
}
937967

cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ module SourceSinkInterpretationInput implements
112112
exists(
113113
string namespace, string type, boolean subtypes, string name, string signature, string ext
114114
|
115-
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
116-
e = interpretElement(namespace, type, subtypes, name, signature, ext) and
117-
model = "" // TODO
115+
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
116+
e = interpretElement(namespace, type, subtypes, name, signature, ext)
118117
)
119118
}
120119

@@ -128,9 +127,8 @@ module SourceSinkInterpretationInput implements
128127
exists(
129128
string package, string type, boolean subtypes, string name, string signature, string ext
130129
|
131-
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
132-
e = interpretElement(package, type, subtypes, name, signature, ext) and
133-
model = "" // TODO
130+
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, model) and
131+
e = interpretElement(package, type, subtypes, name, signature, ext)
134132
)
135133
}
136134

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import Node0ToString
1111
private import ModelUtil
1212
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
1313
private import semmle.code.cpp.models.interfaces.DataFlow as DF
14+
private import semmle.code.cpp.dataflow.ExternalFlow as External
1415

1516
cached
1617
private module Cached {
@@ -1333,9 +1334,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
13331334
/** Extra data-flow steps needed for lambda flow analysis. */
13341335
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
13351336

1336-
predicate knownSourceModel(Node source, string model) { none() }
1337+
predicate knownSourceModel(Node source, string model) { External::sourceNode(source, _, model) }
13371338

1338-
predicate knownSinkModel(Node sink, string model) { none() }
1339+
predicate knownSinkModel(Node sink, string model) { External::sinkNode(sink, _, model) }
13391340

13401341
/**
13411342
* Holds if flow is allowed to pass from parameter `p` and back to itself as a

0 commit comments

Comments
 (0)