Clever ARM instruction validation for Chrome Native Client(chromium.org)
chromium.org
Clever ARM instruction validation for Chrome Native Client
http://www.chromium.org/nativeclient/reference/arm-overview
3 comments
Because you'll fault in the guard zone on one of those memory accesses, and then your app will get killed.
EDIT: No, you don't need to check after a stack memory access either. The farthest you can get out of the sandbox is an access-then-adjust of 4095 bytes, followed by an adjust-then-access of 4095 bytes, which means you access the very tail end (offset 8190) of the guard zone, fault, and die.
EDIT: No, you don't need to check after a stack memory access either. The farthest you can get out of the sandbox is an access-then-adjust of 4095 bytes, followed by an adjust-then-access of 4095 bytes, which means you access the very tail end (offset 8190) of the guard zone, fault, and die.
Thanks, I just realized that ... duh. I'd been imagining the guard regions as a "passive guard", eg: an area where nothing important is, rather than as an "active guard", eg: where you fault if you read/write.
I see a lot of interesting techniques here. I couldn't figure out is how writes are prevented to code areas in the sandbox. I'd guess they mark pages with code-bundles as read-only but I don't see any specific mention of it.
(The article does mention that the guard pages are set to no read/write/execute)
(The article does mention that the guard pages are set to no read/write/execute)
Turning every load or store from one instruction into two sounds slow; pNaCl can't arrive soon enough.
It sounds slow, but think about what's going on in the processor. Memory access instructions are far slower than simple arithmetic instructions. As for the conditional nature of the load instructions, I'm sure that the Cortex-A9 branch predictor will make the overhead from that pretty close to negligible. And there's probably something similar on the Cortex-A8, though I haven't checked.
In other words, this is a lot less slow than it sounds.
In other words, this is a lot less slow than it sounds.
The branch predictor is not involved here since there is no branch. A conditional non-branch instruction is, on most implementations, scheduled identically to the unconditional base instruction. A load/store instruction whose condition passes thus executes identically to an unconditional one. If the condition fails, it schedules as though it had hit L1 cache.
The main problem I see here is significantly increased code size, which will put additional pressure on the L1 I-cache.
The main problem I see here is significantly increased code size, which will put additional pressure on the L1 I-cache.
Fast code doesn't touch memory that often - if you're doing enough loads/stores that the extra instruction is significant, you're probably bounded by memory latency instead of processor speed anyway.
And the most common "frequent" accesses (stack space) don't require those checks.
And the most common "frequent" accesses (stack space) don't require those checks.
Won't iterating over a heap-allocated array result in a load for every element? A lot of good C will keep a lot in L1, but it won't always be in registers or on the stack.
Yes, there you'll be incurring the huge performance penalty of one additional instruction per element in the array.
As I said, not really significant unless your loop is so tight that memory latency is the big limiter anyway.
As I said, not really significant unless your loop is so tight that memory latency is the big limiter anyway.
I get the idea of the guard protecting against the biggest immediate offset, but what stops me doing an SP-updating LDR with a big offset multiple times, pushing SP beyond my "safe" memory segment?
EDIT: I guess I might be taking:
too precisely, and you could just follow every ldr which writes back SP with a BIC too. Maybe I'm missing the point.
EDIT2: Wait, wait, I get it now. Once the stack pointer is in the guard area, the CPU faults if you do another LDR. Don't mind me!