Skip to content

Commit c0828a4

Browse files
committed
C++: Fix barriers in 'InvalidPointerToDereference.qll'.
1 parent abe3a81 commit c0828a4

File tree

1 file changed

+81
-58
lines changed

1 file changed

+81
-58
lines changed

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

Lines changed: 81 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,14 @@ private import RangeAnalysisUtil
8282

8383
private module InvalidPointerToDerefBarrier {
8484
private module BarrierConfig implements DataFlow::ConfigSig {
85-
predicate isSource(DataFlow::Node source) {
86-
// The sources is the same as in the sources for `InvalidPointerToDerefConfig`.
87-
invalidPointerToDerefSource(_, _, source, _)
85+
additional predicate isSource(DataFlow::Node source, PointerArithmeticInstruction pai) {
86+
invalidPointerToDerefSource(_, pai, _, _) and
87+
// source <= pai
88+
bounded2(source.asInstruction(), pai, any(int d | d <= 0))
8889
}
8990

91+
predicate isSource(DataFlow::Node source) { isSource(source, _) }
92+
9093
additional predicate isSink(
9194
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
9295
) {
@@ -99,59 +102,80 @@ private module InvalidPointerToDerefBarrier {
99102

100103
private module BarrierFlow = DataFlow::Global<BarrierConfig>;
101104

102-
private int getInvalidPointerToDerefSourceDelta(DataFlow::Node node) {
103-
exists(DataFlow::Node source |
104-
BarrierFlow::flow(source, node) and
105-
invalidPointerToDerefSource(_, _, source, result)
106-
)
107-
}
108-
105+
/**
106+
* Holds if `g` ensures that `small < big + k` if `g` evaluates to `edge`.
107+
*
108+
* Additionally, it also holds that `big <= pai`. Thus, when `g` evaluates to `edge`
109+
* it holds that `small < pai + k`.
110+
*/
109111
private predicate operandGuardChecks(
110-
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
112+
PointerArithmeticInstruction pai, IRGuardCondition g, Operand small, int k, boolean edge
111113
) {
112-
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
113-
nRight.asOperand() = right and
114-
nLeft.asOperand() = left and
115-
BarrierConfig::isSink(nLeft, nRight, g, k, edge) and
116-
state = getInvalidPointerToDerefSourceDelta(nRight) and
117-
k <= state
114+
exists(DataFlow::Node source, DataFlow::Node nSmall, DataFlow::Node nBig |
115+
nSmall.asOperand() = small and
116+
BarrierConfig::isSource(source, pai) and
117+
BarrierFlow::flow(source, nBig) and
118+
BarrierConfig::isSink(nSmall, nBig, g, k, edge)
118119
)
119120
}
120121

121-
Instruction getABarrierInstruction(int state) {
122-
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge |
122+
/**
123+
* Gets an instruction `instr` such that `instr < pai`.
124+
*/
125+
Instruction getABarrierInstruction(PointerArithmeticInstruction pai) {
126+
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge, int delta, int k |
123127
use = value.getAUse() and
124-
operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _, state,
125-
pragma[only_bind_into](edge)) and
126-
result = value.getAnInstruction() and
127-
g.controls(result.getBlock(), edge)
128+
operandGuardChecks(pai, pragma[only_bind_into](g), pragma[only_bind_into](use),
129+
pragma[only_bind_into](k), pragma[only_bind_into](edge)) and
130+
// result <= value + delta
131+
bounded(result, value.getAnInstruction(), delta) and
132+
g.controls(result.getBlock(), edge) and
133+
delta + k <= 0
134+
// combining the above we have: result < pai + k + delta <= pai
128135
)
129136
}
130137

131-
DataFlow::Node getABarrierNode() { result.asOperand() = getABarrierInstruction(_).getAUse() }
138+
DataFlow::Node getABarrierNode(PointerArithmeticInstruction pai) {
139+
result.asOperand() = getABarrierInstruction(pai).getAUse()
140+
}
132141

133-
pragma[nomagic]
134-
IRBlock getABarrierBlock(int state) { result.getAnInstruction() = getABarrierInstruction(state) }
142+
/**
143+
* Gets an instruction `instr` such that `instr < derefSource - deltaDerefSinkAndDerefAddress`
144+
* for some `derefSource`.
145+
*/
146+
AddressOperand getABarrierAddressOperand(PointerArithmeticInstruction pai) {
147+
result.getDef() = getABarrierInstruction(pai)
148+
}
135149
}
136150

137151
/**
138152
* A configuration to track flow from a pointer-arithmetic operation found
139153
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
140154
*/
141-
private module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
142-
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, _, source, _) }
155+
private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
156+
class FlowState extends PointerArithmeticInstruction {
157+
FlowState() { invalidPointerToDerefSource(_, this, _, _) }
158+
}
159+
160+
predicate isSource(DataFlow::Node source, FlowState pai) {
161+
invalidPointerToDerefSource(_, pai, source, _)
162+
}
143163

144164
pragma[inline]
145-
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _) }
165+
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _, _) }
166+
167+
predicate isSink(DataFlow::Node sink, FlowState pai) { none() }
146168

