Skip to content

Commit 3c9c79a

Browse files
committed
JS: remove flow labels from js/resource-exhaustion
1 parent 5965035 commit 3c9c79a

13 files changed

+93
-520
lines changed

javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -33,57 +33,7 @@
3333

3434
<p>
3535

36-
The following example allocates a buffer with a user-controlled
37-
size.
38-
39-
</p>
40-
41-
<sample src="examples/ResourceExhaustion_buffer.js" />
42-
43-
<p>
44-
45-
This is problematic since an attacker can choose a size
46-
that makes the application run out of memory. Even worse, in older
47-
versions of Node.js, this could leak confidential memory.
48-
49-
To prevent such attacks, limit the buffer size:
50-
51-
</p>
52-
53-
<sample src="examples/ResourceExhaustion_buffer_fixed.js" />
54-
55-
</example>
56-
57-
<example>
58-
59-
<p>
60-
61-
As another example, consider an application that allocates an
62-
array with a user-controlled size, and then fills it with values:
63-
64-
</p>
65-
66-
<sample src="examples/ResourceExhaustion_array.js" />
67-
68-
<p>
69-
The allocation of the array itself is not problematic since arrays are
70-
allocated sparsely, but the subsequent filling of the array will take
71-
a long time, causing the application to be unresponsive, or even run
72-
out of memory.
73-
74-
Again, a limit on the size will prevent the attack:
75-
76-
</p>
77-
78-
<sample src="examples/ResourceExhaustion_array_fixed.js" />
79-
80-
</example>
81-
82-
<example>
83-
84-
<p>
85-
86-
Finally, the following example lets a user choose a delay after
36+
The following example lets a user choose a delay after
8737
which a function is executed:
8838

8939
</p>
@@ -97,7 +47,7 @@
9747
registrations of such delays will therefore use up all of the memory
9848
in the application.
9949

100-
Again, a limit on the delay will prevent the attack:
50+
A limit on the delay will prevent the attack:
10151

10252
</p>
10353

javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js

Lines changed: 0 additions & 16 deletions
This file was deleted.

javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js

Lines changed: 0 additions & 16 deletions
This file was deleted.

javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,36 +19,29 @@ module ResourceExhaustion {
1919
class Configuration extends TaintTracking::Configuration {
2020
Configuration() { this = "ResourceExhaustion" }
2121

22-
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
23-
source.(Source).getAFlowLabel() = label
24-
}
22+
override predicate isSource(DataFlow::Node source) { source instanceof Source }
2523

26-
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
27-
sink.(Sink).getAFlowLabel() = label
28-
}
24+
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
2925

30-
override predicate isAdditionalFlowStep(
31-
DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel,
32-
DataFlow::FlowLabel dstlabel
33-
) {
34-
dstlabel instanceof Label::Number and
26+
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node dst) {
3527
isNumericFlowStep(src, dst)
3628
or
3729
// reuse most existing taint steps
38-
super.isAdditionalFlowStep(src, dst) and
39-
not dst.asExpr() instanceof AddExpr and
40-
if dst.(DataFlow::MethodCallNode).calls(src, "toString")
41-
then dstlabel.isTaint()
42-
else srclabel = dstlabel
30+
isRestrictedAdditionalTaintStep(src, dst)
4331
}
4432

4533
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
4634
guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or
47-
guard instanceof UpperBoundsCheckSanitizerGuard or
48-
guard instanceof TypeTestGuard
35+
guard instanceof UpperBoundsCheckSanitizerGuard
4936
}
5037
}
5138

39+
predicate isRestrictedAdditionalTaintStep(DataFlow::Node src, DataFlow::Node dst) {
40+
any(TaintTracking::AdditionalTaintStep dts).step(src, dst) and
41+
not dst.asExpr() instanceof AddExpr and
42+
not dst.(DataFlow::MethodCallNode).calls(src, "toString")
43+
}
44+
5245
/**
5346
* Holds if data may flow from `src` to `dst` as a number.
5447
*/

javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll

