Skip to content

Commit c5dc883

Browse files
authored
Merge pull request #15528 from MathiasVP/flow-barrier-interface
C++: Add an interface for models to block flow
2 parents 7814861 + f7fe84a commit c5dc883

File tree

9 files changed

+83
-21
lines changed

9 files changed

+83
-21
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Added an abstract class `FlowOutBarrierFunction` that can be used to block flow out of a function.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ private import codeql.ssa.Ssa as SsaImplCommon
22
private import semmle.code.cpp.ir.IR
33
private import DataFlowUtil
44
private import DataFlowImplCommon as DataFlowImplCommon
5+
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
56
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
67
private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow
8+
private import semmle.code.cpp.models.interfaces.FlowOutBarrier as FOB
9+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
710
private import semmle.code.cpp.ir.internal.IRCppLanguage
811
private import DataFlowPrivate
912
private import ssa0.SsaInternals as SsaInternals0
@@ -784,10 +787,30 @@ private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
784787
)
785788
}
786789

790+
/**
791+
* Holds if there should not be use-use flow out of `n` (or a conversion that
792+
* flows to `n`).
793+
*/
794+
private predicate modeledFlowBarrier(Node n) {
795+
exists(FIO::FunctionInput input, CallInstruction call |
796+
call.getStaticCallTarget().(FOB::FlowOutBarrierFunction).isFlowOutBarrier(input) and
797+
n = callInput(call, input)
798+
)
799+
or
800+
exists(Operand operand, Instruction instr, Node n0, int indirectionIndex |
801+
modeledFlowBarrier(n0) and
802+
nodeHasInstruction(n0, instr, indirectionIndex) and
803+
conversionFlow(operand, instr, false, _) and
804+
nodeHasOperand(n, operand, indirectionIndex)
805+
)
806+
}
807+
787808
/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */
788809
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
789810
exists(Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
790-
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and nodeFrom != nodeTo
811+
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and
812+
not modeledFlowBarrier(nFrom) and
813+
nodeFrom != nodeTo
791814
|
792815
if uncertain = true then nodeFrom = [nFrom, getAPriorDefinition(defOrUse)] else nodeFrom = nFrom
793816
)

cpp/ql/lib/semmle/code/cpp/models/implementations/Swap.qll

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import semmle.code.cpp.models.interfaces.DataFlow
22
import semmle.code.cpp.models.interfaces.Taint
33
import semmle.code.cpp.models.interfaces.Alias
4+
import semmle.code.cpp.models.interfaces.FlowOutBarrier
45

