Skip to content

Commit c951a29

Browse files
committed
JS: Migrate UnvalidatedDynamicMethodCall
1 parent 820f81f commit c951a29

File tree

2 files changed

+87
-39
lines changed

2 files changed

+87
-39
lines changed

javascript/ql/lib/semmle/javascript/security/dataflow/UnvalidatedDynamicMethodCallCustomizations.qll

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,86 @@ import PropertyInjectionShared
1010
private import semmle.javascript.dataflow.InferredTypes
1111

1212
module UnvalidatedDynamicMethodCall {
13-
private import DataFlow::FlowLabel
13+
private newtype TFlowState =
14+
TTaint() or
15+
TMaybeNonFunction() or
16+
TMaybeFromProto()
17+
18+
/** A flow state to associate with a tracked value. */
19+
class FlowState extends TFlowState {
20+
/** Gets a string representation fo this flow state */
21+
string toString() {
22+
this = TTaint() and result = "taint"
23+
or
24+
this = TMaybeNonFunction() and result = "maybe-non-function"
25+
or
26+
this = TMaybeFromProto() and result = "maybe-from-proto"
27+
}
28+
29+
deprecated DataFlow::FlowLabel toFlowLabel() {
30+
this = TTaint() and result.isTaint()
31+
or
32+
this = TMaybeNonFunction() and result instanceof MaybeNonFunction
33+
or
34+
this = TMaybeFromProto() and result instanceof MaybeFromProto
35+
}
36+
}
37+
38+
/** Predicates for working with flow states. */
39+
module FlowState {
40+
deprecated FlowState fromFlowLabel(DataFlow::FlowLabel label) { result.toFlowLabel() = label }
41+
42+
/** A tainted value. */
43+
FlowState taint() { result = TTaint() }
44+
45+
/**
46+
* A non-function value, obtained by reading from a tainted property name.
47+
*/
48+
FlowState maybeNonFunction() { result = TMaybeNonFunction() }
49+
50+
/**
51+
* A value obtained from a prototype object while reading from a tainted property name.
52+
*/
53+
FlowState maybeFromProto() { result = TMaybeFromProto() }
54+
}
1455

1556
/**
1657
* A data flow source for unvalidated dynamic method calls.
1758
*/
1859
abstract class Source extends DataFlow::Node {
1960
/**
20-
* Gets the flow label relevant for this source.
61+
* Gets the flow state relevant for this source.
2162
*/
22-
DataFlow::FlowLabel getFlowLabel() { result = taint() }
63+
FlowState getAFlowState() { result = FlowState::taint() }
64+
65+
/** DEPRECATED. Use `getAFlowState()` instead. */
66+
deprecated DataFlow::FlowLabel getFlowLabel() { result = this.getAFlowState().toFlowLabel() }
2367
}
2468

2569
/**
2670
* A data flow sink for unvalidated dynamic method calls.
2771
*/
2872
abstract class Sink extends DataFlow::Node {
2973
/**
30-
* Gets the flow label relevant for this sink
74+
* Gets the flow state relevant for this sink
3175
*/
32-
abstract DataFlow::FlowLabel getFlowLabel();
76+
FlowState getAFlowState() { result = FlowState::taint() }
77+
78+
/** DEPRECATED. Use `getAFlowState()` instead. */
79+
deprecated DataFlow::FlowLabel getFlowLabel() { result = this.getAFlowState().toFlowLabel() }
3380
}
3481

3582
/**
3683
* A sanitizer for unvalidated dynamic method calls.
3784
*/
3885
abstract class Sanitizer extends DataFlow::Node {
3986
/**
40-
* Gets the flow label blocked by this sanitizer.
87+
* Gets a flow state blocked by this sanitizer.
4188
*/
42-
DataFlow::FlowLabel getFlowLabel() { result.isTaint() }
89+
FlowState getAFlowState() { result = FlowState::taint() }
90+
91+
/** DEPRECATED. Use `getAFlowState()` instead. */
92+
deprecated DataFlow::FlowLabel getFlowLabel() { result = this.getAFlowState().toFlowLabel() }
4393

4494
/**
4595
* DEPRECATED. Use sanitizer nodes instead.
@@ -64,16 +114,16 @@ module UnvalidatedDynamicMethodCall {
64114
predicate blocksExpr(boolean outcome, Expr e) { none() }
65115

66116
/**
67-
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
117+
* Holds if this node acts as a barrier for `state`, blocking further flow from `e` if `this` evaluates to `outcome`.
68118
*/
69-
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) { none() }
119+
predicate blocksExpr(boolean outcome, Expr e, FlowState state) { none() }
70120

71121
/** DEPRECATED. Use `blocksExpr` instead. */
72122
deprecated predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
73123

74124
/** DEPRECATED. Use `blocksExpr` instead. */
75125
deprecated predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
76-
this.blocksExpr(outcome, e, label)
126+
this.blocksExpr(outcome, e, FlowState::fromFlowLabel(label))
77127
}
78128
}
79129

