Skip to content

Commit 72d4c97

Browse files
authored
Merge pull request github#8628 from michaelnebel/csharp/generatedkind
C#: Introduce generated flag as a part of the kind column for flow summaries
2 parents 879b8a1 + 2562910 commit 72d4c97

File tree

27 files changed

+467
-299
lines changed

27 files changed

+467
-299
lines changed

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

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,17 @@ private predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
162162

163163
private predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
164164

165+
bindingset[input]
166+
private predicate getKind(string input, string kind, boolean generated) {
167+
input.splitAt(":", 0) = "generated" and kind = input.splitAt(":", 1) and generated = true
168+
or
169+
not input.matches("%:%") and kind = input and generated = false
170+
}
171+
165172
/** Holds if a source model exists for the given parameters. */
166173
predicate sourceModel(
167174
string namespace, string type, boolean subtypes, string name, string signature, string ext,
168-
string output, string kind
175+
string output, string kind, boolean generated
169176
) {
170177
exists(string row |
171178
sourceModel(row) and
@@ -177,14 +184,14 @@ predicate sourceModel(
177184
row.splitAt(";", 4) = signature and
178185
row.splitAt(";", 5) = ext and
179186
row.splitAt(";", 6) = output and
180-
row.splitAt(";", 7) = kind
187+
exists(string k | row.splitAt(";", 7) = k and getKind(k, kind, generated))
181188
)
182189
}
183190

184191
/** Holds if a sink model exists for the given parameters. */
185192
predicate sinkModel(
186193
string namespace, string type, boolean subtypes, string name, string signature, string ext,
187-
string input, string kind
194+
string input, string kind, boolean generated
188195
) {
189196
exists(string row |
190197
sinkModel(row) and
@@ -196,14 +203,14 @@ predicate sinkModel(
196203
row.splitAt(";", 4) = signature and
197204
row.splitAt(";", 5) = ext and
198205
row.splitAt(";", 6) = input and
199-
row.splitAt(";", 7) = kind
206+
exists(string k | row.splitAt(";", 7) = k and getKind(k, kind, generated))
200207
)
201208
}
202209

203210
/** Holds if a summary model exists for the given parameters. */
204211
predicate summaryModel(
205212
string namespace, string type, boolean subtypes, string name, string signature, string ext,
206-
string input, string output, string kind
213+
string input, string output, string kind, boolean generated
207214
) {
208215
exists(string row |
209216
summaryModel(row) and
@@ -216,14 +223,14 @@ predicate summaryModel(
216223
row.splitAt(";", 5) = ext and
217224
row.splitAt(";", 6) = input and
218225
row.splitAt(";", 7) = output and
219-
row.splitAt(";", 8) = kind
226+
exists(string k | row.splitAt(";", 8) = k and getKind(k, kind, generated))
220227
)
221228
}
222229

223230
private predicate relevantNamespace(string namespace) {
224-
sourceModel(namespace, _, _, _, _, _, _, _) or
225-
sinkModel(namespace, _, _, _, _, _, _, _) or
226-
summaryModel(namespace, _, _, _, _, _, _, _, _)
231+
sourceModel(namespace, _, _, _, _, _, _, _, _) or
232+
sinkModel(namespace, _, _, _, _, _, _, _, _) or
233+
summaryModel(namespace, _, _, _, _, _, _, _, _, _)
227234
}
228235

229236
private predicate namespaceLink(string shortns, string longns) {
@@ -251,25 +258,25 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
251258
part = "source" and
252259
n =
253260
strictcount(string subns, string type, boolean subtypes, string name, string signature,
254-
string ext, string output |
261+
string ext, string output, boolean generated |
255262
canonicalNamespaceLink(namespace, subns) and
256-
sourceModel(subns, type, subtypes, name, signature, ext, output, kind)
263+
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, generated)
257264
)
258265
or
259266
part = "sink" and
260267
n =
261268
strictcount(string subns, string type, boolean subtypes, string name, string signature,
262-
string ext, string input |
269+
string ext, string input, boolean generated |
263270
canonicalNamespaceLink(namespace, subns) and
264-
sinkModel(subns, type, subtypes, name, signature, ext, input, kind)
271+
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, generated)
265272
)
266273
or
267274
part = "summary" and
268275
n =
269276
strictcount(string subns, string type, boolean subtypes, string name, string signature,
270-
string ext, string input, string output |
277+
string ext, string input, string output, boolean generated |
271278
canonicalNamespaceLink(namespace, subns) and
272-
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind)
279+
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, generated)
273280
)
274281
)
275282
}
@@ -279,11 +286,11 @@ module CsvValidation {
279286
/** Holds if some row in a CSV-based flow model appears to contain typos. */
280287
query predicate invalidModelRow(string msg) {
281288
exists(string pred, string namespace, string type, string name, string signature, string ext |
282-
sourceModel(namespace, type, _, name, signature, ext, _, _) and pred = "source"
289+
sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
283290
or
284-
sinkModel(namespace, type, _, name, signature, ext, _, _) and pred = "sink"
291+
sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
285292
or
286-
summaryModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "summary"
293+
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
287294
|
288295
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
289296
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
@@ -302,9 +309,9 @@ module CsvValidation {
302309
)
303310
or
304311
exists(string pred, AccessPath input, string part |
305-
sinkModel(_, _, _, _, _, _, input, _) and pred = "sink"
312+
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
306313
or
307-
summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
314+
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
308315
|
309316
(
310317
invalidSpecComponent(input, part) and
@@ -319,9 +326,9 @@ module CsvValidation {
319326
)
320327
or
321328
exists(string pred, string output, string part |
322-
sourceModel(_, _, _, _, _, _, output, _) and pred = "source"
329+
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
323330
or
324-
summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
331+
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
325332
|
326333
invalidSpecComponent(output, part) and
327334
not part = "" and
@@ -351,20 +358,23 @@ module CsvValidation {
351358
)
352359
)
353360
or
354-
exists(string row, string kind | summaryModel(row) |
355-
kind = row.splitAt(";", 8) and
361+
exists(string row, string k, string kind | summaryModel(row) |
362+
k = row.splitAt(";", 8) and
363+
getKind(k, kind, _) and
356364
not kind = ["taint", "value"] and
357365
msg = "Invalid kind \"" + kind + "\" in summary model."
358366
)
359367
or
360-
exists(string row, string kind | sinkModel(row) |
361-
kind = row.splitAt(";", 7) and
368+
exists(string row, string k, string kind | sinkModel(row) |
369+
k = row.splitAt(";", 7) and
370+
getKind(k, kind, _) and
362371
not kind = ["code", "sql", "xss", "remote", "html"] and
363372
msg = "Invalid kind \"" + kind + "\" in sink model."
364373
)
365374
or
366-
exists(string row, string kind | sourceModel(row) |
367-
kind = row.splitAt(";", 7) and
375+
exists(string row, string k, string kind | sourceModel(row) |
376+
k = row.splitAt(";", 7) and
377+
getKind(k, kind, _) and
368378
not kind = "local" and
369379
msg = "Invalid kind \"" + kind + "\" in source model."
370380
)
@@ -374,9 +384,9 @@ module CsvValidation {
374384
private predicate elementSpec(
375385
string namespace, string type, boolean subtypes, string name, string signature, string ext
376386
) {
377-
sourceModel(namespace, type, subtypes, name, signature, ext, _, _) or
378-
sinkModel(namespace, type, subtypes, name, signature, ext, _, _) or
379-
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _)
387+
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
388+
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
389+
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
380390
}
381391

382392
private predicate elementSpec(
@@ -502,6 +512,13 @@ Element interpretElement(
502512
)
503513
}
504514

515+
/**
516+
* Holds if `c` has a `generated` summary.
517+
*/
518+
predicate hasSummary(DataFlowCallable c, boolean generated) {
519+
summaryElement(c, _, _, _, generated)
520+
}
521+
505522
cached
506523
private module Cached {
507524
/**

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -806,10 +806,10 @@ module Private {
806806
module External {
807807
/** Holds if `spec` is a relevant external specification. */
808808
private predicate relevantSpec(string spec) {
809-
summaryElement(_, spec, _, _) or
810-
summaryElement(_, _, spec, _) or
811-
sourceElement(_, spec, _) or
812-
sinkElement(_, spec, _)
809+
summaryElement(_, spec, _, _, _) or
810+
summaryElement(_, _, spec, _, _) or
811+
sourceElement(_, spec, _, _) or
812+
sinkElement(_, spec, _, _)
813813
}
814814

815815
private class AccessPathRange extends AccessPath::Range {
@@ -875,13 +875,20 @@ module Private {
875875
}
876876

877877
private class SummarizedCallableExternal extends SummarizedCallable {
878-
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
878+
SummarizedCallableExternal() { summaryElement(this, _, _, _, _) }
879+
880+
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
881+
summaryElement(this, inSpec, outSpec, kind, false)
882+
or
883+
summaryElement(this, inSpec, outSpec, kind, true) and
884+
not summaryElement(this, _, _, _, false)
885+
}
879886

880887
override predicate propagatesFlow(
881888
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
882889
) {
883890
exists(AccessPath inSpec, AccessPath outSpec, string kind |
884-
summaryElement(this, inSpec, outSpec, kind) and
891+
this.relevantSummaryElement(inSpec, outSpec, kind) and
885892
interpretSpec(inSpec, input) and
886893
interpretSpec(outSpec, output)
887894
|
@@ -910,7 +917,7 @@ module Private {
910917

911918
private predicate sourceElementRef(InterpretNode ref, AccessPath output, string kind) {
912919
exists(SourceOrSinkElement e |
913-
sourceElement(e, output, kind) and
920+
sourceElement(e, output, kind, _) and
914921
if outputNeedsReference(output.getToken(0))
915922
then e = ref.getCallTarget()
916923
else e = ref.asElement()
@@ -919,7 +926,7 @@ module Private {
919926

920927
private predicate sinkElementRef(InterpretNode ref, AccessPath input, string kind) {
921928
exists(SourceOrSinkElement e |
922-
sinkElement(e, input, kind) and
929+
sinkElement(e, input, kind, _) and
923930
if inputNeedsReference(input.getToken(0))
924931
then e = ref.getCallTarget()
925932
else e = ref.asElement()

csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,39 +85,44 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
8585

8686
/**
8787
* Holds if an external flow summary exists for `c` with input specification
88-
* `input`, output specification `output`, and kind `kind`.
88+
* `input`, output specification `output`, kind `kind`, and a flag `generated`
89+
* stating whether the summary is autogenerated.
8990
*/
90-
predicate summaryElement(DataFlowCallable c, string input, string output, string kind) {
91+
predicate summaryElement(
92+
DataFlowCallable c, string input, string output, string kind, boolean generated
93+
) {
9194
exists(
9295
string namespace, string type, boolean subtypes, string name, string signature, string ext
9396
|
94-
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
97+
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated) and
9598
c = interpretElement(namespace, type, subtypes, name, signature, ext)
9699
)
97100
}
98101

99102
/**
100103
* Holds if an external source specification exists for `e` with output specification
101-
* `output` and kind `kind`.
104+
* `output`, kind `kind`, and a flag `generated` stating whether the source specification is
105+
* autogenerated.
102106
*/
103-
predicate sourceElement(Element e, string output, string kind) {
107+
predicate sourceElement(Element e, string output, string kind, boolean generated) {
104108
exists(
105109
string namespace, string type, boolean subtypes, string name, string signature, string ext
106110
|
107-
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind) and
111+
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, generated) and
108112
e = interpretElement(namespace, type, subtypes, name, signature, ext)
109113
)
110114
}
111115

112116
/**
113-
* Holds if an external sink specification exists for `n` with input specification
114-
* `input` and kind `kind`.
117+
* Holds if an external sink specification exists for `e` with input specification
118+
* `input`, kind `kind` and a flag `generated` stating whether the sink specification is
119+
* autogenerated.
115120
*/
116-
predicate sinkElement(Element e, string input, string kind) {
121+
predicate sinkElement(Element e, string input, string kind, boolean generated) {
117122
exists(
118123
string namespace, string type, boolean subtypes, string name, string signature, string ext
119124
|
120-
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind) and
125+
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, generated) and
121126
e = interpretElement(namespace, type, subtypes, name, signature, ext)
122127
)
123128
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Capture discarded summary models.
3+
* @description Finds summary models that are discarded as handwritten counterparts exist.
4+
* @id csharp/utils/model-generator/discarded-summary-models
5+
*/
6+
7+
private import semmle.code.csharp.dataflow.ExternalFlow
8+
private import internal.CaptureModels
9+
private import internal.CaptureFlow
10+
11+
from TargetApi api, string flow
12+
where flow = captureFlow(api) and hasSummary(api, false)
13+
select flow order by flow

0 commit comments

Comments
 (0)