-fret-clean
Suggested by Theo De Raadt the 25th of May 2024:
This is a new -fret-clean option in clang, which is used to compile the following:
libc, libcrypto, ld.so, all the ssh binaries, and the kernel
It is a compiler pass that changes the following:
callq something
into
callq something movq $0, -8(%rsp)
The goal being to remove pointers to libc from the stack, so that an attacker with an arbitrary read there can’t find their way to the libc. Combined with the execute-only. mapping of the libc, it kind of makes sense.
Unfortunately:
A review of the stack after this shows substantial sanitization. This doesn’t fix all pointers you can see on the stack, just this one type of ‘pointer’. Local variable pointers inside call frames will remain, but that’s harder for an attacker to exercise.
I’m not proposing that we compile many main programs with this. The retval data hiding being proposed is most useful near the syscall boundary in libc.so (and ld.so). In dynamic libc.so, pinsyscalls(2) prevents one syscall stub from being a chimera for other operations, but you will still find all the stubs in libc.so lying around in some random place.
Arbitrary stack reads aren’t that common, but when they happen, they tend to be pretty powerful: A single pointer leak would be enough to completely bypass this. It’s a marginal improvement over good ol’ ASLR, keeping it true to the acronym: A Single Leak Required. Moreover, nowadays everyone and their dog is attacking the heap, where pointers are legion and primitives stronger, focusing on pointers disclosure on the stack in 2024 is a bit embarrassing.
The feature landed in OpenBSD 7.6, albeit disabled by default.
This meh-tigation is a good example of OpenBSD’s security posture: nobody in
their contributor base ever wrote an exploit, so they’re “fixing”
irrelevant/imaginary “issues”. I don’t think -fret-clean
will kill a single
exploit.