Description
Description
Using -msign-return-address
options (like in #78394 on OpenBSD) and Concurrency primitives like withTaskGroup
can cause a PAC trap.
The current understanding is that this is due to the fact that on ELF platforms, swift_task_switch
may be called through a PLT stub which modifies the stack pointer, but after swift_task_switch
the stack pointer is not equivalently adjusted, causing the stack signing to fault.
Reproduction
@main struct Main {
static func main() async {
await withTaskGroup(of: Int.self) { group in print("hello") }
}
}
Execute with swiftc -parse-as-library -g bad.swift -Xcc -Xclang=-msign-return-address=non-leaf
.
Expected behavior
Code executes normally.
Environment
aarch64: swift 6.0.3 prebuilt on Linux, swift HEAD on OpenBSD.
Additional information
I don't believe this is posing a problem on Darwin/aarch64 since I am guessing (though have not verified) that Mach-O doesn't really have a concept of the PLT like on ELF platforms do. Return address signing through -msign-return-address
appears to be optional on Linux, but turning it on will also highlights the problem. I suspect the stack pointer is not being restored correctly regardless of signing and thus stack would be "leaked" through repeated swift_task_switch
calls through the PLT.
On OpenBSD/aarch64, enforcement of indirect branch targets (including return address signing) is mandatory, unless explicitly opted out by informing the platform linker (with -z nobtcfi
). The platform compiler adds the flags -mbranch-target-enforce
, -msign-return-address=non-leaf
, and -msign-return-address-key=a_key
by default. When the latter two options are enabled, the compiler emits paciasp
and autiasp
instructions for PAC on the stack pointer. When there is a misbranch on OpenBSD, the binary will receive a SIGILL signal and code ILL_BTCFI
to indicate a branch target issue. When executing the above code, the ESR indicates a pointer authentication fault.