Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cc44e89

Browse files
committed
C#: Introduce support for Negative summary models.
1 parent 4df2e5d commit cc44e89

13 files changed

Lines changed: 170 additions & 20 deletions

File tree

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

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
*
66
* The CSV specification has the following columns:
77
* - Sources:
8-
* `namespace; type; subtypes; name; signature; ext; output; kind`
8+
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
99
* - Sinks:
10-
* `namespace; type; subtypes; name; signature; ext; input; kind`
10+
* `namespace; type; subtypes; name; signature; ext; input; kind; provenance`
1111
* - Summaries:
12-
* `namespace; type; subtypes; name; signature; ext; input; output; kind`
13-
*
12+
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
13+
* - Negative Summaries:
14+
* `namespace; type; name; signature; provenance`
1415
* The interpretation of a row is similar to API-graphs with a left-to-right
1516
* reading.
1617
* 1. The `namespace` column selects a namespace.
@@ -163,12 +164,24 @@ class SummaryModelCsv extends Unit {
163164
abstract predicate row(string row);
164165
}
165166

167+
/**
168+
* A unit class for adding negative summary model rows.
169+
*
170+
* Extend this class to add additional flow summary definitions.
171+
*/
172+
class NegativeSummaryModelCsv extends Unit {
173+
/** Holds if `row` specifies a negative summary definition. */
174+
abstract predicate row(string row);
175+
}
176+
166177
private predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
167178

168179
private predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
169180

170181
private predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
171182

183+
private predicate negativeSummaryModel(string row) { any(NegativeSummaryModelCsv s).row(row) }
184+
172185
/** Holds if a source model exists for the given parameters. */
173186
predicate sourceModel(
174187
string namespace, string type, boolean subtypes, string name, string signature, string ext,
@@ -230,6 +243,20 @@ predicate summaryModel(
230243
)
231244
}
232245

246+
/** Holds is a summary model exists indicating there is no flow for the given parameters. */
247+
predicate negativeSummaryModel(
248+
string namespace, string type, string name, string signature, string provenance
249+
) {
250+
exists(string row |
251+
negativeSummaryModel(row) and
252+
row.splitAt(";", 0) = namespace and
253+
row.splitAt(";", 1) = type and
254+
row.splitAt(";", 2) = name and
255+
row.splitAt(";", 3) = signature and
256+
row.splitAt(";", 4) = provenance
257+
)
258+
}
259+
233260
private predicate relevantNamespace(string namespace) {
234261
sourceModel(namespace, _, _, _, _, _, _, _, _) or
235262
sinkModel(namespace, _, _, _, _, _, _, _, _) or
@@ -298,6 +325,10 @@ module CsvValidation {
298325
or
299326
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance) and
300327
pred = "summary"
328+
or
329+
negativeSummaryModel(namespace, type, name, signature, provenance) and
330+
ext = "" and
331+
pred = "nonesummary"
301332
|
302333
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
303334
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
@@ -392,9 +423,13 @@ module CsvValidation {
392423
private predicate elementSpec(
393424
string namespace, string type, boolean subtypes, string name, string signature, string ext
394425
) {
395-
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
396-
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
426+
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _)
427+
or
428+
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _)
429+
or
397430
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
431+
or
432+
negativeSummaryModel(namespace, type, name, signature, _) and ext = "" and subtypes = false
398433
}
399434

400435
private predicate elementSpec(
@@ -508,7 +543,7 @@ private Element interpretElement0(
508543
)
509544
}
510545