Lines changed: 7 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,12 @@ module ResourceExhaustion {
1010
/**
1111
* A data flow source for resource exhaustion vulnerabilities.
1212
*/
13-
abstract class Source extends DataFlow::Node {
14-
/** Gets a flow label denoting the type of value for which this is a source. */
15-
DataFlow::FlowLabel getAFlowLabel() { result.isTaint() }
16-
}
13+
abstract class Source extends DataFlow::Node { }
1714

1815
/**
1916
* A data flow sink for resource exhaustion vulnerabilities.
2017
*/
2118
abstract class Sink extends DataFlow::Node {
22-
/** Gets a flow label denoting the type of value for which this is a sink. */
23-
DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number }
24-
2519
/**
2620
* Gets a description of why this is a problematic sink.
2721
*/
@@ -33,59 +27,19 @@ module ResourceExhaustion {
3327
*/
3428
abstract class Sanitizer extends DataFlow::Node { }
3529

36-
/**
37-
* Provides data flow labels for resource exhaustion vulnerabilities.
38-
*/
39-
module Label {
40-
/**
41-
* A number data flow label.
42-
*/
43-
class Number extends DataFlow::FlowLabel {
44-
Number() { this = "number" }
45-
}
46-
}
47-
4830
/**
4931
* A sanitizer that blocks taint flow if the size of a number is limited.
5032
*/
51-
class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode,
33+
class UpperBoundsCheckSanitizerGuard extends TaintTracking::SanitizerGuardNode,
5234
DataFlow::ValueNode {
5335
override RelationalComparison astNode;
5436

55-
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
56-
label instanceof Label::Number and
57-
(
58-
true = outcome and
59-
e = astNode.getLesserOperand()
60-
or
61-
false = outcome and
62-
e = astNode.getGreaterOperand()
63-
)
64-
}
65-
}
66-
67-
/**
68-
* A test of form `typeof x === "something"`, preventing `x` from being a number in some cases.
69-
*/
70-
class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode {
71-
override EqualityTest astNode;
72-
Expr x;
73-
boolean polarity;
74-
75-
TypeTestGuard() {
76-
// typeof x === "number" sanitizes `x` when it evaluates to false
77-
TaintTracking::isTypeofGuard(astNode, x, "number") and
78-
polarity = astNode.getPolarity().booleanNot()
37+
override predicate sanitizes(boolean outcome, Expr e) {
38+
true = outcome and
39+
e = astNode.getLesserOperand()
7940
or
80-
// typeof x === "string" sanitizes `x` when it evaluates to true
81-
TaintTracking::isTypeofGuard(astNode, x, any(string s | s != "number")) and
82-
polarity = astNode.getPolarity()
83-
}
84-
85-
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
86-
polarity = outcome and
87-
e = x and
88-
label instanceof Label::Number
41+
false = outcome and
42+
e = astNode.getGreaterOperand()
8943
}
9044
}
9145

@@ -94,60 +48,6 @@ module ResourceExhaustion {
9448
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
9549
}
9650

97-
/**
98-
* A node that determines the size of a buffer, considered as a data flow sink for resource exhaustion vulnerabilities.
99-
*/
100-
class BufferSizeSink extends Sink {
101-
BufferSizeSink() {
102-
exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index |
103-
clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index)
104-
|
105-
exists(string name |
106-
invk = clazz.getAMemberCall(name) and
107-
(
108-
name = "from" and index = 2
109-
or
110-
name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0
111-
)
112-
)
113-
or
114-
invk = clazz.getAnInvocation() and
115-
(
116-
invk.getNumArgument() = 1 and
117-
index = 0
118-
or
119-
invk.getNumArgument() = 3 and index = 2
120-
)
121-
)
122-
or
123-
this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0)
124-
}
125-
126-
override string getProblemDescription() {
127-
result = "This creates a buffer with a user-controlled size"
128-
}
129-
}
130-
131-
/**
132-
* A node that determines the size of an array, considered as a data flow sink for resource exhaustion vulnerabilities.
133-
*/
134-
class DenseArraySizeSink extends Sink {
135-
DenseArraySizeSink() {
136-
// Arrays are sparse by default, so we must also look at how the array is used
137-
exists(DataFlow::ArrayConstructorInvokeNode instance |
138-
this = instance.getArgument(0) and
139-
instance.getNumArgument() = 1
140-
|
141-
exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or
142-
instance.flowsToExpr(any(AddExpr p).getAnOperand())
143-
)
144-
}
145-
146-
override string getProblemDescription() {
147-
result = "This creates an array with a user-controlled length"
148-
}
149-
}
150-
15151
/**
15252
* A node that determines the repetitions of a string, considered as a data flow sink for resource exhaustion vulnerabilities.
15353
*/
@@ -159,8 +59,6 @@ module ResourceExhaustion {
15959
)
16060
}
16161

162-
override DataFlow::FlowLabel getAFlowLabel() { any() }
163-
16462
override string getProblemDescription() {
16563
result = "This creates a string with a user-controlled length"
16664
}
@@ -175,8 +73,6 @@ module ResourceExhaustion {
17573
this = LodashUnderscore::member(["delay", "throttle", "debounce"]).getACall().getArgument(1)
17674
}
17775

178-
override DataFlow::FlowLabel getAFlowLabel() { any() }
179-
18076
override string getProblemDescription() {
18177
result = "This creates a timer with a user-controlled duration"
18278
}

0 commit comments

Comments
 (0)