It's not exploitable. It's an exploit mitigation, in fact. It's not a bug; it's intentional that it works this way. And Nathan Michaels didn't think that if you want to find Theo de Raadt writing on some subject, better try OpenBSD discussion fora, not the LLVM mailing list. (-:
This was put into OpenBSD back in 2017. It's not "trap instructions". It's "trapsleds". The idea is to trap the sleds (a.k.a. slides) of NOP instructions that linkers used to put in between compiled code for alignment, and which could be exploited with "return-oriented programming" where an attacker could cause execution to jump to any address in the padding range (possibly needing the inexactitude because of constraints upon byte substitutions) and slide along all of the NOPs to the target function.
The instructions have to be trap instructions for it to work.
The conditional branch-backward instruction it is is almost as bad as the series of NOPs, since it is still likely to redirect an attacker to functioning code. (If the attacker can clear the mi flag first, these are just NOPs!)
And this is where the OpenBSD people will paraphrase Henry Spencer and say that those who do not understand OpenBSD are doomed to reinvent it badly. (Personally, I think that that's putting OpenBSD onto a pedestal. It's no ideal; one gets the same tradeoffs and problems as everywhere else.) In this case, the reinvention for LLVM targetting ARM, that credits seeing this committed to OpenBSD by Theo de Raadt, totally ignored that the original for gas targetting x86 both trapped and jumped.
I intentionally also pointed you to a collection of several critiques of the whole idea, long-since made. (-:
I think you're misunderstanding. 32 bit ARM has TWO instruction encodings. OpenBSD apparently only knows about one. In thumb encoding, the instruction is a branch, not a trap.
It just fills the memory with 0xd4 bytes. That happens to be a trapping instruction if it's filling space between aligned 32-bit ARM instructions. It doesn't work to infill 16-bit holes in thumb instructions at all (i.e. it's not a trap), but when used for its intended purpose it presumably works fine.
> It's not a bug; it's intentional that it works this way.
What is "this way"? Trap or jump? If you're saying a jump is supposed to count as a trap, it's a pretty bad one. It still allows a lot of jumps to the padding to continue and execute valuable code.
Putting instructions that halt execution in unreachable parts of the code would make sense, but this is just a jump with a fixed offset, which may technically still be exploitable.
If trap instructions are not possible, I would at least try to make it an unconditional jump to create an infinite loop.
> It's not exploitable. It's an exploit mitigation, in fact. It's not a bug; it's intentional that it works this way.
If the instructions are branching instead of trapping (as explained in the article) then it would be exploitable as a ROP gadget and it would be a bug.
You are misunderstanding the purpose of the initial jump in a trap sled. It is to redirect code which expects to flow through the sled past the traps, while leaving the traps for anything else which lands in that range.
The padding the article is talking about lives between functions. It is not meant to be executed, nothing is needed to jump over it. (The unconditional bx lr before it is the return at the end of the function.)
> The trapsleds implemented in this diff convert NOP sleds longer than 2 bytes from a series of 0x66666690 instructions to a 2 byte short JMP over a series of INT3 instructions that fill the rest of the gap.
The BMI instructions in the article are not jumping over breakpoint (INT3) instructions. They're conditionally jumping backwards by some amount.
Why in your belief is this? Please use your own words or a relevant direct quote to state your understanding of how a trapsled works.
Yes yes, but it's only an exploit mitigation if the bytes encode a mitigating instruction. On 32 bit ARM, they do. In thumb mode[1], they don't. That's interesting enough to be worth a blog post.
[1] For those who don't realize: author is on a Cortex-M processor per the ISA Ref they cite. These devices support *only* thumb instructions. Although as of thumb2, the encoding is now variable-length and there are lots of not-at-all-orthogonal-with-big-ARM 32 bit variants too. It's... not really the same architecture at all, to be honest.
Your second link suggests that this mitigation is not very helpful these days. I suppose in that light it doesn't really matter if LLVM changes it to a trap instruction or not.
This was put into OpenBSD back in 2017. It's not "trap instructions". It's "trapsleds". The idea is to trap the sleds (a.k.a. slides) of NOP instructions that linkers used to put in between compiled code for alignment, and which could be exploited with "return-oriented programming" where an attacker could cause execution to jump to any address in the padding range (possibly needing the inexactitude because of constraints upon byte substitutions) and slide along all of the NOPs to the target function.
* https://undeadly.org/cgi?action=article;sid=20170622065629
* https://isopenbsdsecu.re/mitigations/trapsled/