Skip to content

Commit 69c1ead

Browse files
committed
Merge branch 'main' into mathiasvp/read-step-without-memory-operands
2 parents 5546830 + 48a1ee6 commit 69c1ead

File tree

94 files changed

+3694
-164
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+3694
-164
lines changed

cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,20 @@ private predicate addressTakenVariable(StackVariable var) {
7373
)
7474
}
7575

76+
/**
77+
* Holds if `v` is a stack-allocated reference-typed local variable. We don't
78+
* build SSA for such variables since they are likely to change values even
79+
* when not syntactically mentioned. For the same reason,
80+
* `addressTakenVariable` is used to prevent tracking variables that may be
81+
* aliased by such a reference.
82+
*
83+
* Reference-typed parameters are treated as if they weren't references.
84+
* That's because it's in practice highly unlikely that they alias other data
85+
* accessible from the function body.
86+
*/
7687
private predicate isReferenceVar(StackVariable v) {
77-
v.getUnspecifiedType() instanceof ReferenceType
88+
v.getUnspecifiedType() instanceof ReferenceType and
89+
not v instanceof Parameter
7890
}
7991

8092
/**

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,19 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
525525
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
526526
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
527527
)
528+
or
529+
// Reverse flow: data that flows from the post-update node of a reference
530+
// returned by a function call, back into the qualifier of that function.
531+
// This allows data to flow 'in' through references returned by a modeled
532+
// function such as `operator[]`.
533+
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
534+
call.getTarget() = f and
535+
inModel.isReturnValueDeref() and
536+
outModel.isQualifierObject() and
537+
f.hasDataFlow(inModel, outModel) and
538+
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
539+
nodeTo.asDefiningArgument() = call.getQualifier()
540+
)
528541
}
529542

530543
/**

cpp/ql/src/semmle/code/cpp/models/Models.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import implementations.Fread
44
private import implementations.Gets
55
private import implementations.IdentityFunction
66
private import implementations.Inet
7+
private import implementations.Iterator
78
private import implementations.MemberFunction
89
private import implementations.Memcpy
910
private import implementations.Memset
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/**
2+
* Provides implementation classes modeling C++ iterators, including
3+
* `std::iterator`, `std::iterator_traits`, and types meeting the
4+
* `LegacyIterator` named requirement. See `semmle.code.cpp.models.Models` for
5+
* usage information.
6+
*/
7+
8+
import cpp
9+
import semmle.code.cpp.models.interfaces.Taint
10+
import semmle.code.cpp.models.interfaces.DataFlow
11+
12+
/**
13+
* An instantiation of the `std::iterator_traits` template.
14+
*/
15+
class IteratorTraits extends Class {
16+
IteratorTraits() {
17+
this.hasQualifiedName("std", "iterator_traits") and
18+
not this instanceof TemplateClass and
19+
exists(TypedefType t |
20+
this.getAMember() = t and
21+
t.getName() = "iterator_category"
22+
)
23+
}
24+
25+
Type getIteratorType() { result = this.getTemplateArgument(0) }
26+
}
27+
28+
/**
29+
* A type which has the typedefs expected for an iterator.
30+
*/
31+
class IteratorByTypedefs extends Class {
32+
IteratorByTypedefs() {
33+
this.getAMember().(TypedefType).hasName("difference_type") and
34+
this.getAMember().(TypedefType).hasName("value_type") and
35+
this.getAMember().(TypedefType).hasName("pointer") and
36+
this.getAMember().(TypedefType).hasName("reference") and
37+
this.getAMember().(TypedefType).hasName("iterator_category") and
38+
not this.hasQualifiedName("std", "iterator_traits")
39+
}
40+
}
41+
42+
/**
43+
* The `std::iterator` class.
44+
*/
45+
class StdIterator extends Class {
46+
StdIterator() { this.hasQualifiedName("std", "iterator") }
47+
}
48+
49+
/**
50+
* A type which can be used as an iterator
51+
*/
52+
class Iterator extends Type {
53+
Iterator() {
54+
this instanceof IteratorByTypedefs or
55+
exists(IteratorTraits it | it.getIteratorType() = this) or
56+
this instanceof StdIterator
57+
}
58+
}
59+
60+
private FunctionInput getIteratorArgumentInput(Operator op, int index) {
61+
exists(Type t |
62+
t =
63+
op
64+
.getACallToThisFunction()
65+
.getArgument(index)
66+
.getExplicitlyConverted()
67+
.getType()
68+
.stripTopLevelSpecifiers()
69+
|
70+
(
71+
t instanceof Iterator or
72+
t.(ReferenceType).getBaseType() instanceof Iterator
73+
) and
74+
if op.getParameter(index).getUnspecifiedType() instanceof ReferenceType
75+
then result.isParameterDeref(index)
76+
else result.isParameter(index)
77+
)
78+
}
79+
80+
/**
81+
* A non-member prefix `operator*` function for an iterator type.
82+
*/
83+
class IteratorPointerDereferenceOperator extends Operator, TaintFunction {
84+
FunctionInput iteratorInput;
85+
86+
IteratorPointerDereferenceOperator() {
87+
this.hasName("operator*") and
88+
iteratorInput = getIteratorArgumentInput(this, 0)
89+
}
90+
91+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
92+
input = iteratorInput and
93+
output.isReturnValue()
94+
}
95+
}
96+
97+
/**
98+
* A non-member `operator++` or `operator--` function for an iterator type.
99+
*/
100+
class IteratorCrementOperator extends Operator, DataFlowFunction {
101+
FunctionInput iteratorInput;
102+
103+
IteratorCrementOperator() {
104+
this.hasName(["operator++", "operator--"]) and
105+
iteratorInput = getIteratorArgumentInput(this, 0)
106+
}
107+
108+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
109+
input = iteratorInput and
110+
output.isReturnValue()
111+
}
112+
}
113+
114+
/**
115+
* A non-member `operator+` function for an iterator type.
116+
*/
117+
class IteratorAddOperator extends Operator, TaintFunction {
118+
FunctionInput iteratorInput;
119+
120+
IteratorAddOperator() {
121+
this.hasName("operator+") and
122+
iteratorInput = getIteratorArgumentInput(this, [0, 1])
123+
}
124+
125+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
126+
input = iteratorInput and
127+
output.isReturnValue()
128+
}
129+
}
130+
131+
/**
132+
* A non-member `operator-` function that takes a pointer difference type as its second argument.
133+
*/
134+
class IteratorSubOperator extends Operator, TaintFunction {
135+
FunctionInput iteratorInput;
136+
137+
IteratorSubOperator() {
138+
this.hasName("operator-") and
139+
iteratorInput = getIteratorArgumentInput(this, 0) and
140+
this.getParameter(1).getUnspecifiedType() instanceof IntegralType // not an iterator difference
141+
}
142+
143+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
144+
input = iteratorInput and
145+
output.isReturnValue()
146+
}
147+
}
148+
149+
/**
150+
* A non-member `operator+=` or `operator-=` function for an iterator type.
151+
*/
152+
class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction {
153+
IteratorAssignArithmeticOperator() {
154+
this.hasName(["operator+=", "operator-="]) and
155+
this.getDeclaringType() instanceof Iterator
156+
}
157+
158+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
159+
input.isParameter(0) and
160+
output.isReturnValue()
161+
}
162+
163+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
164+
input.isParameterDeref(1) and
165+
output.isParameterDeref(0)
166+
}
167+
}
168+
169+
/**
170+
* A prefix `operator*` member function for an iterator type.
171+
*/
172+
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction {
173+
IteratorPointerDereferenceMemberOperator() {
174+
this.hasName("operator*") and
175+
this.getDeclaringType() instanceof Iterator
176+
}
177+
178+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
179+
input.isQualifierObject() and
180+
output.isReturnValue()
181+
}
182+
}
183+
184+
/**
185+
* An `operator++` or `operator--` member function for an iterator type.
186+
*/
187+
class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction {
188+
IteratorCrementMemberOperator() {
189+
this.hasName(["operator++", "operator--"]) and
190+
this.getDeclaringType() instanceof Iterator
191+
}
192+
193+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
194+
input.isQualifierAddress() and
195+
output.isReturnValue()
196+
or
197+
input.isReturnValueDeref() and
198+
output.isQualifierObject()
199+
}
200+
201+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
202+
input.isQualifierObject() and
203+
output.isReturnValueDeref()
204+
}
205+
}
206+
207+
/**
208+
* A member `operator->` function for an iterator type.
209+
*/
210+
class IteratorFieldMemberOperator extends Operator, TaintFunction {
211+
IteratorFieldMemberOperator() {
212+
this.hasName("operator->") and
213+
this.getDeclaringType() instanceof Iterator
214+
}
215+
216+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
217+
input.isQualifierObject() and
218+
output.isReturnValue()
219+
}
220+
}
221+
222+
/**
223+
* An `operator+` or `operator-` member function of an iterator class.
224+
*/
225+
class IteratorBinaryArithmeticMemberOperator extends MemberFunction, TaintFunction {
226+
IteratorBinaryArithmeticMemberOperator() {
227+
this.hasName(["operator+", "operator-"]) and
228+
this.getDeclaringType() instanceof Iterator
229+
}
230+
231+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
232+
input.isQualifierObject() and
233+
output.isReturnValue()
234+
}
235+
}
236+
237+
/**
238+
* An `operator+=` or `operator-=` member function of an iterator class.
239+
*/
240+
class IteratorAssignArithmeticMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction {
241+
IteratorAssignArithmeticMemberOperator() {
242+
this.hasName(["operator+=", "operator-="]) and
243+
this.getDeclaringType() instanceof Iterator
244+
}
245+
246+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
247+
input.isQualifierAddress() and
248+
output.isReturnValue()
249+
or
250+
input.isReturnValueDeref() and
251+
output.isQualifierObject()
252+
}
253+
254+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
255+
input.isQualifierObject() and
256+
output.isReturnValueDeref()
257+
}
258+
}
259+
260+
/**
261+
* An `operator[]` member function of an iterator class.
262+
*/
263+
class IteratorArrayMemberOperator extends MemberFunction, TaintFunction {
264+
IteratorArrayMemberOperator() {
265+
this.hasName("operator[]") and
266+
this.getDeclaringType() instanceof Iterator
267+
}
268+
269+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
270+
input.isQualifierObject() and
271+
output.isReturnValue()
272+
}
273+
}

cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
/**
2+
* Provides implementation classes modeling `std::string` and other
3+
* instantiations of`std::basic_string`. See `semmle.code.cpp.models.Models`
4+
* for usage information.
5+
*/
6+
17
import semmle.code.cpp.models.interfaces.Taint
8+
import semmle.code.cpp.models.implementations.Iterator
29

310
/**
411
* The `std::basic_string` template class.
@@ -78,11 +85,17 @@ class StdStringAppend extends TaintFunction {
7885
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
7986
}
8087

88+
/**
89+
* Gets the index of a parameter to this function that is an iterator.
90+
*/
91+
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
92+
8193
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
8294
// flow from string and parameter to string (qualifier) and return value
8395
(
8496
input.isQualifierObject() or
85-
input.isParameterDeref(getAStringParameterIndex())
97+
input.isParameterDeref(getAStringParameterIndex()) or
98+
input.isParameter(getAnIteratorParameterIndex())
8699
) and
87100
(
88101
output.isQualifierObject() or
@@ -118,6 +131,28 @@ class StdStringAssign extends TaintFunction {
118131
}
119132
}
120133

134+
/**
135+
* The standard functions `std::string.begin` and `std::string.end` and their
136+
* variants.
137+
*/
138+
class StdStringBeginEnd extends TaintFunction {
139+
StdStringBeginEnd() {
140+
this.hasQualifiedName("std", "basic_string", "begin") or
141+
this.hasQualifiedName("std", "basic_string", "cbegin") or
142+
this.hasQualifiedName("std", "basic_string", "rbegin") or
143+
this.hasQualifiedName("std", "basic_string", "crbegin") or
144+
this.hasQualifiedName("std", "basic_string", "end") or
145+
this.hasQualifiedName("std", "basic_string", "cend") or
146+
this.hasQualifiedName("std", "basic_string", "rend") or
147+
this.hasQualifiedName("std", "basic_string", "crend")
148+
}
149+
150+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
151+
input.isQualifierObject() and
152+
output.isReturnValue()
153+
}
154+
}
155+
121156
/**
122157
* The standard function `std::string.copy`.
123158
*/

0 commit comments

Comments
 (0)