Skip to content

CPP: Model taint through std::string and std::stringstream #1637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion change-notes/1.23/analysis-cpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.

## Changes to QL libraries

- bullet list
- The library now models data flow through `std::string` and `std::stringstream`.
18 changes: 12 additions & 6 deletions cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -546,14 +546,20 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
toExpr.(LambdaExpression).getInitializer() = fromExpr
or
toExpr = any(Call call |
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel, int iIn |
call.getTarget() = f and
f.hasDataFlow(inModel, outModel) and
outModel.isOutReturnValue() and
inModel.isInParameter(iIn) and
fromExpr = call.getArgument(iIn)
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and
f.hasDataFlow(inModel, outModel) and
outModel.isOutReturnValue()
|
exists(int argInIndex |
inModel.isInParameter(argInIndex) and
fromExpr = call.getArgument(argInIndex)
)
or
inModel.isInQualifier() and
fromExpr = call.getQualifier()
)
)
}

private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
Expand Down
70 changes: 56 additions & 14 deletions cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
)
or
// Taint can flow through modeled functions
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr()) or
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
}

Expand Down Expand Up @@ -113,6 +114,39 @@ private predicate noFlowFromChildExpr(Expr e) {
e instanceof FieldAccess
}

private predicate exprToExprStep(Expr exprIn, Expr exprOut) {
exists(Call call, TaintFunction f, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and
f.hasTaintFlow(inModel, outModel) and
(
exists(int argInIndex |
inModel.isInParameterPointer(argInIndex) and
exprIn = call.getArgument(argInIndex)
) or exists(int argInIndex |
inModel.isInParameterPointer(argInIndex) and
call.passesByReference(argInIndex, exprIn)
) or exists(int argInIndex |
inModel.isInParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
) or (
inModel.isInQualifier() and
exprIn = call.getQualifier()
) or (
inModel.isInReturnValue() and
exprIn = call
)
) and (
(
outModel.isOutReturnValue() and
exprOut = call
) or exists(int argOutIndex |
outModel.isOutParameterPointer(argOutIndex) and
exprOut = call.getArgument(argOutIndex)
)
)
)
}

private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
exists(DataFlowFunction f, Call call, FunctionOutput outModel, int argOutIndex |
call.getTarget() = f and
Expand All @@ -128,21 +162,29 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
)
)
or
exists(TaintFunction f, Call call, FunctionOutput outModel, int argOutIndex |
exists(Call call, TaintFunction f, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and
argOut = call.getArgument(argOutIndex) and
outModel.isOutParameterPointer(argOutIndex) and
exists(int argInIndex, FunctionInput inModel |
f.hasTaintFlow(inModel, outModel)
|
inModel.isInParameterPointer(argInIndex) and
exprIn = call.getArgument(argInIndex)
or
inModel.isInParameterPointer(argInIndex) and
call.passesByReference(argInIndex, exprIn)
or
inModel.isInParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
f.hasTaintFlow(inModel, outModel) and
(
exists(int argInIndex |
inModel.isInParameterPointer(argInIndex) and
exprIn = call.getArgument(argInIndex)
) or exists(int argInIndex |
inModel.isInParameterPointer(argInIndex) and
call.passesByReference(argInIndex, exprIn)
) or exists(int argInIndex |
inModel.isInParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
) or (
inModel.isInQualifier() and
exprIn = call.getQualifier()
) or (
inModel.isInReturnValue() and
exprIn = call
)
) and exists(int argOutIndex |
outModel.isOutParameterPointer(argOutIndex) and
argOut = call.getArgument(argOutIndex)
)
)
}
1 change: 1 addition & 0 deletions cpp/ql/src/semmle/code/cpp/models/Models.qll
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ private import implementations.Pure
private import implementations.Strcat
private import implementations.Strcpy
private import implementations.Strftime
private import implementations.Strings
private import implementations.Swap
70 changes: 70 additions & 0 deletions cpp/ql/src/semmle/code/cpp/models/implementations/Strings.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint

/**
* The `std::basic_string` constructor(s).
*/
class StringConstructor extends DataFlowFunction {
StringConstructor() {
this.hasQualifiedName("std", "basic_string", "basic_string")
}

override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// flow from any constructor argument to return value
input.isInParameter(_) and
output.isOutReturnValue()
}
}

