@@ -8,6 +8,7 @@ private import semmle.code.csharp.commons.Collections as Collections
8
8
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
9
9
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
10
10
private import semmle.code.csharp.frameworks.system.linq.Expressions
11
+ private import semmle.code.csharp.frameworks.System
11
12
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
12
13
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
13
14
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -19,10 +20,12 @@ module TaintTracking = CS::TaintTracking;
19
20
20
21
class Type = CS:: Type ;
21
22
23
+ class Callable = CS:: Callable ;
24
+
22
25
/**
23
26
* Holds if any of the parameters of `api` are `System.Func<>`.
24
27
*/
25
- private predicate isHigherOrder ( CS :: Callable api ) {
28
+ private predicate isHigherOrder ( Callable api ) {
26
29
exists ( Type t | t = api .getAParameter ( ) .getType ( ) .getUnboundDeclaration ( ) |
27
30
t instanceof SystemLinqExpressions:: DelegateExtType
28
31
)
@@ -32,23 +35,56 @@ private predicate irrelevantAccessor(CS::Accessor a) {
32
35
a .getDeclaration ( ) .( CS:: Property ) .isReadWrite ( )
33
36
}
34
37
35
- /**
36
- * Holds if it is relevant to generate models for `api`.
37
- */
38
- private predicate isRelevantForModels ( CS:: Callable api ) {
39
- [ api .( CS:: Modifiable ) , api .( CS:: Accessor ) .getDeclaration ( ) ] .isEffectivelyPublic ( ) and
40
- api .getDeclaringType ( ) .getNamespace ( ) .getFullName ( ) != "" and
41
- not api instanceof CS:: ConversionOperator and
42
- not api instanceof Util:: MainMethod and
43
- not api instanceof CS:: Destructor and
44
- not api instanceof CS:: AnonymousFunctionExpr and
45
- not api .( CS:: Constructor ) .isParameterless ( ) and
46
- // Disregard all APIs that have a manual model.
47
- not api = any ( FlowSummaryImpl:: Public:: SummarizedCallable sc | sc .applyManualModel ( ) ) and
48
- not api = any ( FlowSummaryImpl:: Public:: NeutralSummaryCallable sc | sc .hasManualModel ( ) ) and
38
+ private predicate isUninterestingForModels ( Callable api ) {
39
+ api .getDeclaringType ( ) .getNamespace ( ) .getFullName ( ) = ""
40
+ or
41
+ api instanceof CS:: ConversionOperator
42
+ or
43
+ api instanceof Util:: MainMethod
44
+ or
45
+ api instanceof CS:: Destructor
46
+ or
47
+ api instanceof CS:: AnonymousFunctionExpr
48
+ or
49
+ api .( CS:: Constructor ) .isParameterless ( )
50
+ or
51
+ exists ( Type decl | decl = api .getDeclaringType ( ) |
52
+ decl instanceof SystemObjectClass or
53
+ decl instanceof SystemValueTypeClass
54
+ )
55
+ or
49
56
// Disregard properties that have both a get and a set accessor,
50
57
// which implicitly means auto implemented properties.
51
- not irrelevantAccessor ( api )
58
+ irrelevantAccessor ( api )
59
+ }
60
+
61
+ private predicate relevant ( Callable api ) {
62
+ [ api .( CS:: Modifiable ) , api .( CS:: Accessor ) .getDeclaration ( ) ] .isEffectivelyPublic ( ) and
63
+ api .fromSource ( ) and
64
+ api .isUnboundDeclaration ( ) and
65
+ not isUninterestingForModels ( api )
66
+ }
67
+
68
+ private Callable getARelevantOverrideeOrImplementee ( Overridable m ) {
69
+ m .overridesOrImplements ( result ) and relevant ( result )
70
+ }
71
+
72
+ /**
73
+ * Gets the super implementation of `api` if it is relevant.
74
+ * If such a super implementation does not exist, returns `api` if it is relevant.
75
+ */
76
+ private Callable liftedImpl ( Callable api ) {
77
+ (
78
+ result = getARelevantOverrideeOrImplementee ( api )
79
+ or
80
+ result = api and relevant ( api )
81
+ ) and
82
+ not exists ( getARelevantOverrideeOrImplementee ( result ) )
83
+ }
84
+
85
+ private predicate hasManualModel ( Callable api ) {
86
+ api = any ( FlowSummaryImpl:: Public:: SummarizedCallable sc | sc .applyManualModel ( ) ) or
87
+ api = any ( FlowSummaryImpl:: Public:: NeutralSummaryCallable sc | sc .hasManualModel ( ) )
52
88
}
53
89
54
90
/**
@@ -66,23 +102,37 @@ predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api
66
102
predicate isUninterestingForTypeBasedFlowModels ( CS:: Callable api ) { none ( ) }
67
103
68
104
/**
69
- * A class of callables that are relevant generating summary, source and sinks models for.
105
+ * A class of callables that are potentially relevant for generating summary, source, sink
106
+ * and neutral models.
70
107
*
71
- * In the Standard library and 3rd party libraries it the callables that can be called
72
- * from outside the library itself.
108
+ * In the Standard library and 3rd party libraries it is the callables (or callables that have a
109
+ * super implementation) that can be called from outside the library itself.
73
110
*/
74
- class TargetApiSpecific extends CS:: Callable {
111
+ class TargetApiSpecific extends Callable {
112
+ private Callable lift ;
113
+
75
114
TargetApiSpecific ( ) {
76
- this .fromSource ( ) and
77
- this .isUnboundDeclaration ( ) and
78
- isRelevantForModels ( this )
115
+ lift = liftedImpl ( this ) and
116
+ not hasManualModel ( lift )
79
117
}
118
+
119
+ /**
120
+ * Gets the callable that a model will be lifted to.
121
+ *
122
+ * The lifted callable is relevant in terms of model
123
+ * generation (this is ensured by `liftedImpl`).
124
+ */
125
+ Callable lift ( ) { result = lift }
126
+
127
+ /**
128
+ * Holds if `this` is relevant in terms of model generation.
129
+ */
130
+ predicate isRelevant ( ) { relevant ( this ) }
80
131
}
81
132
82
- predicate asPartialModel = ExternalFlow:: asPartialModel / 1 ;
133
+ string asPartialModel ( TargetApiSpecific api ) { result = ExternalFlow:: asPartialModel ( api . lift ( ) ) }
83
134
84
- /** Computes the first 4 columns for neutral CSV rows of `c`. */
85
- predicate asPartialNeutralModel = ExternalFlow:: getSignature / 1 ;
135
+ string asPartialNeutralModel ( TargetApiSpecific api ) { result = ExternalFlow:: getSignature ( api ) }
86
136
87
137
/**
88
138
* Holds if `t` is a type that is generally used for bulk data in collection types.
@@ -151,7 +201,7 @@ string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
151
201
/**
152
202
* Gets the enclosing callable of `ret`.
153
203
*/
154
- CS :: Callable returnNodeEnclosingCallable ( DataFlow:: Node ret ) {
204
+ Callable returnNodeEnclosingCallable ( DataFlow:: Node ret ) {
155
205
result = DataFlowImplCommon:: getNodeEnclosingCallable ( ret ) .asCallable ( )
156
206
}
157
207
@@ -176,12 +226,24 @@ private predicate isRelevantMemberAccess(DataFlow::Node node) {
176
226
177
227
predicate sinkModelSanitizer ( DataFlow:: Node node ) { none ( ) }
178
228
229
+ private class ManualNeutralSinkCallable extends Callable {
230
+ ManualNeutralSinkCallable ( ) {
231
+ this =
232
+ any ( FlowSummaryImpl:: Public:: NeutralCallable nc |
233
+ nc .hasManualModel ( ) and nc .getKind ( ) = "sink"
234
+ )
235
+ }
236
+ }
237
+
179
238
/**
180
239
* Holds if `source` is an api entrypoint relevant for creating sink models.
181
240
*/
182
241
predicate apiSource ( DataFlow:: Node source ) {
183
242
( isRelevantMemberAccess ( source ) or source instanceof DataFlow:: ParameterNode ) and
184
- isRelevantForModels ( source .getEnclosingCallable ( ) )
243
+ exists ( Callable enclosing | enclosing = source .getEnclosingCallable ( ) |
244
+ relevant ( enclosing ) and
245
+ not enclosing instanceof ManualNeutralSinkCallable
246
+ )
185
247
}
186
248
187
249
/**
0 commit comments