StackProtection: ignore pointers with no stores

Stack protection only protects against overflows, but not against out of bounds reads.

rdar://105231457
This commit is contained in:
Erik Eckstein
2023-02-14 20:44:54 +01:00
parent b2512ab5cb
commit 49e66c57b8
3 changed files with 196 additions and 20 deletions

View File

@@ -486,6 +486,11 @@ private extension Instruction {
if !atp.needsStackProtection {
return nil
}
var hasNoStores = NoStores()
if hasNoStores.walkDownUses(ofValue: atp, path: SmallProjectionPath()) == .continueWalk {
return nil
}
// The result of an `address_to_pointer` may be used in any unsafe way, e.g.
// passed to a C function.
baseAddr = atp.operand
@@ -493,6 +498,11 @@ private extension Instruction {
if !ia.needsStackProtection {
return nil
}
var hasNoStores = NoStores()
if hasNoStores.walkDownUses(ofAddress: ia, path: SmallProjectionPath()) == .continueWalk {
return nil
}
// `index_addr` is unsafe if not used for tail-allocated elements (e.g. in Array).
baseAddr = ia.base
default:
@@ -509,6 +519,29 @@ private extension Instruction {
}
}
/// Checks if there are no stores to an address or raw pointer.
private struct NoStores : ValueDefUseWalker, AddressDefUseWalker {
var walkDownCache = WalkerCache<SmallProjectionPath>()
mutating func leafUse(value: Operand, path: SmallProjectionPath) -> WalkResult {
if let ptai = value.instruction as? PointerToAddressInst {
return walkDownUses(ofAddress: ptai, path: path)
}
return .abortWalk
}
mutating func leafUse(address: Operand, path: SmallProjectionPath) -> WalkResult {
switch address.instruction {
case is LoadInst:
return .continueWalk
case let cai as CopyAddrInst:
return address == cai.sourceOperand ? .continueWalk : .abortWalk
default:
return .abortWalk
}
}
}
private extension Function {
func setNeedsStackProtection(_ context: FunctionPassContext) {
if !needsStackProtection {