Skip to content

Commit 0ba5921

Browse files
authored
Merge pull request github#4020 from jbj/taint-range-based-for-ast
C++: Taint through RangeBasedForStmt (AST only)
2 parents e3a12c5 + c8911ab commit 0ba5921

File tree

5 files changed

+138
-5
lines changed

5 files changed

+138
-5
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
6565
// tracking. The flow from expression `x` into `x++` etc. is handled in the
6666
// case above.
6767
exprTo = DataFlow::getAnAccessToAssignedVariable(exprFrom.(PostfixCrementOperation))
68+
or
69+
// In `for (char c : s) { ... c ... }`, this rule propagates taint from `s`
70+
// to `c`.
71+
exists(RangeBasedForStmt rbf |
72+
exprFrom = rbf.getRange() and
73+
// It's guaranteed up to at least C++20 that the range-based for loop
74+
// desugars to a variable with an initializer.
75+
exprTo = rbf.getVariable().getInitializer().getExpr()
76+
)
6877
)
6978
or
7079
// Taint can flow through modeled functions

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@
417417
| stl.cpp:239:15:239:15 | ref arg (__range) | stl.cpp:239:15:239:15 | (__range) | |
418418
| stl.cpp:239:15:239:15 | s | stl.cpp:239:15:239:15 | (__range) | |
419419
| stl.cpp:239:15:239:15 | s | stl.cpp:239:15:239:15 | (__range) | |
420+
| stl.cpp:239:15:239:15 | s | stl.cpp:239:15:239:15 | call to operator* | TAINT |
420421
| stl.cpp:243:33:243:33 | ref arg s | stl.cpp:243:50:243:50 | s | |
421422
| stl.cpp:243:33:243:33 | ref arg s | stl.cpp:247:16:247:16 | s | |
422423
| stl.cpp:243:35:243:39 | call to begin | stl.cpp:243:44:243:45 | it | |
@@ -438,6 +439,7 @@
438439
| stl.cpp:247:16:247:16 | ref arg (__range) | stl.cpp:247:16:247:16 | (__range) | |
439440
| stl.cpp:247:16:247:16 | s | stl.cpp:247:16:247:16 | (__range) | |
440441
| stl.cpp:247:16:247:16 | s | stl.cpp:247:16:247:16 | (__range) | |
442+
| stl.cpp:247:16:247:16 | s | stl.cpp:247:16:247:16 | call to operator* | TAINT |
441443
| stl.cpp:251:28:251:33 | call to source | stl.cpp:251:28:251:36 | call to basic_string | TAINT |
442444
| stl.cpp:251:28:251:36 | call to basic_string | stl.cpp:252:22:252:28 | const_s | |
443445
| stl.cpp:252:22:252:22 | call to begin | stl.cpp:252:22:252:22 | (__begin) | |
@@ -450,6 +452,61 @@
450452
| stl.cpp:252:22:252:22 | ref arg (__begin) | stl.cpp:252:22:252:22 | (__begin) | |
451453
| stl.cpp:252:22:252:28 | const_s | stl.cpp:252:22:252:22 | (__range) | |
452454
| stl.cpp:252:22:252:28 | const_s | stl.cpp:252:22:252:22 | (__range) | |
455+
| stl.cpp:252:22:252:28 | const_s | stl.cpp:252:22:252:22 | call to operator* | TAINT |
456+
| stl.cpp:288:43:288:49 | source1 | stl.cpp:292:21:292:27 | source1 | |
457+
| stl.cpp:288:43:288:49 | source1 | stl.cpp:306:33:306:39 | source1 | |
458+
| stl.cpp:292:21:292:27 | source1 | stl.cpp:292:21:292:28 | call to vector | TAINT |
459+
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:294:14:294:14 | v | |
460+
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:298:38:298:38 | v | |
461+
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:298:55:298:55 | v | |
462+
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:302:15:302:15 | v | |
463+
| stl.cpp:294:14:294:14 | call to begin | stl.cpp:294:14:294:14 | (__begin) | |
464+
| stl.cpp:294:14:294:14 | call to begin | stl.cpp:294:14:294:14 | (__begin) | |
465+
| stl.cpp:294:14:294:14 | call to begin | stl.cpp:294:14:294:14 | (__begin) | |
466+
| stl.cpp:294:14:294:14 | call to end | stl.cpp:294:14:294:14 | (__end) | |
467+
| stl.cpp:294:14:294:14 | call to operator* | stl.cpp:295:8:295:8 | x | |
468+
| stl.cpp:294:14:294:14 | ref arg (__begin) | stl.cpp:294:14:294:14 | (__begin) | |
469+
| stl.cpp:294:14:294:14 | ref arg (__begin) | stl.cpp:294:14:294:14 | (__begin) | |
470+
| stl.cpp:294:14:294:14 | ref arg (__begin) | stl.cpp:294:14:294:14 | (__begin) | |
471+
| stl.cpp:294:14:294:14 | ref arg (__range) | stl.cpp:294:14:294:14 | (__range) | |
472+
| stl.cpp:294:14:294:14 | v | stl.cpp:294:14:294:14 | (__range) | |
473+
| stl.cpp:294:14:294:14 | v | stl.cpp:294:14:294:14 | (__range) | |
474+
| stl.cpp:294:14:294:14 | v | stl.cpp:294:14:294:14 | call to operator* | TAINT |
475+
| stl.cpp:298:38:298:38 | ref arg v | stl.cpp:298:55:298:55 | v | |
476+
| stl.cpp:298:38:298:38 | ref arg v | stl.cpp:302:15:302:15 | v | |
477+
| stl.cpp:298:40:298:44 | call to begin | stl.cpp:298:49:298:50 | it | |
478+
| stl.cpp:298:40:298:44 | call to begin | stl.cpp:298:66:298:67 | it | |
479+
| stl.cpp:298:40:298:44 | call to begin | stl.cpp:299:9:299:10 | it | |
480+
| stl.cpp:298:55:298:55 | ref arg v | stl.cpp:298:55:298:55 | v | |
481+
| stl.cpp:298:55:298:55 | ref arg v | stl.cpp:302:15:302:15 | v | |
482+
| stl.cpp:298:66:298:67 | ref arg it | stl.cpp:298:49:298:50 | it | |
483+
| stl.cpp:298:66:298:67 | ref arg it | stl.cpp:298:66:298:67 | it | |
484+
| stl.cpp:298:66:298:67 | ref arg it | stl.cpp:299:9:299:10 | it | |
485+
| stl.cpp:302:15:302:15 | call to begin | stl.cpp:302:15:302:15 | (__begin) | |
486+
| stl.cpp:302:15:302:15 | call to begin | stl.cpp:302:15:302:15 | (__begin) | |
487+
| stl.cpp:302:15:302:15 | call to begin | stl.cpp:302:15:302:15 | (__begin) | |
488+
| stl.cpp:302:15:302:15 | call to end | stl.cpp:302:15:302:15 | (__end) | |
489+
| stl.cpp:302:15:302:15 | call to operator* | stl.cpp:303:8:303:8 | x | |
490+
| stl.cpp:302:15:302:15 | ref arg (__begin) | stl.cpp:302:15:302:15 | (__begin) | |
491+
| stl.cpp:302:15:302:15 | ref arg (__begin) | stl.cpp:302:15:302:15 | (__begin) | |
492+
| stl.cpp:302:15:302:15 | ref arg (__begin) | stl.cpp:302:15:302:15 | (__begin) | |
493+
| stl.cpp:302:15:302:15 | ref arg (__range) | stl.cpp:302:15:302:15 | (__range) | |
494+
| stl.cpp:302:15:302:15 | v | stl.cpp:302:15:302:15 | (__range) | |
495+
| stl.cpp:302:15:302:15 | v | stl.cpp:302:15:302:15 | (__range) | |
496+
| stl.cpp:302:15:302:15 | v | stl.cpp:302:15:302:15 | call to operator* | TAINT |
497+
| stl.cpp:306:33:306:39 | source1 | stl.cpp:306:33:306:40 | call to vector | TAINT |
498+
| stl.cpp:306:33:306:40 | call to vector | stl.cpp:307:21:307:27 | const_v | |
499+
| stl.cpp:307:21:307:21 | call to begin | stl.cpp:307:21:307:21 | (__begin) | |
500+
| stl.cpp:307:21:307:21 | call to begin | stl.cpp:307:21:307:21 | (__begin) | |
501+
| stl.cpp:307:21:307:21 | call to begin | stl.cpp:307:21:307:21 | (__begin) | |
502+
| stl.cpp:307:21:307:21 | call to end | stl.cpp:307:21:307:21 | (__end) | |
503+
| stl.cpp:307:21:307:21 | call to operator* | stl.cpp:308:8:308:8 | x | |
504+
| stl.cpp:307:21:307:21 | ref arg (__begin) | stl.cpp:307:21:307:21 | (__begin) | |
505+
| stl.cpp:307:21:307:21 | ref arg (__begin) | stl.cpp:307:21:307:21 | (__begin) | |
506+
| stl.cpp:307:21:307:21 | ref arg (__begin) | stl.cpp:307:21:307:21 | (__begin) | |
507+
| stl.cpp:307:21:307:27 | const_v | stl.cpp:307:21:307:21 | (__range) | |
508+
| stl.cpp:307:21:307:27 | const_v | stl.cpp:307:21:307:21 | (__range) | |
509+
| stl.cpp:307:21:307:27 | const_v | stl.cpp:307:21:307:21 | call to operator* | TAINT |
453510
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
454511
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
455512
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |

cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,22 +234,77 @@ void test_string_constructors_assignments()
234234

235235
void sink(char) {}
236236

237-
void test_range_based_for_loop() {
237+
void test_range_based_for_loop_string() {
238238
std::string s(source());
239239
for(char c : s) {
240-
sink(c); // tainted [NOT DETECTED]
240+
sink(c); // tainted [NOT DETECTED by IR]
241241
}
242242

243243
for(std::string::iterator it = s.begin(); it != s.end(); ++it) {
244244
sink(*it); // tainted [NOT DETECTED]
245245
}
246246

247247
for(char& c : s) {
248-
sink(c); // tainted [NOT DETECTED]
248+
sink(c); // tainted [NOT DETECTED by IR]
249249
}
250250

251251
const std::string const_s(source());
252252
for(const char& c : const_s) {
253-
sink(c); // tainted [NOT DETECTED]
253+
sink(c); // tainted [NOT DETECTED by IR]
254254
}
255-
}
255+
}
256+
257+
258+
259+
260+
261+
262+
263+
264+
namespace std {
265+
template <class T>
266+
class vector {
267+
private:
268+
void *data_;
269+
public:
270+
vector(int size);
271+
272+
T& operator[](int idx);
273+
const T& operator[](int idx) const;
274+
275+
typedef std::iterator<random_access_iterator_tag, T> iterator;
276+
typedef std::iterator<random_access_iterator_tag, const T> const_iterator;
277+
278+
iterator begin() noexcept;
279+
iterator end() noexcept;
280+
281+
const_iterator begin() const noexcept;
282+
const_iterator end() const noexcept;
283+
};
284+
}
285+
286+
void sink(int);
287+
288+
void test_range_based_for_loop_vector(int source1) {
289+
// Tainting the vector by allocating a tainted length. This doesn't represent
290+
// how a vector would typically get tainted, but it allows this test to avoid
291+
// being concerned with std::vector modeling.
292+
std::vector<int> v(source1);
293+
294+
for(int x : v) {
295+
sink(x); // tainted [NOT DETECTED by IR]
296+
}
297+
298+
for(std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
299+
sink(*it); // tainted [NOT DETECTED]
300+
}
301+
302+
for(int& x : v) {
303+
sink(x); // tainted [NOT DETECTED by IR]
304+
}
305+
306+
const std::vector<int> const_v(source1);
307+
for(const int& x : const_v) {
308+
sink(x); // tainted [NOT DETECTED by IR]
309+
}
310+
}

cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
| stl.cpp:211:8:211:9 | s3 | stl.cpp:207:8:207:13 | call to source |
4848
| stl.cpp:230:8:230:9 | s1 | stl.cpp:226:32:226:37 | call to source |
4949
| stl.cpp:231:8:231:9 | s2 | stl.cpp:228:20:228:25 | call to source |
50+
| stl.cpp:240:8:240:8 | c | stl.cpp:238:16:238:21 | call to source |
51+
| stl.cpp:248:8:248:8 | c | stl.cpp:238:16:238:21 | call to source |
52+
| stl.cpp:253:8:253:8 | c | stl.cpp:251:28:251:33 | call to source |
53+
| stl.cpp:295:8:295:8 | x | stl.cpp:288:43:288:49 | source1 |
54+
| stl.cpp:303:8:303:8 | x | stl.cpp:288:43:288:49 | source1 |
55+
| stl.cpp:308:8:308:8 | x | stl.cpp:288:43:288:49 | source1 |
5056
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
5157
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
5258
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |

cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
| stl.cpp:211:8:211:9 | stl.cpp:207:8:207:13 | AST only |
4545
| stl.cpp:230:8:230:9 | stl.cpp:226:32:226:37 | AST only |
4646
| stl.cpp:231:8:231:9 | stl.cpp:228:20:228:25 | AST only |
47+
| stl.cpp:240:8:240:8 | stl.cpp:238:16:238:21 | AST only |
48+
| stl.cpp:248:8:248:8 | stl.cpp:238:16:238:21 | AST only |
49+
| stl.cpp:253:8:253:8 | stl.cpp:251:28:251:33 | AST only |
50+
| stl.cpp:295:8:295:8 | stl.cpp:288:43:288:49 | AST only |
51+
| stl.cpp:303:8:303:8 | stl.cpp:288:43:288:49 | AST only |
52+
| stl.cpp:308:8:308:8 | stl.cpp:288:43:288:49 | AST only |
4753
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
4854
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
4955
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |

0 commit comments

Comments
 (0)