Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3fce971

Browse files
author
Dave Bartolomeo
committed
Fix taint propagation to qualifier objects and update test expectations
1 parent 8666805 commit 3fce971

4 files changed

Lines changed: 171 additions & 83 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
8383
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
8484

8585
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
86-
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
86+
commonTaintStep(n1, n2)
8787
}
8888

8989
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
@@ -101,7 +101,7 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
101101
}
102102

103103
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
104-
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
104+
commonTaintStep(n1, n2)
105105
or
106106
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
107107
or
@@ -125,7 +125,7 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
125125
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
126126

127127
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
128-
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
128+
commonTaintStep(n1, n2)
129129
or
130130
// Additional step for flow out of variables. There is no flow _into_
131131
// variables in this configuration, so this step only serves to take flow
@@ -215,19 +215,62 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) {
215215
}
216216

217217
cached
218-
private predicate instructionTaintStep(Instruction i1, Instruction i2) {
218+
private predicate commonTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
219+
instructionToInstructionTaintStep(fromNode.asInstruction(), toNode.asInstruction())
220+
or
221+
operandToInstructionTaintStep(fromNode.asOperand(), toNode.asInstruction())
222+
or
223+
operandToOperandTaintStep(fromNode.asOperand(), toNode.asOperand())
224+
}
225+
226+
private predicate operandToOperandTaintStep(Operand fromOperand, Operand toOperand) {
227+
exists(ReadSideEffectInstruction readInstr |
228+
fromOperand = readInstr.getArgumentOperand() and
229+
toOperand = readInstr.getSideEffectOperand()
230+
)
231+
}
232+
233+
private predicate operandToInstructionTaintStep(Operand fromOperand, Instruction toInstr) {
219234
// Expressions computed from tainted data are also tainted
220-
exists(CallInstruction call, int argIndex | call = i2 |
235+
exists(CallInstruction call, int argIndex | call = toInstr |
221236
isPureFunction(call.getStaticCallTarget().getName()) and
222-
i1 = getACallArgumentOrIndirection(call, argIndex) and
223-
forall(Instruction arg | arg = call.getAnArgument() |
224-
arg = getACallArgumentOrIndirection(call, argIndex) or predictableInstruction(arg)
237+
fromOperand = getACallArgumentOrIndirection(call, argIndex) and
238+
forall(Operand argOperand | argOperand = call.getAnArgumentOperand() |
239+
argOperand = getACallArgumentOrIndirection(call, argIndex) or
240+
predictableInstruction(argOperand.getAnyDef())
225241
) and
226242
// flow through `strlen` tends to cause dubious results, if the length is
227243
// bounded.
228244
not call.getStaticCallTarget().getName() = "strlen"
229245
)
230246
or
247+
// Flow from argument to return value
248+
toInstr =
249+
any(CallInstruction call |
250+
exists(int indexIn |
251+
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
252+
fromOperand = getACallArgumentOrIndirection(call, indexIn) and
253+
not predictableOnlyFlow(call.getStaticCallTarget().getName())
254+
)
255+
)
256+
or
257+
// Flow from input argument to output argument
258+
// TODO: This won't work in practice as long as all aliased memory is tracked
259+
// together in a single virtual variable.
260+
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
261+
// is a pointer addition expression?
262+
toInstr =
263+
any(WriteSideEffectInstruction outInstr |
264+
exists(CallInstruction call, int indexIn, int indexOut |
265+
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
266+
fromOperand = getACallArgumentOrIndirection(call, indexIn) and
267+
outInstr.getIndex() = indexOut and
268+
outInstr.getPrimaryInstruction() = call
269+
)
270+
)
271+
}
272+
273+
private predicate instructionToInstructionTaintStep(Instruction i1, Instruction i2) {
231274
// Flow through pointer dereference
232275
i2.(LoadInstruction).getSourceAddress() = i1
233276
or
@@ -291,31 +334,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
291334
read.getAnOperand().(SideEffectOperand).getAnyDef() = i1 and
292335
read.getArgumentDef() = i2
293336
)
294-
or
295-
// Flow from argument to return value
296-
i2 =
297-
any(CallInstruction call |
298-
exists(int indexIn |
299-
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
300-
i1 = getACallArgumentOrIndirection(call, indexIn) and
301-
not predictableOnlyFlow(call.getStaticCallTarget().getName())
302-
)
303-
)
304-
or
305-
// Flow from input argument to output argument
306-
// TODO: This won't work in practice as long as all aliased memory is tracked
307-
// together in a single virtual variable.
308-
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
309-
// is a pointer addition expression?
310-
i2 =
311-
any(WriteSideEffectInstruction outNode |
312-
exists(CallInstruction call, int indexIn, int indexOut |
313-
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
314-
i1 = getACallArgumentOrIndirection(call, indexIn) and
315-
outNode.getIndex() = indexOut and
316-
outNode.getPrimaryInstruction() = call
317-
)
318-
)
319337
}
320338

321339
pragma[noinline]
@@ -331,15 +349,25 @@ private InitializeParameterInstruction getInitializeParameter(IRFunction f, Para
331349
}
332350

333351
/**
334-
* Get an instruction that goes into argument `argumentIndex` of `call`. This
352+
* Returns the index of the side effect instruction corresponding to the specified function output,
353+
* if one exists.
354+
*/
355+
private int getWriteSideEffectIndex(FunctionOutput output) {
356+
output.isParameterDeref(result)
357+
or
358+
output.isQualifierObject() and result = -1
359+
}
360+
361+
/**
362+
* Get an operand that goes into argument `argumentIndex` of `call`. This
335363
* can be either directly or through one pointer indirection.
336364
*/
337-
private Instruction getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
338-
result = call.getPositionalArgument(argumentIndex)
365+
private Operand getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
366+
result = call.getPositionalArgumentOperand(argumentIndex)
339367
or
340368
exists(ReadSideEffectInstruction readSE |
341369
// TODO: why are read side effect operands imprecise?
342-
result = readSE.getSideEffectOperand().getAnyDef() and
370+
result = readSE.getSideEffectOperand() and
343371
readSE.getPrimaryInstruction() = call and
344372
readSE.getIndex() = argumentIndex
345373
)
@@ -353,7 +381,7 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
353381
f.(TaintFunction).hasTaintFlow(modelIn, modelOut)
354382
) and
355383
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
356-
modelOut.isParameterDeref(parameterOut)
384+
parameterOut = getWriteSideEffectIndex(modelOut)
357385
)
358386
}
359387