/**
* The standard function `std::string.c_str`.
*/
class StringCStr extends DataFlowFunction {
StringCStr() {
this.hasQualifiedName("std", "basic_string", "c_str")
}

override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// flow from string itself (qualifier) to return value
input.isInQualifier() and
output.isOutReturnValue()
}
}

/**
* The standard function `operator<<`, for example on `std::stringstream`.
*/
class InsertionOperator extends TaintFunction {
InsertionOperator() {
this.hasQualifiedName("std", "operator<<")
}

override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
// flow from second argument to return value
input.isInParameterPointer(1) and
output.isOutReturnValue()
) or (
// flow from return value to first argument
// (this is a bit odd; another way to think of it is the sink effectively
// flowing from the first argument to the return value)
input.isInReturnValue() and
output.isOutParameterPointer(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense for taint to come in through the return value. Can we model << in another way? How about saying that in a << b there's taint from b -> a, a -> return, and b -> return.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of:

ss3 << "123" << source();

i.e.

(ss3 << "123") << source();

taint needs to flow from the bracketed expression to ss3 somehow (in actuality I think the thing that's flowing is a reference to the sink, in the other direction, which is why my attempt at solving this looks so backwards).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand the problem now.

The ss3 argument should have a post-update node (a DefinitionByReferenceNode) since it's passed by mutable reference into operator<<. Does it work to add flow from (ss3 << "123") to the post-update node of ss3?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm understanding correctly this won't actually be a change to the model - you're still asking for flow from the return value to the first parameter. You just want the taint library to wire that up to the post-update node of that parameter?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I think I understand the problem now. It's the third time I think I understand it, so bear with me.

I think there are two things to be modelled about operator<<. The first is that it copies its first argument (a) to its return value (reference to reference). When that's put into the DataFlowFunction model, the taint-tracking library should be extended to add flow from pre-update a to pre-update call and from post-update call to pre-update a. The latter one goes backwards like in https://github.com/Semmle/ql/pull/1766/files#diff-255652465f915d69e8f3adeed3e96f11R238. The second thing to be modelled is the taint. I haven't thought this through completely, and I've got to leave now. I'll revisit this tomorrow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be more precise, I think these are the steps we want in the model of operator<<:

  • Data flow: isInParameter(0) --> isOutReturnValue()
  • Taint: isInParameterPointer(1) --> isOutReturnPointer()

We should really write some documentation in FunctionInputsAndOutputs.qll. Maybe the documentation is missing because we're still figuring out what each of the input/output kinds ought to mean for taint and data flow. I think that for pointer/reference types, the Value kinds (like isOutReturnValue) refer refer to the pointer itself, and the Pointer kinds (like isOutReturnPointer) refer to the contents that are pointed to. If that's the case, we should rename Pointer to Content or Pointee or something.

When a model specifies "parameter value" to "return value" data flow, I think the data flow library should add both forward flow between the pre-update nodes and backwards flow between the post-update nodes. I had at one point a plan to generalise https://github.com/Semmle/ql/pull/1766/files#diff-255652465f915d69e8f3adeed3e96f11R238 to add such backwards post-update flow everywhere that the right post-update nodes existed, but we decided that it was more sensible to add these cases one at a time. As an example of why we want such flow, consider an identity function on reference types: int& id(int &x) { return x; }. Adding backwards post-update flow would let us model id(id(a)) = source; as an assignment to a (assuming we have flow from pre-update RHS to post-update LHS of =).

When a model specifies flow to a Pointer output (the contents pointed to), I think the data flow (or taint flow) library should interpret that as flow into the appropriate post-update node. In this case, flow to isOutReturnPointer() goes to the post-update node for the operator<< call. Such a post-update node should be made to exist when the call itself is being used as an argument to a function that takes a pointer argument. It doesn't exist today -- that's one of the coverage gaps we talked about in #1900.

With this mapping in place between the models and the data flow library, I think it's going to work. Then we get the following data-flow edges for your example with (ss3 <<₁ "123") <<₂ source();, where ==> is taint, and --> is data flow:

# Edges for <<₁:
pre-ss3 --> pre-<<₁
post-<<₁ --> post-ss3 # backwards post-update flow
pre-"123" ==> post-<<₁

# Edges for <<₂:
pre-<<₁ --> pre-<<₂
post-<<₂ --> post-<<₁ # backwards post-update flow
pre-source() ==> post-<<₂

In that graph, there is a path from pre-source() to post-ss3 as desired.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've discussed this with @aschackmull. The Java library has a StringBuilder class that is more or less equivalent to std::stringstream. Calls like sb.append(s1).append(s2) are modelled by introducing a concept of the "initial qualifier" on a chain of calls -- sb in this case. For C++ we'd prefer to do this modelling only on the Function and not on the Call, and I think that's possible.

When a model specifies flow to a Pointer output (the contents pointed to), I think the data flow (or taint flow) library should interpret that as flow into the appropriate post-update node.

The post-update node I mentioned above may not exist. I'd like to try and investigate whether a Call can be its own post-update node.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the two-rule modelling of operator<< that I proposed in #1637 (comment) was too "clever", relying on flow through post-order nodes of calls that happened to exist in some cases but only by coincidence. Here's how I now think we should model operator<<, using the terminology of #1938. It's the same as what I wrote in #1637 (comment), but this time I'm being precise about what's pre and what's post.

  • Data flow: isParameter(0) --> isReturnValue(). On a << b, this should give data flow from pre-a to pre-<< and from post-<< to post-a.
  • Taint: isParameterDeref(1) --> isReturnValueDeref(). On a << b, this should give taint flow from pre-b to pre-<<. I'd previously claimed this should go to post-<<, but that doesn't exist in general for a call, and the "post-result" of a call is just the result.
  • Taint: isParameterDeref(1) --> isParameterDeref(0). On a << b, this should give taint flow from pre-b to post-a.

That gives us the following edges for (ss3 <<₁ "123") <<₂ source();, where there exists a path from pre-source() to post-ss3.

# Edges for <<₁:
pre-ss3 --> pre-<<₁ # due to isInParameter(0) --> isOutReturnValue()
post-<<₁ --> post-ss3 # backwards post-update flow of the above
pre-"123" ==> pre-<<₁ # due to isParameterDeref(1) --> isReturnValueDeref()
pre-"123" ==> post-ss3 # due to isParameterDeref(1) --> isParameterDeref(0)

# Edges for <<₂:
pre-<<₁ --> pre-<<₂ # due to isInParameter(0) --> isOutReturnValue()
# post-<<₂ --> post-<<₁ # (there is no post-<<₂ node)
pre-source() ==> pre-<<₂ # due to isParameterDeref(1) --> isReturnValueDeref()
pre-source() ==> post-<<₁ # due to isParameterDeref(1) --> isParameterDeref(0)

)
}
}

