Skip to content

Commit 9893650

Browse files
authored
Merge pull request #8604 from erik-krogh/httpNode
JS: refactor most library models away from AST nodes
2 parents 25b988d + 4e14177 commit 9893650

File tree

153 files changed

+1916
-1155
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+1916
-1155
lines changed

javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CoreKnowledge.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ predicate isOtherModeledArgument(DataFlow::Node n, FilteringReason reason) {
175175
or
176176
n instanceof CryptographicKey and reason instanceof CryptographicKeyReason
177177
or
178-
any(CryptographicOperation op).getInput().flow() = n and
178+
any(CryptographicOperation op).getInput() = n and
179179
reason instanceof CryptographicOperationFlowReason
180180
or
181181
exists(DataFlow::CallNode call | n = call.getAnArgument() |

javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ private module AccessPaths {
144144
not param = base.getReceiver()
145145
|
146146
result = param and
147-
name = param.asSource().asExpr().(Parameter).getName()
147+
name = param.asSource().(DataFlow::ParameterNode).getName()
148148
or
149149
param.asSource().asExpr() instanceof DestructuringPattern and
150150
result = param.getMember(name)

javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ module SinkEndpointFilter {
4242
result = "modeled database access"
4343
or
4444
// Remove calls to APIs that aren't relevant to NoSQL injection
45-
call.getReceiver().asExpr() instanceof HTTP::RequestExpr and
45+
call.getReceiver() instanceof HTTP::RequestNode and
4646
result = "receiver is a HTTP request expression"
4747
or
48-
call.getReceiver().asExpr() instanceof HTTP::ResponseExpr and
48+
call.getReceiver() instanceof HTTP::ResponseNode and
4949
result = "receiver is a HTTP response expression"
5050
)
5151
or
@@ -115,7 +115,7 @@ predicate isBaseAdditionalFlowStep(
115115
inlbl = TaintedObject::label() and
116116
outlbl = TaintedObject::label() and
117117
exists(NoSql::Query query, DataFlow::SourceNode queryObj |
118-
queryObj.flowsToExpr(query) and
118+
queryObj.flowsTo(query) and
119119
queryObj.flowsTo(trg) and
120120
src = queryObj.getAPropertyWrite().getRhs()
121121
)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
category: breaking
3+
---
4+
* Many library models have been rewritten to use dataflow nodes instead of the AST.
5+
The types of some classes have been changed, and these changes may break existing code.
6+
Other classes and predicates have been renamed, in these cases the old name is still available as a deprecated feature.
7+
8+
* The basetype of the following list of classes has changed from an expression to a dataflow node, and thus code using these classes might break.
9+
The fix to these breakages is usually to use `asExpr()` to get an expression from a dataflow node, or to use `.flow()` to get a dataflow node from an expression.
10+
- DOM.qll#WebStorageWrite
11+
- CryptoLibraries.qll#CryptographicOperation
12+
- Express.qll#Express::RequestBodyAccess
13+
- HTTP.qll#HTTP::ResponseBody
14+
- HTTP.qll#HTTP::CookieDefinition
15+
- HTTP.qll#HTTP::ServerDefinition
16+
- HTTP.qll#HTTP::RouteSetup
17+
- NoSQL.qll#NoSql::Query
18+
- SQL.qll#SQL::SqlString
19+
- SQL.qll#SQL::SqlSanitizer
20+
- HTTP.qll#ResponseBody
21+
- HTTP.qll#CookieDefinition
22+
- HTTP.qll#ServerDefinition
23+
- HTTP.qll#RouteSetup
24+
- HTTP.qll#HTTP::RedirectInvocation
25+
- HTTP.qll#RedirectInvocation
26+
- Express.qll#Express::RouterDefinition
27+
- AngularJSCore.qll#LinkFunction
28+
- Connect.qll#Connect::StandardRouteHandler
29+
- CryptoLibraries.qll#CryptographicKeyCredentialsExpr
30+
- AWS.qll#AWS::Credentials
31+
- Azure.qll#Azure::Credentials
32+
- Connect.qll#Connect::Credentials
33+
- DigitalOcean.qll#DigitalOcean::Credentials
34+
- Express.qll#Express::Credentials
35+
- NodeJSLib.qll#NodeJSLib::Credentials
36+
- PkgCloud.qll#PkgCloud::Credentials
37+
- Request.qll#Request::Credentials
38+
- ServiceDefinitions.qll#InjectableFunctionServiceRequest
39+
- SensitiveActions.qll#SensitiveVariableAccess
40+
- SensitiveActions.qll#CleartextPasswordExpr
41+
- Connect.qll#Connect::ServerDefinition
42+
- Restify.qll#Restify::ServerDefinition
43+
- Connect.qll#Connect::RouteSetup
44+
- Express.qll#Express::RouteSetup
45+
- Fastify.qll#Fastify::RouteSetup
46+
- Hapi.qll#Hapi::RouteSetup
47+
- Koa.qll#Koa::RouteSetup
48+
- Restify.qll#Restify::RouteSetup
49+
- NodeJSLib.qll#NodeJSLib::RouteSetup
50+
- Express.qll#Express::StandardRouteHandler
51+
- Express.qll#Express::SetCookie
52+
- Hapi.qll#Hapi::RouteHandler
53+
- HTTP.qll#HTTP::Servers::StandardHeaderDefinition
54+
- HTTP.qll#Servers::StandardHeaderDefinition
55+
- Hapi.qll#Hapi::ServerDefinition
56+
- Koa.qll#Koa::AppDefinition
57+
- SensitiveActions.qll#SensitiveCall

javascript/ql/lib/semmle/javascript/Expr.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
167167
/**
168168
* Holds if this expression may refer to the initial value of parameter `p`.
169169
*/
170-
predicate mayReferToParameter(Parameter p) { this.flow().mayReferToParameter(p) }
170+
predicate mayReferToParameter(Parameter p) { DataFlow::parameterNode(p).flowsToExpr(this) }
171171

172172
/**
173173
* Gets the static type of this expression, as determined by the TypeScript type system.

javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,12 @@ module DataFlow {
139139
}
140140

141141
/**
142+
* DEPRECATED: Use `DataFlow::ParameterNode::flowsTo()` instead.
142143
* Holds if this expression may refer to the initial value of parameter `p`.
143144
*/
144-
predicate mayReferToParameter(Parameter p) { parameterNode(p).(SourceNode).flowsTo(this) }
145+
deprecated predicate mayReferToParameter(Parameter p) {
146+
parameterNode(p).(SourceNode).flowsTo(this)
147+
}
145148

146149
/**
147150
* Holds if this element is at the specified location.

javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,12 @@ class FunctionNode extends DataFlow::ValueNode, DataFlow::SourceNode {
472472
/** Gets a parameter of this function. */
473473
ParameterNode getAParameter() { result = this.getParameter(_) }
474474

475+
/** Gets the parameter named `name` of this function, if any. */
476+
DataFlow::ParameterNode getParameterByName(string name) {
477+
result = this.getAParameter() and
478+
result.getName() = name
479+
}
480+
475481
/** Gets the number of parameters declared on this function. */
476482
int getNumParameter() { result = count(astNode.getAParameter()) }
477483

@@ -556,6 +562,14 @@ class ObjectLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode {
556562
DataFlow::FunctionNode getPropertySetter(string name) {
557563
result = astNode.getPropertyByName(name).(PropertySetter).getInit().flow()
558564
}
565+
566+
/** Gets the value of a computed property name of this object literal, such as `x` in `{[x]: 1}` */
567+
DataFlow::Node getAComputedPropertyName() {
568+
exists(Property prop | prop = astNode.getAProperty() |
569+
prop.isComputed() and
570+
result = prop.getNameExpr().flow()
571+
)
572+
}
559573
}
560574

561575
/**

javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -482,17 +482,13 @@ module TaintTracking {
482482
*/
483483
private class HeapTaintStep extends SharedTaintStep {
484484
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
485-
exists(Expr e, Expr f | e = succ.asExpr() and f = pred.asExpr() |
486-
exists(Property prop | e.(ObjectExpr).getAProperty() = prop |
487-
prop.isComputed() and f = prop.getNameExpr()
488-
)
489-
or
490-
// spreading a tainted object into an object literal gives a tainted object
491-
e.(ObjectExpr).getAProperty().(SpreadProperty).getInit().(SpreadElement).getOperand() = f
492-
or
493-
// spreading a tainted value into an array literal gives a tainted array
494-
e.(ArrayExpr).getAnElement().(SpreadElement).getOperand() = f
495-
)
485+
succ.(DataFlow::ObjectLiteralNode).getAComputedPropertyName() = pred
486+
or
487+
// spreading a tainted object into an object literal gives a tainted object
488+
succ.(DataFlow::ObjectLiteralNode).getASpreadProperty() = pred
489+
or
490+
// spreading a tainted value into an array literal gives a tainted array
491+
succ.(DataFlow::ArrayCreationNode).getASpreadArgument() = pred
496492
or
497493
// arrays with tainted elements and objects with tainted property names are tainted
498494
succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and
@@ -546,16 +542,16 @@ module TaintTracking {
546542
*/
547543
private class ComputedPropWriteTaintStep extends SharedTaintStep {
548544
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
549-
exists(AssignExpr assgn, IndexExpr idx, DataFlow::SourceNode obj |
550-
assgn.getTarget() = idx and
551-
obj.flowsToExpr(idx.getBase()) and
552-
not exists(idx.getPropertyName()) and
553-
pred = DataFlow::valueNode(assgn.getRhs()) and
545+
exists(DataFlow::PropWrite assgn, DataFlow::SourceNode obj |
546+
not exists(assgn.getPropertyName()) and
547+
not assgn.getWriteNode() instanceof Property and // not a write inside an object literal
548+
pred = assgn.getRhs() and
549+
assgn = obj.getAPropertyWrite() and
554550
succ = obj
555551
|
556552
obj instanceof DataFlow::ObjectLiteralNode
557553
or
558-
obj.getAPropertyRead("length").flowsToExpr(idx.getPropertyNameExpr())
554+
obj.getAPropertyRead("length").flowsToExpr(assgn.getPropertyNameExpr())
559555
)
560556
}
561557
}
@@ -580,8 +576,8 @@ module TaintTracking {
580576
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node target) {
581577
exists(DataFlow::ValueNode succ | target = succ |
582578
// string operations that propagate taint
583-
exists(string name | name = succ.getAstNode().(MethodCallExpr).getMethodName() |
584-
pred.asExpr() = succ.getAstNode().(MethodCallExpr).getReceiver() and
579+
exists(string name | name = succ.(DataFlow::MethodCallNode).getMethodName() |
580+
pred = succ.(DataFlow::MethodCallNode).getReceiver() and
585581
(
586582
// sorted, interesting, properties of String.prototype
587583
name =
@@ -600,7 +596,7 @@ module TaintTracking {
600596
name = "join"
601597
)
602598
or
603-
exists(int i | pred.asExpr() = succ.getAstNode().(MethodCallExpr).getArgument(i) |
599+
exists(int i | pred = succ.(DataFlow::MethodCallNode).getArgument(i) |
604600
name = "concat"
605601
or
606602
name = ["replace", "replaceAll"] and i = 1
@@ -615,10 +611,10 @@ module TaintTracking {
615611
)
616612
or
617613
// String.fromCharCode and String.fromCodePoint
618-
exists(int i, MethodCallExpr mce |
619-
mce = succ.getAstNode() and
620-
pred.asExpr() = mce.getArgument(i) and
621-
(mce.getMethodName() = "fromCharCode" or mce.getMethodName() = "fromCodePoint")
614+
exists(int i, DataFlow::MethodCallNode mcn |
615+
mcn = succ and
616+
pred = mcn.getArgument(i) and
617+
mcn.getMethodName() = ["fromCharCode", "fromCodePoint"]
622618
)
623619
or
624620
// `(encode|decode)URI(Component)?` propagate taint
@@ -744,11 +740,11 @@ module TaintTracking {
744740
* the parameters in `input`.
745741
*/
746742
predicate isUrlSearchParams(DataFlow::SourceNode params, DataFlow::Node input) {
747-
exists(DataFlow::GlobalVarRefNode urlSearchParams, NewExpr newUrlSearchParams |
743+
exists(DataFlow::GlobalVarRefNode urlSearchParams, DataFlow::NewNode newUrlSearchParams |
748744
urlSearchParams.getName() = "URLSearchParams" and
749-
newUrlSearchParams = urlSearchParams.getAnInstantiation().asExpr() and
750-
params.asExpr() = newUrlSearchParams and
751-
input.asExpr() = newUrlSearchParams.getArgument(0)
745+
newUrlSearchParams = urlSearchParams.getAnInstantiation() and
746+
params = newUrlSearchParams and
747+
input = newUrlSearchParams.getArgument(0)
752748
)
753749
}
754750

javascript/ql/lib/semmle/javascript/frameworks/AWS.qll

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ module AWS {
88
/**
99
* Holds if the `i`th argument of `invk` is an object hash for `AWS.Config`.
1010
*/
11-
private predicate takesConfigurationObject(InvokeExpr invk, int i) {
11+
private predicate takesConfigurationObject(DataFlow::InvokeNode invk, int i) {
1212
exists(DataFlow::ModuleImportNode mod | mod.getPath() = "aws-sdk" |
1313
// `AWS.config.update(nd)`
14-
invk = mod.getAPropertyRead("config").getAMemberCall("update").asExpr() and
14+
invk = mod.getAPropertyRead("config").getAMemberCall("update") and
1515
i = 0
1616
or
1717
exists(DataFlow::SourceNode cfg | cfg = mod.getAConstructorInvocation("Config") |
1818
// `new AWS.Config(nd)`
19-
invk = cfg.asExpr() and
19+
invk = cfg and
2020
i = 0
2121
or
2222
// `var config = new AWS.Config(...); config.update(nd);`
23-
invk = cfg.getAMemberCall("update").asExpr() and
23+
invk = cfg.getAMemberCall("update") and
2424
i = 0
2525
)
2626
)
@@ -29,13 +29,13 @@ module AWS {
2929
/**
3030
* An expression that is used as an AWS config value: `{ accessKeyId: <user>, secretAccessKey: <password>}`.
3131
*/
32-
class Credentials extends CredentialsExpr {
32+
class Credentials extends CredentialsNode {
3333
string kind;
3434

3535
Credentials() {
36-
exists(string prop, InvokeExpr invk, int i |
36+
exists(string prop, DataFlow::InvokeNode invk, int i |
3737
takesConfigurationObject(invk, i) and
38-
invk.hasOptionArgument(i, prop, this)
38+
this = invk.getOptionArgument(i, prop)
3939
|
4040
prop = "accessKeyId" and kind = "user name"
4141
or

0 commit comments

Comments
 (0)