Skip to content

Commit 8dc95ce

Browse files
authored
Merge pull request github#16722 from michaelnebel/csharp/modelgensourcesink
C#/Java: Respect manual neutrals, sources and sinks in model generation.
2 parents 58b6b3f + 24685a0 commit 8dc95ce

24 files changed

+204
-88
lines changed

csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010
import internal.CaptureModels
1111
import internal.CaptureSummaryFlowQuery
1212

13-
from DataFlowTargetApi api, string noflow
13+
from DataFlowSummaryTargetApi api, string noflow
1414
where noflow = captureNoFlow(api)
1515
select noflow order by noflow

csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql

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

99
import internal.CaptureModels
1010

11-
from DataFlowTargetApi api, string sink
11+
from DataFlowSinkTargetApi api, string sink
1212
where sink = captureSink(api)
1313
select sink order by sink

csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql

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

99
import internal.CaptureModels
1010

11-
from DataFlowTargetApi api, string source
11+
from DataFlowSourceTargetApi api, string source
1212
where source = captureSource(api)
1313
select source order by source

csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010
import internal.CaptureModels
1111
import internal.CaptureSummaryFlowQuery
1212

13-
from DataFlowTargetApi api, string flow
13+
from DataFlowSummaryTargetApi api, string flow
1414
where flow = captureFlow(api)
1515
select flow order by flow

csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ private class ReturnNodeExt extends DataFlow::Node {
2929
}
3030
}
3131