@@ -93,15 +143,15 @@ module UnvalidatedDynamicMethodCall {
93143
* A flow label describing values read from a user-controlled property that
94144
* may not be functions.
95145
*/
96-
abstract class MaybeNonFunction extends DataFlow::FlowLabel {
146+
abstract deprecated class MaybeNonFunction extends DataFlow::FlowLabel {
97147
MaybeNonFunction() { this = "MaybeNonFunction" }
98148
}
99149

100150
/**
101151
* A flow label describing values read from a user-controlled property that
102152
* may originate from a prototype object.
103153
*/
104-
abstract class MaybeFromProto extends DataFlow::FlowLabel {
154+
abstract deprecated class MaybeFromProto extends DataFlow::FlowLabel {
105155
MaybeFromProto() { this = "MaybeFromProto" }
106156
}
107157

@@ -134,14 +184,14 @@ module UnvalidatedDynamicMethodCall {
134184
)
135185
}
136186

137-
override DataFlow::FlowLabel getFlowLabel() {
138-
result instanceof MaybeNonFunction and
187+
override FlowState getAFlowState() {
188+
result = FlowState::maybeNonFunction() and
139189
// don't flag if the type inference can prove that it is a function;
140190
// this complements the `FunctionCheck` sanitizer below: the type inference can
141191
// detect more checks locally, but doesn't provide inter-procedural reasoning
142192
this.analyze().getAType() != TTFunction()
143193
or
144-
result instanceof MaybeFromProto
194+
result = FlowState::maybeFromProto()
145195
}
146196
}
147197

@@ -155,10 +205,10 @@ module UnvalidatedDynamicMethodCall {
155205

156206
FunctionCheck() { TaintTracking::isTypeofGuard(astNode, operand, "function") }
157207

158-
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
208+
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
159209
outcome = astNode.getPolarity() and
160210
e = operand and
161-
label instanceof MaybeNonFunction
211+
state = FlowState::maybeNonFunction()
162212
}
163213
}
164214

javascript/ql/lib/semmle/javascript/security/dataflow/UnvalidatedDynamicMethodCallQuery.qll

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,58 +13,55 @@ import semmle.javascript.frameworks.Express
1313
import PropertyInjectionShared
1414
private import semmle.javascript.dataflow.InferredTypes
1515
import UnvalidatedDynamicMethodCallCustomizations::UnvalidatedDynamicMethodCall
16-
private import DataFlow::FlowLabel
16+
private import UnvalidatedDynamicMethodCallCustomizations::UnvalidatedDynamicMethodCall as UnvalidatedDynamicMethodCall
1717

1818
// Materialize flow labels
19-
private class ConcreteMaybeNonFunction extends MaybeNonFunction {
19+
deprecated private class ConcreteMaybeNonFunction extends MaybeNonFunction {
2020
ConcreteMaybeNonFunction() { this = this }
2121
}
2222

23-
private class ConcreteMaybeFromProto extends MaybeFromProto {
23+
deprecated private class ConcreteMaybeFromProto extends MaybeFromProto {
2424
ConcreteMaybeFromProto() { this = this }
2525
}
2626

2727
/**
2828
* A taint-tracking configuration for reasoning about unvalidated dynamic method calls.
2929
*/
3030
module UnvalidatedDynamicMethodCallConfig implements DataFlow::StateConfigSig {
31-
class FlowState = DataFlow::FlowLabel;
31+
class FlowState = UnvalidatedDynamicMethodCall::FlowState;
3232

33-
predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
34-
source.(Source).getFlowLabel() = label
33+
predicate isSource(DataFlow::Node source, FlowState label) {
34+
source.(Source).getAFlowState() = label
3535
}
3636

37-
predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
38-
sink.(Sink).getFlowLabel() = label
39-
}
37+
predicate isSink(DataFlow::Node sink, FlowState label) { sink.(Sink).getAFlowState() = label }
4038

41-
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) {
42-
node.(Sanitizer).getFlowLabel() = label
39+
predicate isBarrier(DataFlow::Node node, FlowState label) {
40+
node.(Sanitizer).getAFlowState() = label
4341
or
4442
TaintTracking::defaultSanitizer(node) and
45-
label.isTaint()
43+
label = FlowState::taint()
4644
or
47-
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(label)
45+
node = DataFlow::MakeStateBarrierGuard<FlowState, BarrierGuard>::getABarrierNode(label)
4846
}
4947

5048
predicate isBarrier(DataFlow::Node node) {
5149
node = DataFlow::MakeBarrierGuard<BarrierGuard>::getABarrierNode()
5250
}
5351

5452
predicate isAdditionalFlowStep(
55-
DataFlow::Node src, DataFlow::FlowLabel srclabel, DataFlow::Node dst,
56-
DataFlow::FlowLabel dstlabel
53+
DataFlow::Node src, FlowState srclabel, DataFlow::Node dst, FlowState dstlabel
5754
) {
5855
exists(DataFlow::PropRead read |
5956
src = read.getPropertyNameExpr().flow() and
6057
dst = read and
61-
srclabel.isTaint() and
58+
srclabel = FlowState::taint() and
6259
(
63-
dstlabel instanceof MaybeNonFunction
60+
dstlabel = FlowState::maybeNonFunction()
6461
or
6562
// a property of `Object.create(null)` cannot come from a prototype
6663
not PropertyInjection::isPrototypeLessObject(read.getBase().getALocalSource()) and
67-
dstlabel instanceof MaybeFromProto
64+
dstlabel = FlowState::maybeFromProto()
6865
) and
6966
// avoid overlapping results with unsafe dynamic method access query
7067
not PropertyInjection::hasUnsafeMethods(read.getBase().getALocalSource())
@@ -74,10 +71,10 @@ module UnvalidatedDynamicMethodCallConfig implements DataFlow::StateConfigSig {
7471
src = get.getArgument(0) and
7572
dst = get
7673
) and
77-
srclabel.isTaint() and
78-
dstlabel instanceof MaybeNonFunction
74+
srclabel = FlowState::taint() and
75+
dstlabel = FlowState::maybeNonFunction()
7976
or
80-
srclabel.isTaint() and
77+
srclabel = FlowState::taint() and
8178
TaintTracking::defaultTaintStep(src, dst) and
8279
srclabel = dstlabel
8380
}
@@ -118,6 +115,7 @@ deprecated class Configuration extends TaintTracking::Configuration {
118115
DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel,
119116
DataFlow::FlowLabel dstlabel
120117
) {
121-
UnvalidatedDynamicMethodCallConfig::isAdditionalFlowStep(src, srclabel, dst, dstlabel)
118+
UnvalidatedDynamicMethodCallConfig::isAdditionalFlowStep(src,
119+
FlowState::fromFlowLabel(srclabel), dst, FlowState::fromFlowLabel(dstlabel))
122120
}
123121
}

0 commit comments

Comments
 (0)