@@ -542,7 +570,7 @@ module TaintedWithPath {
542570
}
543571

544572
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
545-
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
573+
commonTaintStep(n1, n2)
546574
or
547575
exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() |
548576
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ void test_string()
7171

7272
sink(a); // tainted
7373
sink(b);
74-
sink(c); // tainted [NOT DETECTED]
74+
sink(c); // tainted
7575
sink(b.c_str());
76-
sink(c.c_str()); // tainted [NOT DETECTED]
76+
sink(c.c_str()); // tainted
7777
}
7878

7979
void test_stringstream()
@@ -91,12 +91,12 @@ void test_stringstream()
9191
sink(ss2); // tainted
9292
sink(ss3); // tainted [NOT DETECTED]
9393
sink(ss4); // tainted
94-
sink(ss5); // tainted [NOT DETECTED]
94+
sink(ss5); // tainted
9595
sink(ss1.str());
9696
sink(ss2.str()); // tainted
9797
sink(ss3.str()); // tainted [NOT DETECTED]
9898
sink(ss4.str()); // tainted
99-
sink(ss5.str()); // tainted [NOT DETECTED]
99+
sink(ss5.str()); // tainted
100100
}
101101

102102
void test_stringstream_int(int source)
@@ -123,14 +123,14 @@ void sink(const char *filename, const char *mode);
123123
void test_strings2()
124124
{
125125
string path1 = user_input();
126-
sink(path1.c_str(), "r"); // tainted [NOT DETECTED]
126+
sink(path1.c_str(), "r"); // tainted
127127

128128
string path2;
129129
path2 = user_input();
130130
sink(path2.c_str(), "r"); // tainted
131131

132132
string path3(user_input());
133-
sink(path3.c_str(), "r"); // tainted [NOT DETECTED]
133+
sink(path3.c_str(), "r"); // tainted
134134
}
135135

136136
void test_string3()
@@ -141,7 +141,7 @@ void test_string3()
141141
std::string ss(cs);
142142

143143
sink(cs); // tainted
144-
sink(ss); // tainted [NOT DETECTED]
144+
sink(ss); // tainted
145145
}
146146

147147
void test_string4()
@@ -155,5 +155,5 @@ void test_string4()
155155
cs = ss.c_str();
156156

157157
sink(cs); // tainted [NOT DETECTED]
158-
sink(ss); // tainted [NOT DETECTED]
158+
sink(ss); // tainted
159159
}

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) |
9191
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv |
9292
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) |
93+
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object |
9394
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam |
9495
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:42:91:44 | arg |
9596
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:12:92:14 | arg |
@@ -176,7 +177,9 @@
176177
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s |
177178
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | (unnamed parameter 0) |
178179
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | (unnamed parameter 1) |
180+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:44:176:44:178 | str |
179181
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv |
182+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:63:30:63:30 | s |
180183
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s |
181184
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a |
182185
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source |
@@ -185,6 +188,11 @@
185188
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string |
186189
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... |
187190
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a |
191+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (const string)... |
192+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (reference to) |
193+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c |
194+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
195+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c |
188196
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source |
189197
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... |
190198
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string |
@@ -203,40 +211,63 @@
203211
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... |
204212
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< |
205213
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) |
214+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:6 | call to operator<< |
215+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:10 | (reference dereference) |
216+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
217+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (reference to) |
218+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t |
206219
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... |
207220
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) |
208221
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 |
209222
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... |
210223
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) |
211224
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 |
225+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (const stringstream)... |
226+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (reference to) |
227+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | ss5 |
212228
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
213229
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 |
214230
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
215231
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 |
232+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
233+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | ss5 |
216234
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source |
217235
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string |
218236
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input |
219237
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... |
238+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
239+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 |
220240
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 |
221241
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input |
222242
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... |
223243
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string |
244+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object |
224245
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
225246
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 |
226247
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input |
227248
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... |
228249
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string |
250+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
251+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 |
229252
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs |
230253
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source |
231254
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... |
232255
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs |
233256
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string |
234257
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs |
258+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (const string)... |
259+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (reference to) |
260+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss |
235261
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs |
236262
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source |
237263
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... |
238264
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs |
239265
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string |
266+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
267+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss |
268+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (const string)... |
269+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (reference to) |
270+
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss |
240271
| test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam |
241272
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv |
242273
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... |

0 commit comments

Comments
 (0)