511-
/** Gets the source/sink/summary element corresponding to the supplied parameters. */
546+
/** Gets the source/sink/summary/negativesummary element corresponding to the supplied parameters. */
512547
Element interpretElement(
513548
string namespace, string type, boolean subtypes, string name, string signature, string ext
514549
) {

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,18 +2129,37 @@ module Csv {
21292129
if isBaseCallableOrPrototype(c) then result = "true" else result = "false"
21302130
}
21312131

2132-
/** Computes the first 6 columns for CSV rows of `c`. */
2132+
private predicate partialModel(
2133+
DotNet::Callable c, string namespace, string type, string name, string parameters
2134+
) {
2135+
c.getDeclaringType().hasQualifiedName(namespace, type) and
2136+
c.hasQualifiedName(_, name) and
2137+
parameters = "(" + parameterQualifiedTypeNamesToString(c) + ")"
2138+
}
2139+
2140+
/** Computes the first 6 columns for positive CSV rows of `c`. */
21332141
string asPartialModel(DotNet::Callable c) {
2134-
exists(string namespace, string type, string name |
2135-
c.getDeclaringType().hasQualifiedName(namespace, type) and
2136-
c.hasQualifiedName(_, name) and
2142+
exists(string namespace, string type, string name, string parameters |
2143+
partialModel(c, namespace, type, name, parameters) and
21372144
result =
21382145
namespace + ";" //
21392146
+ type + ";" //
21402147
+ getCallableOverride(c) + ";" //
21412148
+ name + ";" //
2142-
+ "(" + parameterQualifiedTypeNamesToString(c) + ")" + ";" //
2149+
+ parameters + ";" //
21432150
+ /* ext + */ ";" //
21442151
)
21452152
}
2153+
2154+
/** Computes the first 4 columns for negative CSV rows of `c`. */
2155+
string asPartialNegativeModel(DotNet::Callable c) {
2156+
exists(string namespace, string type, string name, string parameters |
2157+
partialModel(c, namespace, type, name, parameters) and
2158+
result =
2159+
namespace + ";" //
2160+
+ type + ";" //
2161+
+ name + ";" //
2162+
+ parameters + ";" //
2163+
)
2164+
}
21462165
}

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

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,16 @@ module Public {
240240
*/
241241
predicate isAutoGenerated() { none() }
242242
}
243+
244+
/** A callable with a flow summary stating there is no flow via the callable. */
245+
class NegativeSummarizedCallable extends SummarizedCallableBase {
246+
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
247+
248+
/**
249+
* Holds if the none summary is auto generated.
250+
*/
251+
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
252+
}
243253
}
244254

245255
/**
@@ -1094,7 +1104,7 @@ module Private {
10941104

10951105
/** Provides a query predicate for outputting a set of relevant flow summaries. */
10961106
module TestOutput {
1097-
/** A flow summary to include in the `summary/3` query predicate. */
1107+
/** A flow summary to include in the `summary/1` query predicate. */
10981108
abstract class RelevantSummarizedCallable instanceof SummarizedCallable {
10991109
/** Gets the string representation of this callable used by `summary/1`. */
11001110
abstract string getCallableCsv();
@@ -1109,15 +1119,27 @@ module Private {
11091119
string toString() { result = super.toString() }
11101120
}
11111121

1122+
/** A flow summary to include in the `negativeSummary/1` query predicate. */
1123+
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
1124+
/** Gets the string representation of this callable used by `summary/1`. */
1125+
abstract string getCallableCsv();
1126+
1127+
string toString() { result = super.toString() }
1128+
}
1129+
11121130
/** Render the kind in the format used in flow summaries. */
11131131
private string renderKind(boolean preservesValue) {
11141132
preservesValue = true and result = "value"
11151133
or
11161134
preservesValue = false and result = "taint"
11171135
}
11181136

1119-
private string renderProvenance(RelevantSummarizedCallable c) {
1120-
if c.(SummarizedCallable).isAutoGenerated() then result = "generated" else result = "manual"
1137+
private string renderProvenance(SummarizedCallable c) {
1138+
if c.isAutoGenerated() then result = "generated" else result = "manual"
1139+
}
1140+
1141+
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
1142+
if c.isAutoGenerated() then result = "generated" else result = "manual"
11211143
}
11221144

11231145
/**
@@ -1132,8 +1154,23 @@ module Private {
11321154
|
11331155
c.relevantSummary(input, output, preservesValue) and
11341156
csv =
1135-
c.getCallableCsv() + getComponentStackCsv(input) + ";" + getComponentStackCsv(output) +
1136-
";" + renderKind(preservesValue) + ";" + renderProvenance(c)
1157+
c.getCallableCsv() // Callable information
1158+
+ getComponentStackCsv(input) + ";" // input
1159+
+ getComponentStackCsv(output) + ";" // output
1160+
+ renderKind(preservesValue) + ";" // kind
1161+
+ renderProvenance(c) // provenance
1162+
)
1163+
}
1164+
1165+
/**
1166+
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
1167+
* The syntax is: "namespace;type;name;signature;provenance"",
1168+
*/
1169+
query predicate negativeSummary(string csv) {
1170+
exists(RelevantNegativeSummarizedCallable c |
1171+
csv =
1172+
c.getCallableCsv() // Callable information
1173+
+ renderProvenanceNegative(c) // provenance
11371174
)
11381175
}
11391176
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ predicate summaryElement(Callable c, string input, string output, string kind, b
114114
)
115115
}
116116

