Skip to content

Commit 289c298

Browse files
author
Esben Sparre Andreasen
committed
JS: split UnvalidatedDynamicMethodCall.qll
1 parent 9e675d9 commit 289c298

File tree

2 files changed

+123
-103
lines changed

2 files changed

+123
-103
lines changed
Lines changed: 8 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
/**
2-
* Provides a taint-tracking configuration for reasoning about unvalidated dynamic
3-
* method calls.
2+
* Provides a taint-tracking configuration for reasoning about
3+
* unvalidated dynamic method calls.
4+
*
5+
* Note, for performance reasons: only import this file if
6+
* `UnvalidatedDynamicMethodCall::Configuration` is needed, otherwise
7+
* `UnvalidatedDynamicMethodCallCustomizations` should be imported
8+
* instead.
49
*/
510

611
import javascript
@@ -9,51 +14,9 @@ import PropertyInjectionShared
914
private import semmle.javascript.dataflow.InferredTypes
1015

1116
module UnvalidatedDynamicMethodCall {
17+
import UnvalidatedDynamicMethodCallCustomizations::UnvalidatedDynamicMethodCall
1218
private import DataFlow::FlowLabel
1319

14-
/**
15-
* A data flow source for unvalidated dynamic method calls.
16-
*/
17-
abstract class Source extends DataFlow::Node {
18-
/**
19-
* Gets the flow label relevant for this source.
20-
*/
21-
DataFlow::FlowLabel getFlowLabel() { result = data() }
22-
}
23-
24-
/**
25-
* A data flow sink for unvalidated dynamic method calls.
26-
*/
27-
abstract class Sink extends DataFlow::Node {
28-
/**
29-
* Gets the flow label relevant for this sink
30-
*/
31-
abstract DataFlow::FlowLabel getFlowLabel();
32-
}
33-
34-
/**
35-
* A sanitizer for unvalidated dynamic method calls.
36-
*/
37-
abstract class Sanitizer extends DataFlow::Node {
38-
abstract predicate sanitizes(DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl);
39-
}
40-
41-
/**
42-
* A flow label describing values read from a user-controlled property that
43-
* may not be functions.
44-
*/
45-
private class MaybeNonFunction extends DataFlow::FlowLabel {
46-
MaybeNonFunction() { this = "MaybeNonFunction" }
47-
}
48-
49-
/**
50-
* A flow label describing values read from a user-controlled property that
51-
* may originate from a prototype object.
52-
*/
53-
private class MaybeFromProto extends DataFlow::FlowLabel {
54-
MaybeFromProto() { this = "MaybeFromProto" }
55-
}
56-
5720
/**
5821
* A taint-tracking configuration for reasoning about unvalidated dynamic method calls.
5922
*/
@@ -90,62 +53,4 @@ module UnvalidatedDynamicMethodCall {
9053
)
9154
}
9255
}
93-
94-
/**
95-
* A source of remote user input, considered as a source for unvalidated dynamic method calls.
96-
*/
97-
class RemoteFlowSourceAsSource extends Source {
98-
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
99-
}
100-
101-
/**
102-
* The page URL considered as a flow source for unvalidated dynamic method calls.
103-
*/
104-
class DocumentUrlAsSource extends Source {
105-
DocumentUrlAsSource() { this = DOM::locationSource() }
106-
}
107-
108-
/**
109-
* A function invocation of an unsafe function, as a sink for remote unvalidated dynamic method calls.
110-
*/
111-
class CalleeAsSink extends Sink {
112-
InvokeExpr invk;
113-
114-
CalleeAsSink() {
115-
this = invk.getCallee().flow() and
116-
// don't flag invocations inside a try-catch
117-
not invk.getASuccessor() instanceof CatchClause
118-
}
119-
120-
override DataFlow::FlowLabel getFlowLabel() {
121-
result instanceof MaybeNonFunction and
122-
// don't flag if the type inference can prove that it is a function;
123-
// this complements the `FunctionCheck` sanitizer below: the type inference can
124-
// detect more checks locally, but doesn't provide inter-procedural reasoning
125-
this.analyze().getAType() != TTFunction()
126-
or
127-
result instanceof MaybeFromProto
128-
}
129-
}
130-
131-
/**
132-
* A check of the form `typeof x === 'function'`, which sanitizes away the `MaybeNonFunction`
133-
* taint kind.
134-
*/
135-
class FunctionCheck extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode {
136-
override EqualityTest astNode;
137-
138-
TypeofExpr t;
139-
140-
FunctionCheck() {
141-
astNode.getAnOperand().getStringValue() = "function" and
142-
astNode.getAnOperand().getUnderlyingValue() = t
143-
}
144-
145-
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
146-
outcome = astNode.getPolarity() and
147-
e = t.getOperand().getUnderlyingValue() and
148-
label instanceof MaybeNonFunction
149-
}
150-
}
15156
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* Provides default sources, sinks and sanitisers for reasoning about
3+
* unvalidated dynamic method calls, as well as extension points for
4+
* adding your own.
5+
*/
6+
7+
import javascript
8+
import semmle.javascript.frameworks.Express
9+
import PropertyInjectionShared
10+
private import semmle.javascript.dataflow.InferredTypes
11+
12+
module UnvalidatedDynamicMethodCall {
13+
private import DataFlow::FlowLabel
14+
15+
/**
16+
* A data flow source for unvalidated dynamic method calls.
17+
*/
18+
abstract class Source extends DataFlow::Node {
19+
/**
20+
* Gets the flow label relevant for this source.
21+
*/
22+
DataFlow::FlowLabel getFlowLabel() { result = data() }
23+
}
24+
25+
/**
26+
* A data flow sink for unvalidated dynamic method calls.
27+
*/
28+
abstract class Sink extends DataFlow::Node {
29+
/**
30+
* Gets the flow label relevant for this sink
31+
*/
32+
abstract DataFlow::FlowLabel getFlowLabel();
33+
}
34+
35+
/**
36+
* A sanitizer for unvalidated dynamic method calls.
37+
*/
38+
abstract class Sanitizer extends DataFlow::Node {
39+
abstract predicate sanitizes(DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl);
40+
}
41+
42+
/**
43+
* A flow label describing values read from a user-controlled property that
44+
* may not be functions.
45+
*/
46+
class MaybeNonFunction extends DataFlow::FlowLabel {
47+
MaybeNonFunction() { this = "MaybeNonFunction" }
48+
}
49+
50+
/**
51+
* A flow label describing values read from a user-controlled property that
52+
* may originate from a prototype object.
53+
*/
54+
class MaybeFromProto extends DataFlow::FlowLabel {
55+
MaybeFromProto() { this = "MaybeFromProto" }
56+
}
57+
58+
/**
59+
* A source of remote user input, considered as a source for unvalidated dynamic method calls.
60+
*/
61+
class RemoteFlowSourceAsSource extends Source {
62+
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
63+
}
64+
65+
/**
66+
* The page URL considered as a flow source for unvalidated dynamic method calls.
67+
*/
68+
class DocumentUrlAsSource extends Source {
69+
DocumentUrlAsSource() { this = DOM::locationSource() }
70+
}
71+
72+
/**
73+
* A function invocation of an unsafe function, as a sink for remote unvalidated dynamic method calls.
74+
*/
75+
class CalleeAsSink extends Sink {
76+
InvokeExpr invk;
77+
78+
CalleeAsSink() {
79+
this = invk.getCallee().flow() and
80+
// don't flag invocations inside a try-catch
81+
not invk.getASuccessor() instanceof CatchClause
82+
}
83+
84+
override DataFlow::FlowLabel getFlowLabel() {
85+
result instanceof MaybeNonFunction and
86+
// don't flag if the type inference can prove that it is a function;
87+
// this complements the `FunctionCheck` sanitizer below: the type inference can
88+
// detect more checks locally, but doesn't provide inter-procedural reasoning
89+
this.analyze().getAType() != TTFunction()
90+
or
91+
result instanceof MaybeFromProto
92+
}
93+
}
94+
95+
/**
96+
* A check of the form `typeof x === 'function'`, which sanitizes away the `MaybeNonFunction`
97+
* taint kind.
98+
*/
99+
class FunctionCheck extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode {
100+
override EqualityTest astNode;
101+
102+
TypeofExpr t;
103+
104+
FunctionCheck() {
105+
astNode.getAnOperand().getStringValue() = "function" and
106+
astNode.getAnOperand().getUnderlyingValue() = t
107+
}
108+
109+
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
110+
outcome = astNode.getPolarity() and
111+
e = t.getOperand().getUnderlyingValue() and
112+
label instanceof MaybeNonFunction
113+
}
114+
}
115+
}

0 commit comments

Comments
 (0)