@@ -8,6 +8,7 @@ private import semmle.code.csharp.commons.Collections as Collections
88private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
99private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010private import semmle.code.csharp.frameworks.system.linq.Expressions
11+ private import semmle.code.csharp.frameworks.System
1112import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
1213import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
1314import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -19,10 +20,12 @@ module TaintTracking = CS::TaintTracking;
1920
2021class Type = CS:: Type ;
2122
23+ class Callable = CS:: Callable ;
24+
2225/**
2326 * Holds if any of the parameters of `api` are `System.Func<>`.
2427 */
25- private predicate isHigherOrder ( CS :: Callable api ) {
28+ private predicate isHigherOrder ( Callable api ) {
2629 exists ( Type t | t = api .getAParameter ( ) .getType ( ) .getUnboundDeclaration ( ) |
2730 t instanceof SystemLinqExpressions:: DelegateExtType
2831 )
@@ -32,23 +35,56 @@ private predicate irrelevantAccessor(CS::Accessor a) {
3235 a .getDeclaration ( ) .( CS:: Property ) .isReadWrite ( )
3336}
3437
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
4956 // Disregard properties that have both a get and a set accessor,
5057 // 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 ( ) )
5288}
5389
5490/**
@@ -66,23 +102,37 @@ predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api
66102predicate isUninterestingForTypeBasedFlowModels ( CS:: Callable api ) { none ( ) }
67103
68104/**
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.
70107 *
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.
73110 */
74- class TargetApiSpecific extends CS:: Callable {
111+ class TargetApiSpecific extends Callable {
112+ private Callable lift ;
113+
75114 TargetApiSpecific ( ) {
76- this .fromSource ( ) and
77- this .isUnboundDeclaration ( ) and
78- isRelevantForModels ( this )
115+ lift = liftedImpl ( this ) and
116+ not hasManualModel ( lift )
79117 }
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 ) }
80131}
81132
82- predicate asPartialModel = ExternalFlow:: asPartialModel / 1 ;
133+ string asPartialModel ( TargetApiSpecific api ) { result = ExternalFlow:: asPartialModel ( api . lift ( ) ) }
83134
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 ) }
86136
87137/**
88138 * 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) {
151201/**
152202 * Gets the enclosing callable of `ret`.
153203 */
154- CS :: Callable returnNodeEnclosingCallable ( DataFlow:: Node ret ) {
204+ Callable returnNodeEnclosingCallable ( DataFlow:: Node ret ) {
155205 result = DataFlowImplCommon:: getNodeEnclosingCallable ( ret ) .asCallable ( )
156206}
157207
@@ -176,12 +226,24 @@ private predicate isRelevantMemberAccess(DataFlow::Node node) {
176226
177227predicate sinkModelSanitizer ( DataFlow:: Node node ) { none ( ) }
178228
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+
179238/**
180239 * Holds if `source` is an api entrypoint relevant for creating sink models.
181240 */
182241predicate apiSource ( DataFlow:: Node source ) {
183242 ( 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+ )
185247}
186248
187249/**
0 commit comments