Skip to content

Commit f17b563

Browse files
committed
C++: handle interprocedural flows
This currently copy-pastes some predicates from InvalidPointerDeref.ql. Those should be moved to a library file in a followup
1 parent 99d7512 commit f17b563

File tree

2 files changed

+100
-20
lines changed

2 files changed

+100
-20
lines changed

cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,98 @@
44
*/
55

66
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
7-
import experimental.semmle.code.cpp.rangeanalysis.Bound
7+
import experimental.semmle.code.cpp.semantic.SemanticBound
88
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
99
import semmle.code.cpp.ir.IR
1010
import experimental.semmle.code.cpp.ir.dataflow.DataFlow
11+
import experimental.semmle.code.cpp.ir.dataflow.DataFlow2
12+
13+
pragma[nomagic]
14+
Instruction getABoundIn(SemBound b, IRFunction func) {
15+
result = b.getExpr(0) and
16+
result.getEnclosingIRFunction() = func
17+
}
18+
19+
/**
20+
* Holds if `i <= b + delta`.
21+
*/
22+
pragma[nomagic]
23+
predicate bounded(Instruction i, Instruction b, int delta) {
24+
exists(SemBound bound, IRFunction func |
25+
semBounded(getSemanticExpr(i), bound, delta, true, _) and
26+
b = getABoundIn(bound, func) and
27+
i.getEnclosingIRFunction() = func
28+
)
29+
}
30+
31+
class FieldAddressToPointerArithmeticConf extends DataFlow::Configuration {
32+
FieldAddressToPointerArithmeticConf() { this = "FieldAddressToPointerArithmeticConf" }
33+
34+
override predicate isSource(DataFlow::Node source) { isFieldAddressSource(_, source) }
35+
36+
override predicate isSink(DataFlow::Node sink) {
37+
exists(PointerAddInstruction pai | pai.getLeft() = sink.asInstruction())
38+
}
39+
}
40+
41+
predicate isFieldAddressSource(Field f, DataFlow::Node source) {
42+
source.asInstruction().(FieldAddressInstruction).getField() = f
43+
}
44+
45+
/**
46+
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
47+
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
48+
* reads from an address that non-strictly upper-bounds `sink`.
49+
*/
50+
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
51+
exists(AddressOperand addr, int delta |
52+
bounded(addr.getDef(), sink.asInstruction(), delta) and
53+
delta >= 0 and
54+
i.getAnOperand() = addr
55+
|
56+
i instanceof StoreInstruction and
57+
operation = "write"
58+
or
59+
i instanceof LoadInstruction and
60+
operation = "read"
61+
)
62+
}
63+
64+
predicate isConstantSizeOverflowSource(Field f, PointerAddInstruction pai, int delta) {
65+
exists(
66+
int size, int bound, SemZeroBound b, FieldAddressToPointerArithmeticConf conf,
67+
DataFlow::Node source, DataFlow::InstructionNode sink
68+
|
69+
conf.hasFlow(source, sink) and
70+
isFieldAddressSource(f, source) and
71+
pai.getLeft() = sink.asInstruction() and
72+
f.getUnspecifiedType().(ArrayType).getArraySize() = size and
73+
semBounded(getSemanticExpr(pai.getRight()), b, bound, true, _) and
74+
delta = bound - size and
75+
delta >= 0 and
76+
size != 0 and
77+
size != 1
78+
)
79+
}
80+
81+
class PointerArithmeticToDerefConf extends DataFlow2::Configuration {
82+
PointerArithmeticToDerefConf() { this = "PointerArithmeticToDerefConf" }
83+
84+
override predicate isSource(DataFlow::Node source) {
85+
isConstantSizeOverflowSource(_, source.asInstruction(), _)
86+
}
87+
88+
override predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
89+
}
1190

