Skip to content

Commit eefbb67

Browse files
committed
C++: Support alert provenance.
1 parent 391816c commit eefbb67

File tree

3 files changed

+89
-61
lines changed

3 files changed

+89
-61
lines changed

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/test/library-tests/dataflow/external-models/flow.expected

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
testFailures
22
failures
33
edges
4-
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | |
4+
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:10 |
55
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | |
66
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | |
77
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
@@ -10,15 +10,15 @@ edges
1010
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
1111
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | |
1212
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
13-
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
14-
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | |
13+
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
14+
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:2 |
1515
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | |
1616
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | |
1717
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:13:18:13:18 | x | provenance | |
1818
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
1919
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | |
2020
| test.cpp:13:18:13:18 | x | test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | provenance | |
21-
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
21+
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:2 |
2222
nodes
2323
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
2424
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |

0 commit comments

Comments
 (0)