-
Notifications
You must be signed in to change notification settings - Fork 249
/
Copy pathcommon.qll
177 lines (157 loc) · 5.39 KB
/
common.qll
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import cpp
import collections
import pointers.managed_ptr
import semmle.code.cpp.dataflow.DataFlow
/**
* Common utilities that is adapted to the specific coding pattern in chrome.
*/
//--------- dataflow edges
/**
* A dataflow edge that allows propagation through operator= as well as normal assignment.
* See `GeneralAssignment` for details.
*/
predicate generalAssignEdge(DataFlow::Node node1, DataFlow::Node node2) {
exists(GeneralAssignment expr | node1.asExpr() = expr.getRValue() and
node2.asExpr() = expr.getLValue()
)
}
/**
* A dataflow edge that allows propagation into loop variable of the form
* ```
* for (int x : xs) {
* ...
* }
* ```
* i.e. goes from `xs` to `x`.
*/
predicate forRangeEdge(DataFlow::Node node1, DataFlow::Node node2) {
exists(RangeBasedForStmt stmt | node1.asExpr() = stmt.getRange() and
node2.asExpr() = stmt.getRangeVariable().getAnAccess()
)
}
/**
* Allows flows of the form:
* ```
* *x = a; //<-- a tainted
* b = x; //<-- b now tainted.
* ```
*/
predicate useUsePairEdge(DataFlow::Node node1, DataFlow::Node node2) {
useUsePair(_, node1.asExpr(), node2.asExpr())
}
predicate copyConstructorEdge(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall cp | cp.getTarget() instanceof CopyConstructor and
cp.getArgument(0) = node1.asExpr() and
cp = node2.asExpr()
)
}
predicate newEdge(DataFlow::Node node1, DataFlow::Node node2) {
exists(NewExpr expr | expr = node2.asExpr() and
node1.asExpr() = expr.getInitializer()
)
}
/**
* Allows dataflow to go through polymorphic function call. Exclude some functions that
* are frequently overloaded to cut down on noise, probably needs tweaking.
*/
predicate polymorphicCallEdge(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc, MemberFunction g, int i | fc.getArgument(i) = node1.asExpr() and
overrides*(g, fc.getTarget()) and node2.asParameter() = g.getParameter(i)|
not fc.getTarget() instanceof AddToCollection and
not fc.getTarget() instanceof TakeFromCollection and
not fc.getTarget() instanceof PointerTransferFunction and
not g.getDeclaringType() instanceof ManagedPtr and
not count(g) = 1
)
}
/**
* Edge that takes into account of general constructions like make_unique,
*/
predicate constructorEdge(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc, Constructor cstor, Class c, Parameter p, int idx | p.getAnAccess() = node2.asExpr() and
constructionCall(c, fc) and p = cstor.getParameter(idx) and
cstor.getDeclaringType() = c and
cstor.getNumberOfParameters() = fc.getNumberOfArguments() and
node1.asExpr() = fc.getArgument(idx)
)
}
//---------- End dataflow edges
/**
* This should be used instead of the `.getQualifier` method in `FunctionCall` and `FieldAccess` because
* the operator -> is often overriden in Chrome. This general method skip the overriden operator -> to find the
* true qualifier in those circumstances.
*/
Expr getQualifier(Expr fc) {
exists(Expr qualifier | qualifier = fc.(FunctionCall).getQualifier() or qualifier = fc.(FieldAccess).getQualifier() |
if qualifier.(FunctionCall).getTarget().hasName("operator->") then
result = getQualifier(qualifier)
else
result = qualifier
)
}
/**
* Again, this should be used instead of `Assignment` because the operator= is often overloaded. This general
* expression takes operator= into account.
*/
class GeneralAssignment extends Expr {
GeneralAssignment() {
this instanceof Assignment or
this.(FunctionCall).getTarget().hasName("operator=")
}
Expr getLValue() {
result = this.(Assignment).getLValue() or
result = this.(FunctionCall).getQualifier()
}
Expr getRValue() {
result = this.(Assignment).getRValue() or
result = this.(FunctionCall).getArgument(0)
}
}
/**
* General construction calls that takes `make_unique` and `MakeRefCounted` into account.
*/
predicate constructionCall(Class c, FunctionCall fc) {
(fc instanceof ConstructorCall and fc.getTarget().getDeclaringType() = c) or
(
(fc.getTarget().getName().matches("make_unique%") or fc.getTarget().getName().matches("MakeRefCounted%"))
and
fc.getTemplateArgument(0) = c
)
}
/**
* General construction call that takes `make_unique` and `MakeRefCounted` into account, but also
* constructor of base class from derived classes.
*/
predicate polyConstructionCall(Class c, FunctionCall fc) {
(fc instanceof ConstructorCall and fc.getTarget().getDeclaringType().getABaseClass*() = c and
not fc instanceof ConstructorBaseInit and not fc.isCompilerGenerated()) or
(
(fc.getTarget().getName().matches("make_unique%") or fc.getTarget().getName().matches("MakeRefCounted%"))
and
fc.getTemplateArgument(0).(Class).getABaseClass*() = c
)
}
/**
* Convenient function to extend `stripType` to include managed pointers also.
*/
Type generalStripType(Type t) {
exists(Type st | st = t.stripType() |
if st instanceof ManagedPtr then
result = st.(ManagedPtr).getManagedType().stripType()
else
result = st
)
}
/** For Optional, UnretainedWrapper, RetainedWrapper to get the underlying type*/
//TODO: Decide whether to include StructPtr or not
Type unwrapType(ClassTemplateInstantiation t) {
if
(
t.getName().matches("Optional<%") or
t.getName().matches("UnretainedWrapper<%") or
t.getName().matches("RetainedRefWrapper<%")
) then
result = t.getTemplateArgument(0)
else
result = t
}