Skip to content

Commit 2846d80

Browse files
authored
Merge pull request #359 from calumgrant/cs/with-stubs
C#: Sources and sinks for ASP.NET Core
2 parents b743ee4 + c003150 commit 2846d80

File tree

28 files changed

+1357
-46
lines changed

28 files changed

+1357
-46
lines changed

change-notes/1.19/analysis-csharp.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
## General improvements
44

55
* Control flow graph improvements:
6-
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
6+
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
77
* Code that is only reachable from a constant failing assertion, such as `Debug.Assert(false)`, is considered to be unreachable.
8-
8+
99
## New queries
1010

1111
| **Query** | **Tags** | **Purpose** |
@@ -16,6 +16,7 @@
1616

1717
| Inconsistent lock sequence (`cs/inconsistent-lock-sequence`) | More results | This query now finds inconsistent lock sequences globally across calls. |
1818
| Local scope variable shadows member (`cs/local-shadows-member`) | Fewer results | Results have been removed where a constructor parameter shadows a member, because the parameter is probably used to initialize the member. |
19+
| Cross-site scripting (`cs/web/xss`) | More results | This query now finds cross-site scripting vulnerabilities in ASP.NET Core applications. |
1920
| *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* |
2021

2122

csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,3 +1746,28 @@ class SystemNetWebUtilityFlow extends LibraryTypeDataFlow, SystemNetWebUtility {
17461746
preservesValue = false
17471747
}
17481748
}
1749+
1750+
/**
1751+
* The `StringValues` class used in many .NET Core libraries. Requires special `LibraryTypeDataFlow` flow.
1752+
*/
1753+
class StringValues extends Struct {
1754+
StringValues() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") }
1755+
}
1756+
1757+
/**
1758+
* Custom flow through StringValues.StringValues library class
1759+
*/
1760+
class StringValuesFlow extends LibraryTypeDataFlow, StringValues {
1761+
override predicate callableFlow(
1762+
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
1763+
boolean preservesValue
1764+
) {
1765+
c = any(Callable ca | this = ca.getDeclaringType()) and
1766+
(
1767+
source = any(CallableFlowSourceArg a) or
1768+
source = any(CallableFlowSourceQualifier q)
1769+
) and
1770+
sink = any(CallableFlowSinkReturn r) and
1771+
preservesValue = false
1772+
}
1773+
}

csharp/ql/src/semmle/code/csharp/dataflow/flowsources/Remote.qll

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import semmle.code.csharp.frameworks.system.web.Services
1111
private import semmle.code.csharp.frameworks.system.web.ui.WebControls
1212
private import semmle.code.csharp.frameworks.WCF
1313
private import semmle.code.csharp.frameworks.microsoft.Owin
14+
private import semmle.code.csharp.frameworks.microsoft.AspNetCore
1415

1516
/** A data flow source of remote user input. */
1617
abstract class RemoteFlowSource extends DataFlow::Node {
@@ -28,9 +29,8 @@ class AspNetQueryStringMember extends Member {
2829
t instanceof SystemWebHttpRequestClass or
2930
t instanceof SystemNetHttpListenerRequestClass or
3031
t instanceof SystemWebHttpRequestBaseClass
31-
|
32-
this = t.getProperty(getHttpRequestFlowPropertyNames())
33-
or
32+
|
33+
this = t.getProperty(getHttpRequestFlowPropertyNames()) or
3434
this.(Field).getType() = t or
3535
this.(Property).getType() = t or
3636
this.(Callable).getReturnType() = t
@@ -61,47 +61,43 @@ class AspNetQueryStringRemoteFlowSource extends AspNetRemoteFlowSource, DataFlow
6161
t instanceof SystemWebHttpRequestClass or
6262
t instanceof SystemNetHttpListenerRequestClass or
6363
t instanceof SystemWebHttpRequestBaseClass
64-
|
64+
|
6565
// A request object can be indexed, so taint the object as well
6666
this.getExpr().getType() = t
6767
)
6868
or
6969
this.getExpr() = any(AspNetQueryStringMember m).getAnAccess()
7070
}
7171