147169
predicate isBarrier(DataFlow::Node node) {
148170
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
149-
or
150-
node = InvalidPointerToDerefBarrier::getABarrierNode()
171+
}
172+
173+
predicate isBarrier(DataFlow::Node node, FlowState pai) {
174+
node = InvalidPointerToDerefBarrier::getABarrierNode(pai)
151175
}
152176
}
153177

154-
private import DataFlow::Global<InvalidPointerToDerefConfig>
178+
private import DataFlow::GlobalWithState<InvalidPointerToDerefConfig>
155179

156180
/**
157181
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
@@ -165,19 +189,14 @@ private predicate invalidPointerToDerefSource(
165189
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
166190
int deltaDerefSourceAndPai
167191
) {
168-
exists(int rhsSizeDelta |
169-
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
170-
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
171-
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
172-
// and the instruction computing the address for which we will search for a dereference.
173-
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, rhsSizeDelta) and
174-
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
175-
deltaDerefSourceAndPai >= 0 and
176-
// TODO: This condition will go away once #13725 is merged, and then we can make `SizeBarrier`
177-
// private to `AllocationToInvalidPointer.qll`.
178-
not derefSource.getBasicBlock() =
179-
AllocToInvalidPointer::SizeBarrier::getABarrierBlock(rhsSizeDelta)
180-
)
192+
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
193+
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
194+
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
195+
// and the instruction computing the address for which we will search for a dereference.
196+
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, _) and
197+
// derefSource <= pai + deltaDerefSourceAndPai
198+
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
199+
deltaDerefSourceAndPai >= 0
181200
}
182201

183202
/**
@@ -187,15 +206,14 @@ private predicate invalidPointerToDerefSource(
187206
*/
188207
pragma[inline]
189208
private predicate isInvalidPointerDerefSink(
190-
DataFlow::Node sink, Instruction i, string operation, int deltaDerefSinkAndDerefAddress
209+
DataFlow::Node sink, AddressOperand addr, Instruction i, string operation,
210+
int deltaDerefSinkAndDerefAddress
191211
) {
192-
exists(AddressOperand addr, Instruction s, IRBlock b |
212+
exists(Instruction s |
193213
s = sink.asInstruction() and
194214
bounded(addr.getDef(), s, deltaDerefSinkAndDerefAddress) and
195215
deltaDerefSinkAndDerefAddress >= 0 and
196-
i.getAnOperand() = addr and
197-
b = i.getBlock() and
198-
not b = InvalidPointerToDerefBarrier::getABarrierBlock(deltaDerefSinkAndDerefAddress)
216+
i.getAnOperand() = addr
199217
|
200218
i instanceof StoreInstruction and
201219
operation = "write"
@@ -221,9 +239,11 @@ private Instruction getASuccessor(Instruction instr) {
221239
instr.getBlock().getASuccessor+() = result.getBlock()
222240
}
223241

224-
private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFlow::Node derefSink) {
242+
private predicate paiForDereferenceSink(
243+
PointerArithmeticInstruction pai, DataFlow::Node derefSink, int deltaDerefSourceAndPai
244+
) {
225245
exists(DataFlow::Node derefSource |
226-
invalidPointerToDerefSource(_, pai, derefSource, _) and
246+
invalidPointerToDerefSource(_, pai, derefSource, deltaDerefSourceAndPai) and
227247
flow(derefSource, derefSink)
228248
)
229249
}
@@ -235,13 +255,15 @@ private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFl
235255
*/
236256
private predicate derefSinkToOperation(
237257
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
238-
string description, int deltaDerefSinkAndDerefAddress
258+
string description, int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress
239259
) {
240-
exists(Instruction operationInstr |
241-
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
242-
isInvalidPointerDerefSink(derefSink, operationInstr, description, deltaDerefSinkAndDerefAddress) and
260+
exists(Instruction operationInstr, AddressOperand addr |
261+
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink), deltaDerefSourceAndPai) and
262+
isInvalidPointerDerefSink(derefSink, addr, operationInstr, description,
263+
deltaDerefSinkAndDerefAddress) and
243264
operationInstr = getASuccessor(derefSink.asInstruction()) and
244-
operation.asInstruction() = operationInstr
265+
operation.asInstruction() = operationInstr and
266+
not addr = InvalidPointerToDerefBarrier::getABarrierAddressOperand(pai)
245267
)
246268
}
247269

@@ -260,7 +282,8 @@ predicate operationIsOffBy(
260282
exists(int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress |
261283
invalidPointerToDerefSource(allocation, pai, derefSource, deltaDerefSourceAndPai) and
262284
flow(derefSource, derefSink) and
263-
derefSinkToOperation(derefSink, pai, operation, description, deltaDerefSinkAndDerefAddress) and
285+
derefSinkToOperation(derefSink, pai, operation, description, deltaDerefSourceAndPai,
286+
deltaDerefSinkAndDerefAddress) and
264287
delta = deltaDerefSourceAndPai + deltaDerefSinkAndDerefAddress
265288
)
266289
}

0 commit comments

Comments
 (0)