Skip to content

Commit bf10456

Browse files
committed
C++: Add a path explanation to the 'cpp/using-expired-stack-address' query.
1 parent 9df923a commit bf10456

File tree

2 files changed

+171
-30
lines changed

2 files changed

+171
-30
lines changed

cpp/ql/src/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @name Use of expired stack-address
33
* @description Accessing the stack-allocated memory of a function
44
* after it has returned can lead to memory corruption.
5-
* @kind problem
5+
* @kind path-problem
66
* @problem.severity error
77
* @security-severity 9.3
88
* @precision high
@@ -238,14 +238,86 @@ predicate step(
238238
)
239239
}
240240

241+
newtype TPathElement =
242+
TStore(StoreInstruction store) { globalAddressPointsToStack(store, _, _, _, _, _, _) } or
243+
TCall(CallInstruction call, IRBlock block) {
244+
globalAddressPointsToStack(_, _, call, block, _, _, _)
245+
} or
246+
TMid(IRBlock block) { step(_, _, _, _, _, block) } or
247+
TSink(LoadInstruction load, IRBlock block) {
248+
exists(TGlobalAddress address |
249+
globalAddressPointsToStack(_, _, _, block, address, _, _) and
250+
block.getAnInstruction() = load and
251+
globalAddress(load.getSourceAddress()) = address
252+
)
253+
}
254+
255+
class PathElement extends TPathElement {
256+
StoreInstruction asStore() { this = TStore(result) }
257+
258+
CallInstruction asCall(IRBlock block) { this = TCall(result, block) }
259+
260+
predicate isCall(IRBlock block) { exists(this.asCall(block)) }
261+
262+
IRBlock asMid() { this = TMid(result) }
263+
264+
LoadInstruction asSink(IRBlock block) { this = TSink(result, block) }
265+
266+
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
267+
268+
string toString() {
269+
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
270+
}
271+
272+
predicate hasLocationInfo(
273+
string filepath, int startline, int startcolumn, int endline, int endcolumn
274+
) {
275+
this.asStore()
276+
.getLocation()
277+
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
278+
or
279+
this.asCall(_)
280+
.getLocation()
281+
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
282+
or
283+
this.asMid().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
284+
or
285+
this.asSink(_)
286+
.getLocation()
287+
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
288+
}
289+
}
290+
241291
predicate isSink(LoadInstruction load, IRBlock block, int index, TGlobalAddress globalAddress) {
242292
block.getInstruction(index) = load and
243293
globalAddress(load.getSourceAddress()) = globalAddress
244294
}
245295

296+
query predicate edges(PathElement pred, PathElement succ) {
297+
// Store -> caller
298+
globalAddressPointsToStack(pred.asStore(), _, succ.asCall(_), _, _, _, _)
299+
or
300+
// Call -> basic block
301+
pred.isCall(succ.asMid())
302+
or
303+
// Special case for when the caller goes directly to the load with no steps
304+
// across basic blocks (i.e., caller -> sink)
305+
exists(IRBlock block |
306+
pred.isCall(block) and
307+
succ.isSink(block)
308+
)
309+
or
310+
// Basic block -> basic block
311+
step(_, _, _, _, pred.asMid(), succ.asMid())
312+
or
313+
// Basic block -> load
314+
succ.isSink(pred.asMid())
315+
}
316+
246317
from
247318
StoreInstruction store, StackVariable var, LoadInstruction load, CallInstruction call,
248-
IRBlock block, boolean isCallBlock, TGlobalAddress address, boolean isStoreBlock, int loadIndex
319+
IRBlock block, boolean isCallBlock, TGlobalAddress address, boolean isStoreBlock,
320+
PathElement source, PathElement sink, int loadIndex
249321
where
250322
globalAddressPointsToStack(store, var, call, block, address, isCallBlock, isStoreBlock) and
251323
isSink(load, block, loadIndex, address) and
@@ -269,6 +341,8 @@ where
269341
loadIndex < storeIndex
270342
)
271343
else any()
272-
)
273-
select load, "Stack variable $@ escapes $@ and is used after it has expired.", var, var.toString(),
274-
store, "here"
344+
) and
345+
source.asStore() = store and
346+
sink.asSink(_) = load
347+
select sink, source, sink, "Stack variable $@ escapes $@ and is used after it has expired.", var,
348+
var.toString(), store, "here"

0 commit comments

Comments
 (0)