72-
override
73-
string getSourceType() { result = "ASP.NET query string" }
72+
override string getSourceType() { result = "ASP.NET query string" }
7473
}
7574

7675
/** A data flow source of remote user input (ASP.NET unvalidated request data). */
77-
class AspNetUnvalidatedQueryStringRemoteFlowSource extends AspNetRemoteFlowSource, DataFlow::ExprNode {
76+
class AspNetUnvalidatedQueryStringRemoteFlowSource extends AspNetRemoteFlowSource,
77+
DataFlow::ExprNode {
7878
AspNetUnvalidatedQueryStringRemoteFlowSource() {
7979
this.getExpr() = any(SystemWebUnvalidatedRequestValues c).getAProperty().getGetter().getACall() or
80-
this.getExpr() = any(SystemWebUnvalidatedRequestValuesBase c).getAProperty().getGetter().getACall()
80+
this.getExpr() = any(SystemWebUnvalidatedRequestValuesBase c)
81+
.getAProperty()
82+
.getGetter()
83+
.getACall()
8184
}
8285

83-
override
84-
string getSourceType() { result = "ASP.NET unvalidated request data" }
86+
override string getSourceType() { result = "ASP.NET unvalidated request data" }
8587
}
8688

8789
/** A data flow source of remote user input (ASP.NET user input). */
8890
class AspNetUserInputRemoteFlowSource extends AspNetRemoteFlowSource, DataFlow::ExprNode {
89-
AspNetUserInputRemoteFlowSource() {
90-
getType() instanceof SystemWebUIWebControlsTextBoxClass
91-
}
91+
AspNetUserInputRemoteFlowSource() { getType() instanceof SystemWebUIWebControlsTextBoxClass }
9292

93-
override
94-
string getSourceType() { result = "ASP.NET user input" }
93+
override string getSourceType() { result = "ASP.NET user input" }
9594
}
9695

9796
/** A data flow source of remote user input (WCF based web service). */
9897
class WcfRemoteFlowSource extends RemoteFlowSource, DataFlow::ParameterNode {
99-
WcfRemoteFlowSource() {
100-
exists(OperationMethod om | om.getAParameter() = this.getParameter())
101-
}
98+
WcfRemoteFlowSource() { exists(OperationMethod om | om.getAParameter() = this.getParameter()) }
10299

103-
override
104-
string getSourceType() { result = "web service input" }
100+
override string getSourceType() { result = "web service input" }
105101
}
106102

107103
/** A data flow source of remote user input (ASP.NET web service). */
@@ -113,8 +109,7 @@ class AspNetServiceRemoteFlowSource extends RemoteFlowSource, DataFlow::Paramete
113109
)
114110
}
115111

116-
override
117-
string getSourceType() { result = "ASP.NET web service input" }
112+
override string getSourceType() { result = "ASP.NET web service input" }
118113
}
119114

120115
/** A data flow source of remote user input (ASP.NET request message). */
@@ -123,8 +118,7 @@ class SystemNetHttpRequestMessageRemoteFlowSource extends RemoteFlowSource, Data
123118
getType() instanceof SystemWebHttpRequestMessageClass
124119
}
125120

126-
override
127-
string getSourceType() { result = "ASP.NET request message" }
121+
override string getSourceType() { result = "ASP.NET request message" }
128122
}
129123

