Skip to content

Commit 6e230e1

Browse files
committed
C++: include stack-allocated arrays in off-by-one query
1 parent b2fb2aa commit 6e230e1

File tree

3 files changed

+39
-22
lines changed

3 files changed

+39
-22
lines changed

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

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysi
1414
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
1515
import semmle.code.cpp.ir.IR
1616
import semmle.code.cpp.ir.dataflow.DataFlow
17-
import FieldAddressToDerefFlow::PathGraph
17+
import ArrayAddressToDerefFlow::PathGraph
1818

1919
pragma[nomagic]
2020
Instruction getABoundIn(SemBound b, IRFunction func) {
@@ -79,10 +79,10 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
7979
}
8080

8181
predicate pointerArithOverflow0(
82-
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
82+
PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta
8383
) {
84-
pai.getElementSize() = f.getUnspecifiedType().(ArrayType).getBaseType().getSize() and
85-
f.getUnspecifiedType().(ArrayType).getArraySize() = size and
84+
pai.getElementSize() = v.getUnspecifiedType().(ArrayType).getBaseType().getSize() and
85+
v.getUnspecifiedType().(ArrayType).getArraySize() = size and
8686
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
8787
delta = bound - size and
8888
delta >= 0 and
@@ -105,23 +105,28 @@ module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
105105
module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefConfig>;
106106

107107
predicate pointerArithOverflow(
108-
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
108+
PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta
109109
) {
110-
pointerArithOverflow0(pai, f, size, bound, delta) and
110+
pointerArithOverflow0(pai, v, size, bound, delta) and
111111
PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _)
112112
}
113113

114-
module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
114+
module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig {
115115
newtype FlowState =
116-
additional TArray(Field f) { pointerArithOverflow(_, f, _, _, _) } or
116+
additional TArray(Variable v) { pointerArithOverflow(_, v, _, _, _) } or
117117
additional TOverflowArithmetic(PointerArithmeticInstruction pai) {
118118
pointerArithOverflow(pai, _, _, _, _)
119119
}
120120

121121
predicate isSource(DataFlow::Node source, FlowState state) {
122-
exists(Field f |
123-
source.asInstruction().(FieldAddressInstruction).getField() = f and
124-
state = TArray(f)
122+
exists(Variable v |
123+
(
124+
source.asInstruction().(FieldAddressInstruction).getField() = v
125+
or
126+
source.asInstruction().(VariableAddressInstruction).getAstVariable() = v
127+
) and
128+
exists(v.getUnspecifiedType().(ArrayType).getArraySize()) and
129+
state = TArray(v)
125130
)
126131
}
127132

@@ -141,27 +146,27 @@ module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
141146
predicate isAdditionalFlowStep(
142147
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
143148
) {
144-
exists(PointerArithmeticInstruction pai, Field f |
145-
state1 = TArray(f) and
149+
exists(PointerArithmeticInstruction pai, Variable v, int size, int delta |
150+
state1 = TArray(v) and
146151
state2 = TOverflowArithmetic(pai) and
147152
pai.getLeft() = node1.asInstruction() and
148153
node2.asInstruction() = pai and
149-
pointerArithOverflow(pai, f, _, _, _)
154+
pointerArithOverflow(pai, v, size, _, delta)
150155
)
151156
}
152157
}
153158

154-
module FieldAddressToDerefFlow = DataFlow::GlobalWithState<FieldAddressToDerefConfig>;
159+
module ArrayAddressToDerefFlow = DataFlow::GlobalWithState<ArrayAddressToDerefConfig>;
155160

156161
from
157-
Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
158-
FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
162+
Variable v, ArrayAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
163+
ArrayAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
159164
where
160-
FieldAddressToDerefFlow::flowPath(source, sink) and
165+
ArrayAddressToDerefFlow::flowPath(source, sink) and
161166
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
162-
source.getState() = FieldAddressToDerefConfig::TArray(f) and
163-
sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and
164-
pointerArithOverflow(pai, f, _, _, delta)
167+
source.getState() = ArrayAddressToDerefConfig::TArray(v) and
168+
sink.getState() = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and
169+
pointerArithOverflow(pai, v, _, _, delta)
165170
select pai, source, sink,
166171
"This pointer arithmetic may have an off-by-" + (delta + 1) +
167-
" error allowing it to overrun $@ at this $@.", f, f.getName(), deref, operation
172+
" error allowing it to overrun $@ at this $@.", v, v.getName(), deref, operation

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ edges
1111
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... |
1212
| test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p |
1313
| test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf |
14+
| test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array |
1415
nodes
1516
| test.cpp:35:5:35:22 | access to array | semmle.label | access to array |
1617
| test.cpp:35:10:35:12 | buf | semmle.label | buf |
@@ -33,6 +34,8 @@ nodes
3334
| test.cpp:77:32:77:34 | buf | semmle.label | buf |
3435
| test.cpp:79:27:79:34 | buf | semmle.label | buf |
3536
| test.cpp:79:32:79:34 | buf | semmle.label | buf |
37+
| test.cpp:128:9:128:11 | arr | semmle.label | arr |
38+
| test.cpp:128:9:128:14 | access to array | semmle.label | access to array |
3639
subpaths
3740
#select
3841
| test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | 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:35:5:35:26 | Store: ... = ... | write |
@@ -44,3 +47,4 @@ subpaths
4447
| test.cpp:61:9:61:19 | PointerAdd: access to array | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
4548
| test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | 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:72:5:72:19 | Store: ... = ... | write |
4649
| test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | 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:67:5:67:10 | Store: ... = ... | write |
50+
| test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write |

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,11 @@ void testEqRefinement2() {
120120
}
121121
}
122122
}
123+
124+
void testStackAllocated() {
125+
char *arr[MAX_SIZE];
126+
127+
for(int i = 0; i <= MAX_SIZE; i++) {
128+
arr[i] = 0; // BAD
129+
}
130+
}

0 commit comments

Comments
 (0)