Skip to content

Commit e91d321

Browse files
authored
Merge pull request #4234 from geoffw0/stringstream
C++: Tests and initial models for taint through std::stringstream / std::ostream.
2 parents a1cec12 + d8bb49b commit e91d321

File tree

12 files changed

+754
-71
lines changed

12 files changed

+754
-71
lines changed

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2323
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.
2424
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
2525
* The models library now models many more taint flows through `std::string`.
26+
* The models library now models some taint flows through `std::ostream`.
2627
* The `SimpleRangeAnalysis` library now supports multiplications of the form
2728
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,17 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
9090
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
9191
call.getTarget() = f and
9292
inModel.isReturnValueDeref() and
93-
outModel.isQualifierObject() and
94-
f.hasTaintFlow(inModel, outModel) and
9593
nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = call and
96-
nodeTo.asDefiningArgument() = call.getQualifier()
94+
f.hasTaintFlow(inModel, outModel) and
95+
(
96+
outModel.isQualifierObject() and
97+
nodeTo.asDefiningArgument() = call.getQualifier()
98+
or
99+
exists(int argOutIndex |
100+
outModel.isParameterDeref(argOutIndex) and
101+
nodeTo.asDefiningArgument() = call.getArgument(argOutIndex)
102+
)
103+
)
97104
)
98105
}
99106

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

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
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.
2+
* Provides implementation classes modeling `std::string` (and other
3+
* instantiations of `std::basic_string`) and `std::ostream`. See
4+
* `semmle.code.cpp.models.Models` for usage information.
55
*/
66

77
import semmle.code.cpp.models.interfaces.Taint
@@ -287,3 +287,68 @@ class StdStringAt extends TaintFunction {
287287
output.isQualifierObject()
288288
}
289289
}
290+
291+
/**
292+
* The `std::basic_ostream` template class.
293+
*/
294+
class StdBasicOStream extends TemplateClass {
295+
StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") }
296+
}
297+
298+
/**
299+
* The `std::ostream` function `operator<<` (defined as a member function).
300+
*/
301+
class StdOStreamOut extends DataFlowFunction, TaintFunction {
302+
StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", "operator<<") }
303+
304+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
305+
// flow from qualifier to return value
306+
input.isQualifierAddress() and
307+
output.isReturnValue()
308+
}
309+
310+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
311+
// flow from parameter to qualifier
312+
input.isParameter(0) and
313+
output.isQualifierObject()
314+
or
315+
// flow from parameter to return value
316+
input.isParameter(0) and
317+
output.isReturnValueDeref()
318+
or
319+
// reverse flow from returned reference to the qualifier
320+
input.isReturnValueDeref() and
321+
output.isQualifierObject()
322+
}
323+
}
324+
325+
/**
326+
* The `std::ostream` function `operator<<` (defined as a non-member function).
327+
*/
328+
class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction {
329+
StdOStreamOutNonMember() {
330+
this.hasQualifiedName("std", "operator<<") and
331+
this.getUnspecifiedType().(ReferenceType).getBaseType() =
332+
any(StdBasicOStream s).getAnInstantiation()
333+
}
334+
335+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
336+
// flow from first parameter to return value
337+
input.isParameter(0) and
338+
output.isReturnValue()
339+
}
340+
341+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
342+
// flow from second parameter to first parameter
343+
input.isParameter(1) and
344+
output.isParameterDeref(0)
345+
or
346+
// flow from second parameter to return value
347+
input.isParameter(1) and
348+
output.isReturnValueDeref()
349+
or
350+
// reverse flow from returned reference to the first parameter
351+
input.isReturnValueDeref() and
352+
output.isParameterDeref(0)
353+
}
354+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ void test_stringstream()
8888
ss5 << t;
8989

9090
sink(ss1);
91-
sink(ss2); // tainted [NOT DETECTED]
91+
sink(ss2); // tainted
9292
sink(ss3); // tainted [NOT DETECTED]
93-
sink(ss4); // tainted [NOT DETECTED]
93+
sink(ss4); // tainted
9494
sink(ss5); // tainted [NOT DETECTED]
9595
sink(ss1.str());
96-
sink(ss2.str()); // tainted [NOT DETECTED]
96+
sink(ss2.str()); // tainted
9797
sink(ss3.str()); // tainted [NOT DETECTED]
98-
sink(ss4.str()); // tainted [NOT DETECTED]
98+
sink(ss4.str()); // tainted
9999
sink(ss5.str()); // tainted [NOT DETECTED]
100100
}
101101

cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,10 @@
197197
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv |
198198
| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam |
199199
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s |
200+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | p#0 |
200201
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | p#1 |
201202
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv |
203+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s |
202204
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a |
203205
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source |
204206
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source |
@@ -209,12 +211,31 @@
209211
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source |
210212
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... |
211213
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string |
214+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< |
215+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) |
212216
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source |
213217
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... |
218+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< |
219+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) |
214220
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source |
215221
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... |
222+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< |
223+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) |
224+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) |
216225
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source |
217226
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... |
227+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< |
228+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) |
229+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... |
230+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) |
231+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 |
232+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... |
233+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) |
234+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 |
235+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
236+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 |
237+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
238+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 |
218239
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source |
219240
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string |
220241
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input |

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,31 @@
6161
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:210:8:210:23 | ... + ... | IR only |
6262
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
6363
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
64+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | p#0 | IR only |
6465
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only |
66+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s | IR only |
6567
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only |
6668
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only |
69+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | IR only |
70+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | IR only |
71+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< | IR only |
72+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) | IR only |
73+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< | IR only |
74+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) | IR only |
75+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) | IR only |
6776
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only |
77+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | IR only |
78+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | IR only |
79+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... | IR only |
80+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) | IR only |
81+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | IR only |
82+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... | IR only |
83+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) | IR only |
84+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | IR only |
85+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... | IR only |
86+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | IR only |
87+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... | IR only |
88+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | IR only |
6889
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only |
6990
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only |
7091
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only |

0 commit comments

Comments
 (0)