/**
* The standard function `std::stringstream.str`.
*/
class StringStreamStr extends TaintFunction {
StringStreamStr() {
this.hasQualifiedName("std", "basic_stringstream", "str")
}

override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from object itself (qualifier) to return value
input.isInQualifier() and
output.isOutReturnValue()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ newtype TFunctionInput =
TInParameterPointer(ParameterIndex i)
or
TInQualifier()
or
TInReturnValue()

class FunctionInput extends TFunctionInput {
abstract string toString();
Expand All @@ -34,6 +36,10 @@ class FunctionInput extends TFunctionInput {
predicate isInQualifier() {
none()
}

predicate isInReturnValue() {
none()
}
}

class InParameter extends FunctionInput, TInParameter {
Expand Down Expand Up @@ -86,6 +92,16 @@ class InQualifier extends FunctionInput, TInQualifier {
}
}

class InReturnValue extends FunctionInput, TInReturnValue {
override string toString() {
result = "InReturnValue"
}

override predicate isInReturnValue() {
any()
}
}

newtype TFunctionOutput =
TOutParameterPointer(ParameterIndex i)
or
Expand Down
54 changes: 54 additions & 0 deletions cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
| stl.cpp:65:12:65:17 | call to source | stl.cpp:69:7:69:7 | a | |
| stl.cpp:66:16:66:20 | 123 | stl.cpp:66:16:66:21 | call to basic_string | |
| stl.cpp:66:16:66:21 | call to basic_string | stl.cpp:70:7:70:7 | b | |
| stl.cpp:66:16:66:21 | call to basic_string | stl.cpp:72:7:72:7 | b | |
| stl.cpp:67:16:67:21 | call to source | stl.cpp:67:16:67:24 | call to basic_string | |
| stl.cpp:67:16:67:24 | call to basic_string | stl.cpp:71:7:71:7 | c | |
| stl.cpp:67:16:67:24 | call to basic_string | stl.cpp:73:7:73:7 | c | |
| stl.cpp:72:7:72:7 | b | stl.cpp:72:9:72:13 | call to c_str | |
| stl.cpp:72:7:72:7 | b [post update] | stl.cpp:72:9:72:13 | call to c_str | |
| stl.cpp:73:7:73:7 | c | stl.cpp:73:9:73:13 | call to c_str | |
| stl.cpp:73:7:73:7 | c [post update] | stl.cpp:73:9:73:13 | call to c_str | |
| stl.cpp:78:20:78:22 | call to basic_stringstream | stl.cpp:81:2:81:4 | ss1 | |
| stl.cpp:78:20:78:22 | call to basic_stringstream | stl.cpp:86:7:86:9 | ss1 | |
| stl.cpp:78:20:78:22 | call to basic_stringstream | stl.cpp:90:7:90:9 | ss1 | |
| stl.cpp:78:25:78:27 | call to basic_stringstream | stl.cpp:82:2:82:4 | ss2 | |
| stl.cpp:78:25:78:27 | call to basic_stringstream | stl.cpp:87:7:87:9 | ss2 | |
| stl.cpp:78:25:78:27 | call to basic_stringstream | stl.cpp:91:7:91:9 | ss2 | |
| stl.cpp:78:30:78:32 | call to basic_stringstream | stl.cpp:83:2:83:4 | ss3 | |
| stl.cpp:78:30:78:32 | call to basic_stringstream | stl.cpp:88:7:88:9 | ss3 | |
| stl.cpp:78:30:78:32 | call to basic_stringstream | stl.cpp:92:7:92:9 | ss3 | |
| stl.cpp:78:35:78:37 | call to basic_stringstream | stl.cpp:84:2:84:4 | ss4 | |
| stl.cpp:78:35:78:37 | call to basic_stringstream | stl.cpp:89:7:89:9 | ss4 | |
| stl.cpp:78:35:78:37 | call to basic_stringstream | stl.cpp:93:7:93:9 | ss4 | |
| stl.cpp:79:16:79:21 | call to source | stl.cpp:79:16:79:24 | call to basic_string | |
| stl.cpp:79:16:79:24 | call to basic_string | stl.cpp:84:9:84:9 | t | |
| stl.cpp:81:2:81:4 | ref arg ss1 | stl.cpp:86:7:86:9 | ss1 | |
| stl.cpp:81:2:81:4 | ref arg ss1 | stl.cpp:90:7:90:9 | ss1 | |
| stl.cpp:81:6:81:6 | call to operator<< | stl.cpp:81:2:81:4 | ref arg ss1 | TAINT |
| stl.cpp:81:6:81:6 | call to operator<< | stl.cpp:81:2:81:4 | ss1 | TAINT |
| stl.cpp:81:9:81:14 | 1234 | stl.cpp:81:6:81:6 | call to operator<< | TAINT |
| stl.cpp:82:2:82:4 | ref arg ss2 | stl.cpp:87:7:87:9 | ss2 | |
| stl.cpp:82:2:82:4 | ref arg ss2 | stl.cpp:91:7:91:9 | ss2 | |
| stl.cpp:82:6:82:6 | call to operator<< | stl.cpp:82:2:82:4 | ref arg ss2 | TAINT |
| stl.cpp:82:6:82:6 | call to operator<< | stl.cpp:82:2:82:4 | ss2 | TAINT |
| stl.cpp:82:9:82:14 | call to source | stl.cpp:82:6:82:6 | call to operator<< | TAINT |
| stl.cpp:83:2:83:4 | ref arg ss3 | stl.cpp:88:7:88:9 | ss3 | |
| stl.cpp:83:2:83:4 | ref arg ss3 | stl.cpp:92:7:92:9 | ss3 | |
| stl.cpp:83:6:83:6 | call to operator<< | stl.cpp:83:2:83:4 | ref arg ss3 | TAINT |
| stl.cpp:83:6:83:6 | call to operator<< | stl.cpp:83:2:83:4 | ss3 | TAINT |
| stl.cpp:83:9:83:13 | 123 | stl.cpp:83:6:83:6 | call to operator<< | TAINT |
| stl.cpp:83:15:83:15 | call to operator<< | stl.cpp:83:6:83:6 | call to operator<< | TAINT |
| stl.cpp:83:18:83:23 | call to source | stl.cpp:83:15:83:15 | call to operator<< | TAINT |
| stl.cpp:84:2:84:4 | ref arg ss4 | stl.cpp:89:7:89:9 | ss4 | |
| stl.cpp:84:2:84:4 | ref arg ss4 | stl.cpp:93:7:93:9 | ss4 | |
| stl.cpp:84:6:84:6 | call to operator<< | stl.cpp:84:2:84:4 | ref arg ss4 | TAINT |
| stl.cpp:84:6:84:6 | call to operator<< | stl.cpp:84:2:84:4 | ss4 | TAINT |
| stl.cpp:84:9:84:9 | t | stl.cpp:84:6:84:6 | call to operator<< | TAINT |
| stl.cpp:90:7:90:9 | ss1 | stl.cpp:90:11:90:13 | call to str | TAINT |
| stl.cpp:91:7:91:9 | ss2 | stl.cpp:91:11:91:13 | call to str | TAINT |
| stl.cpp:92:7:92:9 | ss3 | stl.cpp:92:11:92:13 | call to str | TAINT |
| stl.cpp:93:7:93:9 | ss4 | stl.cpp:93:11:93:13 | call to str | TAINT |
| taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | |
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | |
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | |
Expand Down Expand Up @@ -142,9 +193,11 @@
| taint.cpp:171:8:171:13 | ref arg buffer | taint.cpp:172:10:172:15 | buffer | |
| taint.cpp:171:8:171:13 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | |
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:3:172:8 | call to strcat | |
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | buffer | TAINT |
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:172:3:172:8 | call to strcat | |
| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | |
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | buffer | TAINT |
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
| taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | |
| taint.cpp:181:9:181:9 | p | taint.cpp:181:8:181:9 | * ... | TAINT |
Expand All @@ -158,6 +211,7 @@
| taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:195:7:195:7 | x | |
| taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | TAINT |
| taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
| taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:9:194:10 | & ... | TAINT |
| taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
| taint.cpp:207:6:207:11 | call to source | taint.cpp:207:2:207:13 | ... = ... | |
| taint.cpp:207:6:207:11 | call to source | taint.cpp:210:7:210:7 | x | |
Expand Down
38 changes: 38 additions & 0 deletions cpp/ql/test/library-tests/dataflow/taint-tests/models.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
| stl.cpp:66:16:66:21 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 0 | OutReturnValue |
| stl.cpp:66:16:66:21 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 1 | OutReturnValue |
| stl.cpp:66:16:66:21 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 2 | OutReturnValue |
| stl.cpp:67:16:67:24 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 0 | OutReturnValue |
| stl.cpp:67:16:67:24 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 1 | OutReturnValue |
| stl.cpp:67:16:67:24 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 2 | OutReturnValue |
| stl.cpp:72:9:72:13 | call to c_str | stl.cpp:21:16:21:20 | c_str | dataflow | InQualifier | OutReturnValue |
| stl.cpp:73:9:73:13 | call to c_str | stl.cpp:21:16:21:20 | c_str | dataflow | InQualifier | OutReturnValue |
| stl.cpp:79:16:79:24 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 0 | OutReturnValue |
| stl.cpp:79:16:79:24 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 1 | OutReturnValue |
| stl.cpp:79:16:79:24 | call to basic_string | stl.cpp:19:3:19:14 | basic_string | dataflow | InParameter 2 | OutReturnValue |
| stl.cpp:81:6:81:6 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InParameterPointer 1 | OutReturnValue |
| stl.cpp:81:6:81:6 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InReturnValue | OutParameterPointer 0 |
| stl.cpp:82:6:82:6 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InParameterPointer 1 | OutReturnValue |
| stl.cpp:82:6:82:6 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InReturnValue | OutParameterPointer 0 |
| stl.cpp:83:6:83:6 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InParameterPointer 1 | OutReturnValue |
| stl.cpp:83:6:83:6 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InReturnValue | OutParameterPointer 0 |
| stl.cpp:83:15:83:15 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InParameterPointer 1 | OutReturnValue |
| stl.cpp:83:15:83:15 | call to operator<< | stl.cpp:39:67:39:76 | operator<< | taint | InReturnValue | OutParameterPointer 0 |
| stl.cpp:84:6:84:6 | call to operator<< | stl.cpp:40:85:40:94 | operator<< | taint | InParameterPointer 1 | OutReturnValue |
| stl.cpp:84:6:84:6 | call to operator<< | stl.cpp:40:85:40:94 | operator<< | taint | InReturnValue | OutParameterPointer 0 |
| stl.cpp:90:11:90:13 | call to str | stl.cpp:52:42:52:44 | str | taint | InQualifier | OutReturnValue |
| stl.cpp:91:11:91:13 | call to str | stl.cpp:52:42:52:44 | str | taint | InQualifier | OutReturnValue |
| stl.cpp:92:11:92:13 | call to str | stl.cpp:52:42:52:44 | str | taint | InQualifier | OutReturnValue |
| stl.cpp:93:11:93:13 | call to str | stl.cpp:52:42:52:44 | str | taint | InQualifier | OutReturnValue |
| taint.cpp:170:3:170:8 | call to strcpy | taint.cpp:156:7:156:12 | strcpy | dataflow | InParameter 0 | OutReturnValue |
| taint.cpp:170:3:170:8 | call to strcpy | taint.cpp:156:7:156:12 | strcpy | dataflow | InParameterPointer 1 | OutParameterPointer 0 |
| taint.cpp:170:3:170:8 | call to strcpy | taint.cpp:156:7:156:12 | strcpy | dataflow | InParameterPointer 1 | OutReturnPointer |
| taint.cpp:172:3:172:8 | call to strcat | taint.cpp:157:7:157:12 | strcat | dataflow | InParameter 0 | OutReturnValue |
| taint.cpp:172:3:172:8 | call to strcat | taint.cpp:157:7:157:12 | strcat | taint | InParameter 1 | OutParameterPointer 0 |
| taint.cpp:172:3:172:8 | call to strcat | taint.cpp:157:7:157:12 | strcat | taint | InParameterPointer 0 | OutParameterPointer 0 |
| taint.cpp:194:2:194:7 | call to memcpy | taint.cpp:190:7:190:12 | memcpy | dataflow | InParameter 0 | OutReturnValue |
| taint.cpp:194:2:194:7 | call to memcpy | taint.cpp:190:7:190:12 | memcpy | dataflow | InParameterPointer 1 | OutParameterPointer 0 |
| taint.cpp:194:2:194:7 | call to memcpy | taint.cpp:190:7:190:12 | memcpy | dataflow | InParameterPointer 1 | OutReturnPointer |
| taint.cpp:194:2:194:7 | call to memcpy | taint.cpp:190:7:190:12 | memcpy | taint | InParameter 2 | OutParameterPointer 0 |
| taint.cpp:194:2:194:7 | call to memcpy | taint.cpp:190:7:190:12 | memcpy | taint | InParameter 2 | OutReturnPointer |
| taint.cpp:213:2:213:10 | call to swap | taint.cpp:201:35:201:38 | swap | dataflow | InParameterPointer 0 | OutParameterPointer 1 |
| taint.cpp:213:2:213:10 | call to swap | taint.cpp:201:35:201:38 | swap | dataflow | InParameterPointer 1 | OutParameterPointer 0 |
19 changes: 19 additions & 0 deletions cpp/ql/test/library-tests/dataflow/taint-tests/models.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint

from FunctionCall fc, Function f, string str, FunctionInput inModel, FunctionOutput outModel
where
fc.getTarget() = f and
(
(
f.(TaintFunction).hasTaintFlow(inModel, outModel) and
str = "taint"
) or (
f.(DataFlowFunction).hasDataFlow(inModel, outModel) and
str = "dataflow"
)
)
select
fc, f, str, inModel, outModel
Loading