"Speculative instruction fetch to device memory crashes device" is in my list of favorite bugs ever found. I had ran into it on a Cortex-M4 without an MPU, so I couldn't even fix the memory attributes, the only solution was to gerrymander the compiled code to prevent the speculative fetch.
It's crazy that Armv8/9-A permits speculative instruction fetches to device memory. Crazy enough that I had to look it up to believe it:
"Hardware does not prevent speculative instruction fetches from a memory location with any of the Device memory attributes unless the memory location is also marked as execute-never for all Exception levels." - ARM DDI 0487K.a § B2.15.2
The Armv7-M spec is less clear. It does say: "The architecture does not permit speculative accesses to memory marked as Device," in contrast to Armv8/9-A which qualifies a similar statement with "data accesses". But then it later says "To ensure correctness, read-sensitive locations must be marked as non-executable". (This is all from ARM DDI 0403E.e § A3.5.7)
I don't have v7-A older handy to compare what they say.
asveikautoday at 2:54 AM
On this theme of it not being just about security: if you have a bug like a use after free and it happens to cover a function pointer, the nx bit can ensure that when you follow that pointer through a call, you get a clean trap as close to the failure point as possible. If it blindly executed stale bytes as code, maybe the crash and stack trace doesn't look as nice.
But then, a lot of correctness bugs like that are also security problems.
anyfootoday at 6:30 AM
Nowadays, it's considered bad form to map anything at 0... you now know one of the reasons why!
In the case that I know that has a 1:1 identity mapping of the address space, the physical address space doesn't actually have anything at 0 either, so it still doesn't need to be mapped.
mubbiclestoday at 3:18 AM
I appreciated this article. I've asked our CSP guy the difference, but this helps me better understand device vs ns. I also appreciate that this doesn't appear AI written.
dmitrygrtoday at 3:45 AM
This is doubly weird because actually purposefully executing from device memory is not allowed: “Trying to execute code from a region marked as Device is UNPREDICTABLE.” So: can’t reliably execute from there but can speculatively instruction fetch from there. Funsies!
I really wish I understood this, it hits a bunch of topics that I've heard of and are/sound interesting, but I don't know enough to follow it. I don't get the link between the NX bit (which I get) and speculative access.
eqvinoxtoday at 3:29 AM
Honestly feels like a misdesign in ARM. Where does it ever make sense for Device memory to not be data prefetchable, but allow instruction prefetch? It should IMHO disable all prefetch…
achieriustoday at 3:49 AM
> while ARM does provide a reference implementation of the architecture, vendors are free to customize it at will, or even roll their own implementations
A nitpick, but this is only true for some vendors, depending on their license, and is very much company-by-company. Many vendors, even big names like Meta, don't have the ability to roll their own. And even for the ones who do, 'customize at will' is a bit strong, as ARM very much does want to maintain uniformity across userspace implementations. E.g. Nvidia shouldn't add new traps for architecturally-legal behavior, since then code compiled for Apple hardware wouldn't work on Grace. Or worse, not trap for architecturally-illegal behavior, since then code compiled for Grace might not work for anyone else at all!
yuxinkingtoday at 5:21 AM
[dead]
crazy1_today at 2:49 AM
this is so amazing
Nail2680today at 2:45 AM
Hot take: NX bit is shit W^X is shit. proper JIT is having objects written as needed, and cache line flushing is full bullshit, we need self modifying code as a first class citizen and with modern techiques we can have it work and not be crazy slow, it is currently cuz shits fucked, but we can do better.