56
/**
67
* The standard function `swap`. A use of `swap` looks like this:
78
* ```
89
* std::swap(obj1, obj2)
910
* ```
1011
*/
11-
private class Swap extends DataFlowFunction {
12+
private class Swap extends DataFlowFunction, FlowOutBarrierFunction {
1213
Swap() { this.hasQualifiedName(["std", "bsl"], "swap") }
1314

1415
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
@@ -18,6 +19,8 @@ private class Swap extends DataFlowFunction {
1819
input.isParameterDeref(1) and
1920
output.isParameterDeref(0)
2021
}
22+
23+
override predicate isFlowOutBarrier(FunctionInput input) { input.isParameterDeref(1) }
2124
}
2225

2326
/**
@@ -26,7 +29,9 @@ private class Swap extends DataFlowFunction {
2629
* obj1.swap(obj2)
2730
* ```
2831
*/
29-
private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction {
32+
private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction,
33+
FlowOutBarrierFunction
34+
{
3035
MemberSwap() {
3136
this.hasName("swap") and
3237
this.getNumberOfParameters() = 1 and
@@ -47,4 +52,8 @@ private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction {
4752
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
4853

4954
override predicate parameterIsAlwaysReturned(int index) { index = 0 }
55+
56+
override predicate isFlowOutBarrier(FunctionInput input) {
57+
input.isQualifierObject() or input.isParameterDeref(0)
58+
}
5059
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Provides an abstract class for blocking flow out of functions. To use this
3+
* QL library, create a QL class extending `FlowOutBarrierFunction` with a
4+
* characteristic predicate that selects the function or set of functions you
5+
* are modeling. Within that class, override the predicates provided by
6+
* `FlowOutBarrierFunction` to match the flow within that function.
7+
*/
8+
9+
import semmle.code.cpp.Function
10+
import FunctionInputsAndOutputs
11+
12+
/**
13+
* A library function for which flow should not continue after reaching one
14+
* of its inputs.
15+
*
16+
* For example, since `std::swap(a, b)` swaps the values pointed to by `a`
17+
* and `b` there should not be use-use flow out of `a` or `b`.
18+
*/
19+
abstract class FlowOutBarrierFunction extends Function {
20+
/**
21+
* Holds if use-use flow should not continue onwards after reaching
22+
* the argument, qualifier, or buffer represented by `input`.
23+
*/
24+
pragma[nomagic]
25+
abstract predicate isFlowOutBarrier(FunctionInput input);
26+
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ void test_pair()
7171
sink(i.second); // $ MISSING: ast,ir
7272
sink(i); // $ ast,ir
7373
sink(j.first);
74-
sink(j.second); // $ SPURIOUS: ast,ir
75-
sink(j); // $ SPURIOUS: ast,ir
74+
sink(j.second); // $ SPURIOUS: ast
75+
sink(j); // $ SPURIOUS: ast
7676
sink(k.first);
77-
sink(k.second); // $ SPURIOUS: ast,ir
78-
sink(k); // $ SPURIOUS: ast,ir
77+
sink(k.second); // $ SPURIOUS: ast
78+
sink(k); // $ SPURIOUS: ast
7979
sink(l.first);
8080
sink(l.second); // $ MISSING: ast,ir
8181
sink(l); // $ ast,ir
@@ -196,10 +196,10 @@ void test_map()
196196
sink(m18); // $ ast,ir
197197
m15.swap(m16);
198198
m17.swap(m18);
199-
sink(m15); // $ SPURIOUS: ast,ir
199+
sink(m15); // $ SPURIOUS: ast
200200
sink(m16); // $ ast,ir
201201
sink(m17); // $ ast,ir
202-
sink(m18); // $ SPURIOUS: ast,ir
202+
sink(m18); // $ SPURIOUS: ast
203203

204204
// merge
205205
std::map<char *, char *> m19, m20, m21, m22;
@@ -345,10 +345,10 @@ void test_unordered_map()
345345
sink(m18); // $ ast,ir
346346
m15.swap(m16);
347347
m17.swap(m18);
348-
sink(m15); // $ SPURIOUS: ast,ir
348+
sink(m15); // $ SPURIOUS: ast
349349
sink(m16); // $ ast,ir
350350
sink(m17); // $ ast,ir
351-
sink(m18); // $ SPURIOUS: ast,ir
351+
sink(m18); // $ SPURIOUS: ast
352352

353353
// merge
354354
std::unordered_map<char *, char *> m19, m20, m21, m22;

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ void test_set()
8181
sink(s15); // $ ast,ir
8282
s12.swap(s13);
8383
s14.swap(s15);
84-
sink(s12); // $ SPURIOUS: ast,ir
84+
sink(s12); // $ SPURIOUS: ast
8585
sink(s13); // $ ast,ir
8686
sink(s14); // $ ast,ir
87-
sink(s15); // $ SPURIOUS: ast,ir
87+
sink(s15); // $ SPURIOUS: ast
8888

8989
// merge
9090
std::set<char *> s16, s17, s18, s19;
@@ -193,10 +193,10 @@ void test_unordered_set()
193193
sink(s15); // $ ast,ir
194194
s12.swap(s13);
195195
s14.swap(s15);
196-
sink(s12); // $ SPURIOUS: ast,ir
196+
sink(s12); // $ SPURIOUS: ast
197197
sink(s13); // $ ast,ir
198198
sink(s14); // $ ast,ir
199-
sink(s15); // $ SPURIOUS: ast,ir
199+
sink(s15); // $ SPURIOUS: ast
200200

201201
// merge
202202
std::unordered_set<char *> s16, s17, s18, s19;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,9 @@ void test_string_swap() {
280280
s4.swap(s3);
281281

282282
sink(s1); // $ ast,ir
283-
sink(s2); // $ SPURIOUS: ast,ir
283+
sink(s2); // $ SPURIOUS: ast
284284
sink(s3); // $ ast,ir
285-
sink(s4); // $ SPURIOUS: ast,ir
285+
sink(s4); // $ SPURIOUS: ast
286286
}
287287

288288
void test_string_clear() {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ void test_stringstream_swap()
118118
ss4.swap(ss3);
119119

120120
sink(ss1); // $ ast,ir
121-
sink(ss2); // $ SPURIOUS: ast,ir
121+
sink(ss2); // $ SPURIOUS: ast
122122
sink(ss3); // $ ast,ir
123-
sink(ss4); // $ SPURIOUS: ast,ir
123+
sink(ss4); // $ SPURIOUS: ast
124124
}
125125

126126
void test_stringstream_in()

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ void test_vector_swap() {
114114
v1.swap(v2);
115115
v3.swap(v4);
116116

117-
sink(v1); // $ SPURIOUS: ast,ir
117+
sink(v1); // $ SPURIOUS: ast
118118
sink(v2); // $ ast,ir
119119
sink(v3); // $ ast,ir
120-
sink(v4); // $ SPURIOUS: ast,ir
120+
sink(v4); // $ SPURIOUS: ast
121121
}
122122

123123
void test_vector_clear() {

0 commit comments

Comments
 (0)