130124
/**
@@ -136,17 +130,15 @@ class MicrosoftOwinStringFlowSource extends RemoteFlowSource, DataFlow::ExprNode
136130
this.getExpr() = any(MicrosoftOwinString owinString).getValueProperty().getGetter().getACall()
137131
}
138132

139-
override
140-
string getSourceType() { result = "Microsoft Owin request or query string" }
133+
override string getSourceType() { result = "Microsoft Owin request or query string" }
141134
}
142135

143-
/**
144-
* A data flow source of remote user input (`Microsoft Owin IOwinRequest`).
145-
*/
136+
/** A data flow source of remote user input (`Microsoft Owin IOwinRequest`). */
146137
class MicrosoftOwinRequestRemoteFlowSource extends RemoteFlowSource, DataFlow::ExprNode {
147138
MicrosoftOwinRequestRemoteFlowSource() {
148139
exists(Property p, MicrosoftOwinIOwinRequestClass owinRequest |
149-
this.getExpr() = p.getGetter().getACall() |
140+
this.getExpr() = p.getGetter().getACall()
141+
|
150142
p = owinRequest.getAcceptProperty() or
151143
p = owinRequest.getBodyProperty() or
152144
p = owinRequest.getCacheControlProperty() or
@@ -167,23 +159,62 @@ class MicrosoftOwinRequestRemoteFlowSource extends RemoteFlowSource, DataFlow::E
167159
)
168160
}
169161

170-
override
171-
string getSourceType() { result = "Microsoft Owin request" }
162+
override string getSourceType() { result = "Microsoft Owin request" }
172163
}
173164

174-
/**
175-
* A parameter to an Mvc controller action method, viewed as a source of remote user input.
176-
*/
165+
/** A parameter to an Mvc controller action method, viewed as a source of remote user input. */
177166
class ActionMethodParameter extends RemoteFlowSource, DataFlow::ParameterNode {
178167
ActionMethodParameter() {
179168
exists(Parameter p |
180169
p = this.getParameter() and
181-
p.fromSource() |
170+
p.fromSource()
171+
|
182172
p = any(Controller c).getAnActionMethod().getAParameter() or
183173
p = any(ApiController c).getAnActionMethod().getAParameter()
184174
)
185175
}
186176

187-
override
188-
string getSourceType() { result = "ASP.NET MVC action method parameter" }
177+
override string getSourceType() { result = "ASP.NET MVC action method parameter" }
178+
}
179+
180+
/** A data flow source of remote user input (ASP.NET Core). */
181+
abstract class AspNetCoreRemoteFlowSource extends RemoteFlowSource { }
182+
183+
/** A data flow source of remote user input (ASP.NET query collection). */
184+
class AspNetCoreQueryRemoteFlowSource extends AspNetCoreRemoteFlowSource, DataFlow::ExprNode {
185+
AspNetCoreQueryRemoteFlowSource() {
186+
exists(ValueOrRefType t |
187+
t instanceof MicrosoftAspNetCoreHttpHttpRequest or
188+
t instanceof MicrosoftAspNetCoreHttpQueryCollection or
189+
t instanceof MicrosoftAspNetCoreHttpQueryString
190+
|
191+
this.getExpr().(Call).getTarget().getDeclaringType() = t or
192+
this.asExpr().(Access).getTarget().getDeclaringType() = t
193+
)
194+
or
195+
exists(Call c |
196+
c
197+
.getTarget()
198+
.getDeclaringType()
199+
.hasQualifiedName("Microsoft.AspNetCore.Http", "IQueryCollection") and
200+
c.getTarget().getName() = "TryGetValue" and
201+
this.asExpr() = c.getArgumentForName("value")
202+
)
203+
}
204+
205+
override string getSourceType() { result = "ASP.NET Core query string" }
206+
}
207+
208+
/** A parameter to a `Mvc` controller action method, viewed as a source of remote user input. */
209+
class AspNetCoreActionMethodParameter extends RemoteFlowSource, DataFlow::ParameterNode {
210+
AspNetCoreActionMethodParameter() {
211+
exists(Parameter p |
212+
p = this.getParameter() and
213+
p.fromSource()
214+
|
215+
p = any(MicrosoftAspNetCoreMvcController c).getAnActionMethod().getAParameter()
216+
)
217+
}
218+
219+
override string getSourceType() { result = "ASP.NET Core MVC action method parameter" }
189220
}

0 commit comments

Comments
 (0)