-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathInclusionTests.qll
More file actions
134 lines (119 loc) · 4.11 KB
/
InclusionTests.qll
File metadata and controls
134 lines (119 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* Contains classes for recognizing array and string inclusion tests.
*/
private import codeql.ruby.AST
private import codeql.ruby.DataFlow
private import codeql.ruby.controlflow.CfgNodes
/**
* An expression that checks if an element is contained in an array
* or is a substring of another string.
*
* Examples:
* ```
* A.include?(B)
* A.index(B) != nil
* A.index(B) >= 0
* ```
*/
class InclusionTest extends DataFlow::Node instanceof InclusionTest::Range {
/** Gets the `A` in `A.include?(B)`. */
final DataFlow::Node getContainerNode() { result = super.getContainerNode() }
/** Gets the `B` in `A.include?(B)`. */
final DataFlow::Node getContainedNode() { result = super.getContainedNode() }
/**
* Gets the polarity of the check.
*
* If the polarity is `false` the check returns `true` if the container does not contain
* the given element.
*/
final boolean getPolarity() { result = super.getPolarity() }
}
/**
* Contains classes for recognizing array and string inclusion tests.
*/
module InclusionTest {
/**
* An expression that is equivalent to `A.include?(B)` or `!A.include?(B)`.
*
* Note that this also includes calls to the array method named `include?`.
*/
abstract class Range extends DataFlow::Node {
/** Gets the `A` in `A.include?(B)`. */
abstract DataFlow::Node getContainerNode();
/** Gets the `B` in `A.include?(B)`. */
abstract DataFlow::Node getContainedNode();
/**
* Gets the polarity of the check.
*
* If the polarity is `false` the check returns `true` if the container does not contain
* the given element.
*/
boolean getPolarity() { result = true }
}
/**
* A call to a method named `include?`, assumed to refer to `String.include?`
* or `Array.include?`.
*/
private class Includes_Native extends Range, DataFlow::CallNode {
Includes_Native() {
this.getMethodName() = "include?" and
strictcount(this.getArgument(_)) = 1
}
override DataFlow::Node getContainerNode() { result = this.getReceiver() }
override DataFlow::Node getContainedNode() { result = this.getArgument(0) }
}
/**
* A check of form `A.index(B) != nil`, `A.index(B) >= 0`, or similar.
*/
private class Includes_IndexOfComparison extends Range, DataFlow::Node {
private DataFlow::CallNode indexOf;
private boolean polarity;
Includes_IndexOfComparison() {
exists(ExprCfgNode index, ExprNodes::ComparisonOperationCfgNode comparison, int value |
indexOf.asExpr() = comparison.getAnOperand() and
index = comparison.getAnOperand() and
this.asExpr() = comparison and
// one operand is of the form `whitelist.index(x)`
indexOf.getMethodName() = "index" and
// and the other one is 0 or -1
(
value = index.getConstantValue().getInt() and value = 0
or
index.getConstantValue().isNil() and value = -1
)
|
value = -1 and polarity = false and comparison.getExpr() instanceof CaseEqExpr
or
value = -1 and polarity = false and comparison.getExpr() instanceof EqExpr
or
value = -1 and polarity = true and comparison.getExpr() instanceof NEExpr
or
exists(RelationalOperation op | op = comparison.getExpr() |
exists(Expr lesser, Expr greater |
op.getLesserOperand() = lesser and
op.getGreaterOperand() = greater
|
polarity = true and
greater = indexOf.asExpr().getExpr() and
(
value = 0 and op.isInclusive()
or
value = -1 and not op.isInclusive()
)
or
polarity = false and
lesser = indexOf.asExpr().getExpr() and
(
value = -1 and op.isInclusive()
or
value = 0 and not op.isInclusive()
)
)
)
)
}
override DataFlow::Node getContainerNode() { result = indexOf.getReceiver() }
override DataFlow::Node getContainedNode() { result = indexOf.getArgument(0) }
override boolean getPolarity() { result = polarity }
}
}