32-
class DataFlowTargetApi extends TargetApiSpecific {
33-
DataFlowTargetApi() { not isUninterestingForDataFlowModels(this) }
32+
class DataFlowSummaryTargetApi extends SummaryTargetApi {
33+
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
3434
}
3535

36+
class DataFlowSourceTargetApi = SourceTargetApi;
37+
38+
class DataFlowSinkTargetApi = SinkTargetApi;
39+
3640
private module ModelPrintingInput implements ModelPrintingSig {
37-
class Api = DataFlowTargetApi;
41+
class Api = TargetApiBase;
3842

3943
string getProvenance() { result = "df-generated" }
4044
}
@@ -89,7 +93,7 @@ string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific
8993
/**
9094
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
9195
*/
92-
string captureQualifierFlow(TargetApiSpecific api) {
96+
string captureQualifierFlow(DataFlowSummaryTargetApi api) {
9397
exists(ReturnNodeExt ret |
9498
api = returnNodeEnclosingCallable(ret) and
9599
isOwnInstanceAccessNode(ret)
@@ -150,7 +154,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
150154

151155
predicate isSource(DataFlow::Node source, FlowState state) {
152156
source instanceof DataFlow::ParameterNode and
153-
source.getEnclosingCallable() instanceof DataFlowTargetApi and
157+
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi and
154158
state.(TaintRead).getStep() = 0
155159
}
156160

@@ -195,7 +199,7 @@ private module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfi
195199
/**
196200
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
197201
*/
198-
string captureThroughFlow(DataFlowTargetApi api) {
202+
string captureThroughFlow(DataFlowSummaryTargetApi api) {
199203
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output |
200204
PropagateFlow::flow(p, returnNodeExt) and
201205
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
@@ -222,10 +226,8 @@ module PropagateFromSourceConfig implements DataFlow::ConfigSig {
222226
}
223227

224228
predicate isSink(DataFlow::Node sink) {
225-
exists(DataFlowTargetApi c |
226-
sink instanceof ReturnNodeExt and
227-
sink.getEnclosingCallable() = c
228-
)
229+
sink instanceof ReturnNodeExt and
230+
sink.getEnclosingCallable() instanceof DataFlowSourceTargetApi
229231
}
230232

231233
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext }
@@ -244,7 +246,7 @@ private module PropagateFromSource = TaintTracking::Global<PropagateFromSourceCo
244246
/**
245247
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
246248
*/
247-
string captureSource(DataFlowTargetApi api) {
249+
string captureSource(DataFlowSourceTargetApi api) {
248250
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
249251
PropagateFromSource::flow(source, sink) and
250252
ExternalFlow::sourceNode(source, kind) and
@@ -262,7 +264,9 @@ string captureSource(DataFlowTargetApi api) {
262264
* into an existing known sink (then the API itself becomes a sink).
263265
*/
264266
module PropagateToSinkConfig implements DataFlow::ConfigSig {
265-
predicate isSource(DataFlow::Node source) { apiSource(source) }
267+
predicate isSource(DataFlow::Node source) {
268+
apiSource(source) and source.getEnclosingCallable() instanceof DataFlowSinkTargetApi
269+
}
266270

267271
predicate isSink(DataFlow::Node sink) {
268272
exists(string kind | isRelevantSinkKind(kind) and ExternalFlow::sinkNode(sink, kind))
@@ -286,7 +290,7 @@ private module PropagateToSink = TaintTracking::Global<PropagateToSinkConfig>;
286290
/**
287291
* Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink.
288292
*/
289-
string captureSink(DataFlowTargetApi api) {
293+
string captureSink(DataFlowSinkTargetApi api) {
290294
exists(DataFlow::Node src, DataFlow::Node sink, string kind |
291295
PropagateToSink::flow(src, sink) and
292296
ExternalFlow::sinkNode(sink, kind) and

csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,21 @@ private Callable liftedImpl(Callable api) {
8282
not exists(getARelevantOverrideeOrImplementee(result))
8383
}
8484

85-
private predicate hasManualModel(Callable api) {
85+
private predicate hasManualSummaryModel(Callable api) {
8686
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
8787
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
8888
}
8989

90+
private predicate hasManualSourceModel(Callable api) {
91+
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
92+
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
93+
}
94+
95+
private predicate hasManualSinkModel(Callable api) {
96+
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
97+
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
98+
}
99+
90100
/**
91101
* Holds if it is irrelevant to generate models for `api` based on data flow analysis.
92102
*
@@ -101,20 +111,39 @@ predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api
101111
*/
102112
predicate isUninterestingForTypeBasedFlowModels(CS::Callable api) { none() }
103113

114+
/**
115+
* A class of callables that are potentially relevant for generating summary and
116+
* neutral models.
117+
*/
118+
class SummaryTargetApi extends TargetApiBase {
119+
SummaryTargetApi() { not hasManualSummaryModel(this.lift()) }
120+
}
121+
122+
/**
123+
* A class of callables that are potentially relevant for generating sink models.
124+
*/
125+
class SinkTargetApi extends TargetApiBase {
126+
SinkTargetApi() { not hasManualSinkModel(this.lift()) }
127+
}
128+
129+
/**
130+
* A class of callables that are potentially relevant for generating source models.
131+
*/
132+
class SourceTargetApi extends TargetApiBase {
133+
SourceTargetApi() { not hasManualSourceModel(this.lift()) }
134+
}
135+
104136
/**
105137
* A class of callables that are potentially relevant for generating summary, source, sink
106138
* and neutral models.
107139
*
108140
* In the Standard library and 3rd party libraries it is the callables (or callables that have a
109141
* super implementation) that can be called from outside the library itself.
110142
*/
111-
class TargetApiSpecific extends Callable {
143+
class TargetApiBase extends Callable {
112144
private Callable lift;
113145

114-
TargetApiSpecific() {
115-
lift = liftedImpl(this) and
116-
not hasManualModel(lift)
117-
}
146+
TargetApiBase() { lift = liftedImpl(this) }
118147

119148
/**
120149
* Gets the callable that a model will be lifted to.
@@ -233,24 +262,11 @@ private predicate isRelevantMemberAccess(DataFlow::Node node) {
233262

234263
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
235264

236-
private class ManualNeutralSinkCallable extends Callable {
237-
ManualNeutralSinkCallable() {
238-
this =
239-
any(FlowSummaryImpl::Public::NeutralCallable nc |
240-
nc.hasManualModel() and nc.getKind() = "sink"
241-
)
242-
}
243-
}
244-
245265
/**
246266
* Holds if `source` is an api entrypoint relevant for creating sink models.
247267
*/
248268
predicate apiSource(DataFlow::Node source) {
249-
(isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode) and
250-
exists(Callable enclosing | enclosing = source.getEnclosingCallable() |
251-
relevant(enclosing) and
252-
not enclosing instanceof ManualNeutralSinkCallable
253-
)
269+
isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode
254270
}
255271

256272
private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) {
@@ -269,7 +285,7 @@ private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2)
269285
* if flow is detected from a node within `source` to a sink within `api`.
270286
*/
271287
bindingset[sourceEnclosing, api]
272-
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, TargetApiSpecific api) {
288+
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) {
273289
not exists(DataFlowCallable dc1, DataFlowCallable dc2 | uniquelyCallsPlus(dc1, dc2) or dc1 = dc2 |
274290
dc1.getUnderlyingCallable() = api and
275291
dc2.getUnderlyingCallable() = sourceEnclosing
@@ -299,4 +315,4 @@ predicate isRelevantSinkKind(string kind) { any() }
299315
* Holds if `kind` is a relevant source kind for creating source models.
300316
*/
301317
bindingset[kind]
302-
predicate isRelevantSourceKind(string kind) { not kind = "file" }
318+
predicate isRelevantSourceKind(string kind) { any() }

csharp/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private import CaptureModels
7575
* Captured Model:
7676
* ```Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint;df-generated```
7777
*/
78-
string captureFlow(DataFlowTargetApi api) {
78+
string captureFlow(DataFlowSummaryTargetApi api) {
7979
result = captureQualifierFlow(api) or
8080
result = captureThroughFlow(api)
8181
}
@@ -86,8 +86,8 @@ string captureFlow(DataFlowTargetApi api) {
8686
* a summary model that applies to `api` and if it relevant to generate
8787
* a model for `api`.
8888
*/
89-
string captureNoFlow(DataFlowTargetApi api) {
90-
not exists(DataFlowTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and
89+
string captureNoFlow(DataFlowSummaryTargetApi api) {
90+
not exists(DataFlowSummaryTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and
9191
api.isRelevant() and
9292
result = Printing::asNeutralSummaryModel(api)
9393
}

csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ private module Printing = ModelPrinting<ModelPrintingInput>;
189189
* A class of callables that are relevant generating summaries for based
190190
* on the Theorems for Free approach.
191191
*/
192-
class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
192+
class TypeBasedFlowTargetApi extends Specific::SummaryTargetApi {
193193
TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) }
194194

195195
/**

csharp/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.ext.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ extensions:
44
extensible: sinkModel
55
data:
66
- [ "Sinks", "NewSinks", False, "Sink", "(System.Object)", "", "Argument[0]", "test-sink", "manual"]
7+
- [ "Sinks", "NewSinks", False, "ManualSinkAlreadyDefined", "(System.Object)", "", "Argument[0]", "test-sink", "manual"]
8+
9+
- addsTo:
10+
pack: codeql/csharp-all
11+
extensible: neutralModel
12+
data:
13+
- [ "Sinks", "NewSinks", "ManualSinkNeutral", "(System.Object)", "sink", "manual" ]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/csharp-all
4+
extensible: sourceModel
5+
data:
6+
- ["Sources", "NewSources", False, "ManualSourceAlreadyDefined", "()", "", "ReturnValue", "test-source", "manual"]
7+
8+
- addsTo:
9+
pack: codeql/csharp-all
10+
extensible: neutralModel
11+
data:
12+
- ["Sources", "NewSources", "ManualNeutralSource", "()", "source", "manual"]

0 commit comments

Comments
 (0)