117+
/**
118+
* Holds is an external flow summary exists for `c` which means that there is no
119+
* flow through `c` and a flag `generated` stating whether the summary is autogenerated.
120+
*/
121+
predicate negativeSummaryElement(Callable c, boolean generated) {
122+
exists(string namespace, string type, string name, string signature, string provenance |
123+
negativeSummaryModel(namespace, type, name, signature, provenance) and
124+
generated = isGenerated(provenance) and
125+
c = interpretElement(namespace, type, false, name, signature, "")
126+
)
127+
}
128+
117129
/**
118130
* Holds if an external source specification exists for `e` with output specification
119131
* `output`, kind `kind`, and a flag `generated` stating whether the source specification is

csharp/ql/src/Telemetry/UnsupportedExternalAPIs.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
private import csharp
1010
private import semmle.code.csharp.dispatch.Dispatch
11+
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1112
private import ExternalApi
1213

1314
private predicate getRelevantUsages(ExternalApi api, int usages) {
1415
not api.isUninteresting() and
1516
not api.isSupported() and
17+
not api instanceof FlowSummaryImpl::Public::NegativeSummarizedCallable and
1618
usages = strictcount(DispatchCall c | c = api.getACall())
1719
}
1820

csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
private import semmle.code.csharp.dataflow.ExternalFlow
88
private import internal.CaptureModels
9-
private import internal.CaptureFlow
9+
private import internal.CaptureSummaryFlow
1010

1111
from TargetApi api, string flow
1212
where flow = captureFlow(api) and hasSummary(api, false)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* @name Capture negative summary models.
3+
* @description Finds negative summary models to be used by other queries.
4+
* @kind diagnostic
5+
* @id cs/utils/model-generator/negative-summary-models
6+
* @tags model-generator
7+
*/
8+
9+
private import semmle.code.csharp.dataflow.ExternalFlow
10+
private import internal.CaptureModels
11+
private import internal.CaptureSummaryFlow
12+
13+
from TargetApi api, string noflow
14+
where noflow = captureNoFlow(api) and not hasSummary(api, false)
15+
select noflow order by noflow

csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
private import semmle.code.csharp.dataflow.ExternalFlow
1010
private import internal.CaptureModels
11-
private import internal.CaptureFlow
11+
private import internal.CaptureSummaryFlow
1212

1313
from TargetApi api, string flow
1414
where flow = captureFlow(api) and not hasSummary(api, false)

csharp/ql/src/utils/model-generator/internal/CaptureModels.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ private string asSummaryModel(TargetApi api, string input, string output, string
4848
+ "generated"
4949
}
5050

51+
string asNegativeSummaryModel(TargetApi api) { result = asPartialNegativeModel(api) + "generated" }
52+
53+
predicate partialNegativeModel = asPartialNegativeModel/1;
54+
5155
/**
5256
* Gets the value summary model for `api` with `input` and `output`.
5357
*/

csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class TargetApiSpecific extends DotNet::Callable {
5555

5656
predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
5757

58+
predicate asPartialNegativeModel = DataFlowPrivate::Csv::asPartialNegativeModel/1;
59+
5860
/**
5961
* Holds for type `t` for fields that are relevant as an intermediate
6062
* read or write step in the data flow analysis.

0 commit comments

Comments
 (0)