Probably more of a "stick it in the toolbox for automatic use" rather than building an exploit around it type of situation however.
(Unless someone stays up all night to find the bugs....)
I definitely wouldn't have got this far looking at this - I'd have quickly assumed it was a sentinel value being used for padding and moved on with my day. Good work.
> [This patch] fills holes in executable sections with 0xd4 (ARM) or 0xef (MIPS). These trap instructions were suggested by Theo de Raadt.
into commit messages, but not in the code. What's the cost? What's the downside to having a 2 to 3 line comment above a constant in a C file? Why pretend like all this is super obvious when clearly it isn't?
There seems to be some unwritten cultural rule, particularly in FOSS land, that you're supposed to write code as if you're an all-knowing oracle, as if everything is obvious, and so comments are for losers (as are descriptive variable names). I simply can't understand how and why that developed.
Another argument is comments-as-noise, as I would call it. The more "unnecessary" comments you write, the more core developers (who write and read most of the code), will learn to ignore comments. Then, critical comments like "Be careful not to call this when XYZ isn't initialized yet, unless you don't mind ABC happening" are ignored, and ta-da! comments are now useless.
Commit messages are attached to specific changes. If I want to know why a line of code is the way it is, I can git blame it, and see which commit is to blame, together with issue numbers, authors, maybe reviewers, context, history, etc.
Should there be a comment briefly explaining this patch? Probably. But the commit message should add the other context.
> [W]e find this in ARM.cpp:
> trapInstr = {0xd4, 0xd4, 0xd4, 0xd4};
The only thing left to explain is that the trap instruction is used as padding, but you can’t tell from here if that’s obvious or not. Opening the actual code[1], we see that the occurrences of trapInstr are all along the lines of
> void ARM::writePlt( /* ... */ ) {
> /* ... */
> memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary
which isn’t the absolute best, but seems clear enough (if of course you know what a PLT is, which you should if you’re writing a linker).
I do think this merits an explanation that we’re using (what’s intended to be) a trap because the traditional option of using a nop makes ASLR less effective. But then the commit message you’re quoting doesn’t mention that either.
[1] https://github.com/llvm/llvm-project/blob/b20c291baec94ba370...
In fact, as a former code auditor I can say that comments at times make bug finding harder -- they frame you up a certain way. I definitely preferred to audit without comments.
Anyway, there are definitely valid reasons. I think the commit log or dev notes files are generally preferable, especially when combined with good naming.
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
Don't get them talking, for starters, about the flag files problems that people have introduced to doas, for example, because they didn't copy the OpenBSD kernel feature that original doas relies upon. Or you'll invoke the spirit of Ted Unangst.
* https://news.ycombinator.com/item?id=37314526
Here, they've missed the clear explanation in the original of how and why it both traps and jumps. (And what caution made them add the jump, even though Microsoft had prior to that time been doing the trap-only version for years.)
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.)
And you also haven't spotted, even though Nathan Michaels called it out, that the LLVM version is from someone who either read what Theo de Raadt wrote in the commit or read Todd Mortimer's account of the BSDCan conversation, and copied the idea from GCC for x86 into LLVM for ARM. Rui Ueyama, like you, didn't absorb all of the original explanation, however, otherwise xe would have caught why Todd Mortimer didn't originally do the Microsoft-style string of all-the-same instructions that Rui Ueyama then did.
> 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.
The article doesn't say it is.
> It's an exploit mitigation, in fact.
The article made that clear.
> 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.
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!)
Hence yes, this is a broken exploit mitigation.
I intentionally also pointed you to a collection of several critiques of the whole idea, long-since made. (-:
And why, in your own words, is it OK for the jump to be a conditional backwards jump?
Being ARM32, these should be BKPT (hex BExx). [2]
[1] https://developer.arm.com/documentation/ddi0602/2025-06/Base...
[2] https://developer.arm.com/documentation/ddi0597/2024-09/Base...
rokkamokka•4h ago