Skip to content

Commit 4676ca5

Browse files
authored
Merge pull request github#13789 from MathiasVP/better-names-in-invalid-ptr-deref
C++: Improve names of identifiers in `cpp/invalid-pointer-deref`
2 parents af8612e + c44507c commit 4676ca5

File tree

2 files changed

+76
-79
lines changed

2 files changed

+76
-79
lines changed

cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/AllocationToInvalidPointer.qll

Lines changed: 45 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -42,59 +42,57 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
4242
* ```
4343
* In this case, the sink pair identified by the product flow library (without any additional barriers)
4444
* would be `(p, n)` (where `n` is the `n` in `p[n]`), because there exists a pointer-arithmetic
45-
* instruction `pai` such that:
46-
* 1. The left-hand of `pai` flows from the allocation, and
47-
* 2. The right-hand of `pai` is non-strictly upper bounded by `n` (where `n` is the `n` in `p[n]`)
45+
* instruction `pai = a + b` such that:
46+
* 1. the allocation flows to `a`, and
47+
* 2. `b <= n` where `n` is the `n` in `p[n]`
4848
* but because there's a strict comparison that compares `n` against the size of the allocation this
4949
* snippet is fine.
5050
*/
51-
module Barrier2 {
52-
private class FlowState2 = int;
53-
54-
private module BarrierConfig2 implements DataFlow::ConfigSig {
51+
module SizeBarrier {
52+
private module SizeBarrierConfig implements DataFlow::ConfigSig {
5553
predicate isSource(DataFlow::Node source) {
5654
// The sources is the same as in the sources for the second
5755
// projection in the `AllocToInvalidPointerConfig` module.
5856
hasSize(_, source, _)
5957
}
6058

6159
additional predicate isSink(
62-
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, FlowState2 state,
63-
boolean testIsTrue
60+
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
6461
) {
65-
// The sink is any "large" side of a relational comparison.
66-
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
62+
// The sink is any "large" side of a relational comparison. i.e., the `right` expression
63+
// in a guard such as `left < right + k`.
64+
g.comparesLt(left.asOperand(), right.asOperand(), k, true, testIsTrue)
6765
}
6866

6967
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
7068
}
7169

72-
private import DataFlow::Global<BarrierConfig2>
70+
private import DataFlow::Global<SizeBarrierConfig>
7371

74-
private FlowState2 getAFlowStateForNode(DataFlow::Node node) {
72+
private int getAFlowStateForNode(DataFlow::Node node) {
7573
exists(DataFlow::Node source |
7674
flow(source, node) and
7775
hasSize(_, source, result)
7876
)
7977
}
8078

8179
private predicate operandGuardChecks(
82-
IRGuardCondition g, Operand left, Operand right, FlowState2 state, boolean edge
80+
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
8381
) {
84-
exists(DataFlow::Node nLeft, DataFlow::Node nRight, FlowState2 state0 |
82+
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
8583
nRight.asOperand() = right and
8684
nLeft.asOperand() = left and
87-
BarrierConfig2::isSink(nLeft, nRight, g, state0, edge) and
85+
SizeBarrierConfig::isSink(nLeft, nRight, g, k, edge) and
8886
state = getAFlowStateForNode(nRight) and
89-
state0 <= state
87+
k <= state
9088
)
9189
}
9290

9391
/**
9492
* Gets an instruction that is guarded by a guard condition which ensures that
9593
* the value of the instruction is upper-bounded by size of some allocation.
9694
*/
97-
Instruction getABarrierInstruction(FlowState2 state) {
95+
Instruction getABarrierInstruction(int state) {
9896
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge |
9997
use = value.getAUse() and
10098
operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _,
@@ -108,17 +106,15 @@ module Barrier2 {
108106
* Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that
109107
* the value of the node is upper-bounded by size of some allocation.
110108
*/
111-
DataFlow::Node getABarrierNode(FlowState2 state) {
109+
DataFlow::Node getABarrierNode(int state) {
112110
result.asOperand() = getABarrierInstruction(state).getAUse()
113111
}
114112

115113
/**
116114
* Gets the block of a node that is guarded (see `getABarrierInstruction` or
117115
* `getABarrierNode` for the definition of what it means to be guarded).
118116
*/
119-
IRBlock getABarrierBlock(FlowState2 state) {
120-
result.getAnInstruction() = getABarrierInstruction(state)
121-
}
117+
IRBlock getABarrierBlock(int state) { result.getAnInstruction() = getABarrierInstruction(state) }
122118
}
123119

124120
private module InterestingPointerAddInstruction {
@@ -151,8 +147,8 @@ private module InterestingPointerAddInstruction {
151147
}
152148

153149
/**
154-
* A product-flow configuration for flow from an (allocation, size) pair to a
155-
* pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`.
150+
* A product-flow configuration for flow from an `(allocation, size)` pair to a
151+
* pointer-arithmetic operation `pai` such that `pai <= allocation + size`.
156152
*
157153
* The goal of this query is to find patterns such as:
158154
* ```cpp
@@ -176,29 +172,29 @@ private module Config implements ProductFlow::StateConfigSig {
176172
class FlowState2 = int;
177173

178174
predicate isSourcePair(
179-
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
175+
DataFlow::Node allocSource, FlowState1 unit, DataFlow::Node sizeSource, FlowState2 sizeAddend
180176
) {
181177
// In the case of an allocation like
182178
// ```cpp
183179
// malloc(size + 1);
184180
// ```
185181
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
186182
// to the size of the allocation. This state is then checked in `isSinkPair`.
187-
exists(state1) and
188-
hasSize(source1.asConvertedExpr(), source2, state2)
183+
exists(unit) and
184+
hasSize(allocSource.asConvertedExpr(), sizeSource, sizeAddend)
189185
}
190186