1291
from
13-
FieldAddressInstruction fai, PointerArithmeticInstruction pai, AddressOperand ao, ZeroBound b,
14-
int delta, int size
92+
Field f, DataFlow::Node source, DataFlow::Node sink,
93+
Instruction deref,
94+
PointerArithmeticToDerefConf conf, string operation, int delta
1595
where
16-
size = fai.getField().getUnspecifiedType().(ArrayType).getArraySize() and
17-
DataFlow::localInstructionFlow(fai, pai.getLeft()) and
18-
DataFlow::localInstructionFlow(pai, ao.getAnyDef()) and
19-
semBounded(getSemanticExpr(pai.getRight()), b, delta, true, _) and
20-
delta >= size and
21-
size != 0 and // sometimes 0 or 1 is used for a variable-size array
22-
size != 1
23-
select pai, "This pointer may have an off-by-" + (delta - size + 1) + " error allowing it to overrun $@",
24-
fai.getField(), fai.getField().toString()
96+
conf.hasFlow(source, sink) and
97+
isInvalidPointerDerefSink(sink, deref, operation) and
98+
isConstantSizeOverflowSource(f, source.asInstruction(), delta)
99+
select source,
100+
"This pointer arithmetic may have an off-by-" + (delta + 1) + " error allowing it to overrun $@ at this $@",
101+
f, f.getName(), deref, operation
Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
| test.cpp:35:5:35:22 | PointerAdd: access to array | This pointer may have an off-by-1 error allowing it to overrun $@ | test.cpp:15:9:15:11 | buf | buf |
2-
| test.cpp:36:5:36:24 | PointerAdd: access to array | This pointer may have an off-by-2 error allowing it to overrun $@ | test.cpp:15:9:15:11 | buf | buf |
3-
| test.cpp:43:9:43:19 | PointerAdd: access to array | This pointer may have an off-by-1 error allowing it to overrun $@ | test.cpp:15:9:15:11 | buf | buf |
4-
| test.cpp:49:5:49:22 | PointerAdd: access to array | This pointer may have an off-by-1 error allowing it to overrun $@ | test.cpp:19:9:19:11 | buf | buf |
5-
| test.cpp:50:5:50:24 | PointerAdd: access to array | This pointer may have an off-by-2 error allowing it to overrun $@ | test.cpp:19:9:19:11 | buf | buf |
6-
| test.cpp:57:9:57:19 | PointerAdd: access to array | This pointer may have an off-by-1 error allowing it to overrun $@ | test.cpp:19:9:19:11 | buf | buf |
7-
| test.cpp:61:9:61:19 | PointerAdd: access to array | This pointer may have an off-by-2 error allowing it to overrun $@ | test.cpp:19:9:19:11 | buf | buf |
8-
| test.cpp:77:27:77:44 | PointerAdd: access to array | This pointer may have an off-by-1 error allowing it to overrun $@ | test.cpp:15:9:15:11 | buf | buf |
1+
| test.cpp:26:5:26:15 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:5:9:5:11 | buf | buf | test.cpp:26:5:26:19 | Store: ... = ... | write |
2+
| test.cpp:30:5:30:15 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:10:9:10:11 | buf | buf | test.cpp:30:5:30:19 | Store: ... = ... | write |
3+
| test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
4+
| test.cpp:36:5:36:24 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@ | test.cpp:15:9:15:11 | buf | buf | test.cpp:36:5:36:28 | Store: ... = ... | write |
5+
| test.cpp:43:9:43:19 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:15:9:15:11 | buf | buf | test.cpp:43:9:43:23 | Store: ... = ... | write |
6+
| test.cpp:49:5:49:22 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:19:9:19:11 | buf | buf | test.cpp:49:5:49:26 | Store: ... = ... | write |
7+
| test.cpp:50:5:50:24 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@ | test.cpp:19:9:19:11 | buf | buf | test.cpp:50:5:50:28 | Store: ... = ... | write |
8+
| test.cpp:57:9:57:19 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:19:9:19:11 | buf | buf | test.cpp:57:9:57:23 | Store: ... = ... | write |
9+
| test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@ | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
10+
| test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write |
11+
| test.cpp:77:27:77:44 | access to array | This pointer arithmetic may have an off-by-0 error allowing it to overrun $@ at this $@ | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |

0 commit comments

Comments
 (0)