191187
predicate isSinkPair(
192-
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
188+
DataFlow::Node allocSink, FlowState1 unit, DataFlow::Node sizeSink, FlowState2 sizeAddend
193189
) {
194-
exists(state1) and
190+
exists(unit) and
195191
// We check that the delta computed by the range analysis matches the
196192
// state value that we set in `isSourcePair`.
197-
pointerAddInstructionHasBounds0(_, sink1, sink2, state2)
193+
pointerAddInstructionHasBounds0(_, allocSink, sizeSink, sizeAddend)
198194
}
199195

200196
predicate isBarrier2(DataFlow::Node node, FlowState2 state) {
201-
node = Barrier2::getABarrierNode(state)
197+
node = SizeBarrier::getABarrierNode(state)
202198
}
203199

204200
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
@@ -211,7 +207,7 @@ private module Config implements ProductFlow::StateConfigSig {
211207
private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
212208

213209
/**
214-
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
210+
* Holds if `pai` is non-strictly upper bounded by `sizeSink + delta` and `allocSink` is the
215211
* left operand of the pointer-arithmetic operation.
216212
*
217213
* For example in,
@@ -220,37 +216,37 @@ private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
220216
* ```
221217
* We will have:
222218
* - `pai` is `p + (size + 1)`,
223-
* - `sink1` is `p`
224-
* - `sink2` is `size`
219+
* - `allocSink` is `p`
220+
* - `sizeSink` is `size`
225221
* - `delta` is `1`.
226222
*/
227223
pragma[nomagic]
228224
private predicate pointerAddInstructionHasBounds0(
229-
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
225+
PointerAddInstruction pai, DataFlow::Node allocSink, DataFlow::Node sizeSink, int delta
230226
) {
231227
InterestingPointerAddInstruction::isInteresting(pragma[only_bind_into](pai)) and
232-
exists(Instruction right, Instruction instr2 |
228+
exists(Instruction right, Instruction sizeInstr |
233229
pai.getRight() = right and
234-
pai.getLeft() = sink1.asInstruction() and
235-
instr2 = sink2.asInstruction() and
236-
// pai.getRight() <= sink2 + delta
237-
bounded1(right, instr2, delta) and
238-
not right = Barrier2::getABarrierInstruction(delta) and
239-
not instr2 = Barrier2::getABarrierInstruction(delta)
230+
pai.getLeft() = allocSink.asInstruction() and
231+
sizeInstr = sizeSink.asInstruction() and
232+
// pai.getRight() <= sizeSink + delta
233+
bounded1(right, sizeInstr, delta) and
234+
not right = SizeBarrier::getABarrierInstruction(delta) and
235+
not sizeInstr = SizeBarrier::getABarrierInstruction(delta)
240236
)
241237
}
242238

243239
/**
244-
* Holds if `allocation` flows to `sink1` and `sink1` represents the left-hand
245-
* side of the pointer-arithmetic instruction `pai`, and the right-hand side of `pai`
246-
* is non-strictly upper bounded by the size of `alllocation` + `delta`.
240+
* Holds if `allocation` flows to `allocSink` and `allocSink` represents the left operand
241+
* of the pointer-arithmetic instruction `pai = a + b` (i.e., `allocSink = a`), and
242+
* `b <= allocation + delta`.
247243
*/
248244
pragma[nomagic]
249245
predicate pointerAddInstructionHasBounds(
250-
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node sink1, int delta
246+
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node allocSink, int delta
251247
) {
252-
exists(DataFlow::Node sink2 |
253-
AllocToInvalidPointerFlow::flow(allocation, _, sink1, sink2) and
254-
pointerAddInstructionHasBounds0(pai, sink1, sink2, delta)
248+
exists(DataFlow::Node sizeSink |
249+
AllocToInvalidPointerFlow::flow(allocation, _, allocSink, sizeSink) and
250+
pointerAddInstructionHasBounds0(pai, allocSink, sizeSink, delta)
255251
)
256252
}

cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ private module InvalidPointerToDerefBarrier {
1919
}
2020

2121
additional predicate isSink(
22-
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int state, boolean testIsTrue
22+
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
2323
) {
2424
// The sink is any "large" side of a relational comparison.
25-
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
25+
g.comparesLt(left.asOperand(), right.asOperand(), k, true, testIsTrue)
2626
}
2727

2828
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
@@ -40,12 +40,12 @@ private module InvalidPointerToDerefBarrier {
4040
private predicate operandGuardChecks(
4141
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
4242
) {
43-
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int state0 |
43+
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
4444
nRight.asOperand() = right and
4545
nLeft.asOperand() = left and
46-
BarrierConfig::isSink(nLeft, nRight, g, state0, edge) and
46+
BarrierConfig::isSink(nLeft, nRight, g, k, edge) and
4747
state = getInvalidPointerToDerefSourceDelta(nRight) and
48-
state0 <= state
48+
k <= state
4949
)
5050
}
5151

@@ -85,47 +85,48 @@ private module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
8585
private import DataFlow::Global<InvalidPointerToDerefConfig>
8686

8787
/**
88-
* Holds if `source1` is dataflow node that represents an allocation that flows to the
89-
* left-hand side of the pointer-arithmetic `pai`, and `derefSource` is a dataflow node with
90-
* a pointer-value that is non-strictly upper bounded by `pai + delta`.
88+
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
89+
* left-hand side of the pointer-arithmetic `pai`, and `derefSource <= pai + derefSourcePaiDelta`.
9190
*
9291
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
9392
* as `(p + size) + 1` and `derefSource` is the node representing `(p + size) + 1`. In this
94-
* case `delta` is 1.
93+
* case `derefSourcePaiDelta` is 1.
9594
*/
9695
private predicate invalidPointerToDerefSource(
97-
DataFlow::Node source1, PointerArithmeticInstruction pai, DataFlow::Node derefSource, int delta
96+
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
97+
int deltaDerefSourceAndPai
9898
) {
99-
exists(int delta0 |
100-
// Note that `delta` is not necessarily equal to `delta0`:
101-
// `delta0` is the constant offset added to the size of the allocation, and
102-
// delta is the constant difference between the pointer-arithmetic instruction
99+
exists(int rhsSizeDelta |
100+
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
101+
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
102+
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
103103
// and the instruction computing the address for which we will search for a dereference.
104-
AllocToInvalidPointer::pointerAddInstructionHasBounds(source1, pai, _, delta0) and
105-
bounded2(derefSource.asInstruction(), pai, delta) and
106-
delta >= 0 and
107-
// TODO: This condition will go away once #13725 is merged, and then we can make `Barrier2`
104+
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, rhsSizeDelta) and
105+
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
106+
deltaDerefSourceAndPai >= 0 and
107+
// TODO: This condition will go away once #13725 is merged, and then we can make `SizeBarrier`
108108
// private to `AllocationToInvalidPointer.qll`.
109-
not derefSource.getBasicBlock() = AllocToInvalidPointer::Barrier2::getABarrierBlock(delta0)
109+
not derefSource.getBasicBlock() =
110+
AllocToInvalidPointer::SizeBarrier::getABarrierBlock(rhsSizeDelta)
110111
)
111112
}
112113

113114
/**
114115
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
115-
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
116-
* reads from an address that non-strictly upper-bounds `sink`.
116+
* writes to an address `addr` such that `addr <= sink`, or `i` is a `LoadInstruction` that
117+
* reads from an address `addr` such that `addr <= sink`.
117118
*/
118119
pragma[inline]
119120
private predicate isInvalidPointerDerefSink(
120-
DataFlow::Node sink, Instruction i, string operation, int delta
121+
DataFlow::Node sink, Instruction i, string operation, int deltaDerefSinkAndDerefAddress
121122
) {
122123
exists(AddressOperand addr, Instruction s, IRBlock b |
123124
s = sink.asInstruction() and
124-
bounded(addr.getDef(), s, delta) and
125-
delta >= 0 and
125+
bounded(addr.getDef(), s, deltaDerefSinkAndDerefAddress) and
126+
deltaDerefSinkAndDerefAddress >= 0 and
126127
i.getAnOperand() = addr and
127128
b = i.getBlock() and
128-
not b = InvalidPointerToDerefBarrier::getABarrierBlock(delta)
129+
not b = InvalidPointerToDerefBarrier::getABarrierBlock(deltaDerefSinkAndDerefAddress)
129130
|
130131
i instanceof StoreInstruction and
131132
operation = "write"
@@ -165,13 +166,13 @@ private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFl
165166
*/
166167
private predicate derefSinkToOperation(
167168
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
168-
string description, int delta
169+
string description, int deltaDerefSinkAndDerefAddress
169170
) {
170-
exists(Instruction i |
171+
exists(Instruction operationInstr |
171172
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
172-
isInvalidPointerDerefSink(derefSink, i, description, delta) and
173-
i = getASuccessor(derefSink.asInstruction()) and
174-
operation.asInstruction() = i
173+
isInvalidPointerDerefSink(derefSink, operationInstr, description, deltaDerefSinkAndDerefAddress) and
174+
operationInstr = getASuccessor(derefSink.asInstruction()) and
175+
operation.asInstruction() = operationInstr
175176
)
176177
}
177178

0 commit comments

Comments
 (0)