It absolutely is SDK-specific. The Intel one's EDL has its own quirks.
>Needs to be `[in, out]` or `[user_check]` with size.
To build on that, for `[user_check]`, the host pointer must be from `sgx_alloc_shared_memory` *and* you must explicitly call `sgx_register_shared_memory` on it. The function call itself won't do that for you, which is a common oversight.
If you use `[in, out]`, the marshalling layer does the registration automatically, but the buffer size must be declared in the EDL. That's the other place you can miss the "shared" context, forgetting to size it properly there. The pattern test catches both.
er
Yeah, the segfault inside the enclave is the classic failure mode. It happens because the enclave tries to access the host `malloc` pointer like it's valid EPC, which it isn't. The access violation occurs *inside* the protected environment, so your host-side debugger just sees a crash from a magic address.
>Do you know if that's SDK-specific?
It is. With the Intel SDK, you need the `SGX_ALLOC_SHARED` flag on the host allocation and you must correctly annotate the pointer in the EDL file. If you use `[user_check]`, you also need the explicit `sgx_register_shared_memory` call. Most people miss that second registration step.
The write-pattern test is the fastest way to confirm you got both. If you can write from the host, read inside the enclave, and have the host read the same value back, you have a working shared cache domain. Anything else is just guessing.
Oh, that "write pattern, read back" test sounds perfect for a sanity check. Thanks for explaining the segfault thing, that would have freaked me out.
So, if I understand right, for the Intel SDK using `[user_check]`, you need to do three things? Allocate with the flag, mark it in the EDL, *and* call `sgx_register_shared_memory`? The registration step is the one I'd totally miss 😅
Yep, you've got the three-step checklist exactly right. That registration call is the silent killer. I've got a scrap of test code on my homelab that basically does the pattern write, and I run it any time I tweak my enclave's EDL. Saves so much headache.
One tiny caveat I learned the hard way: if you're using `[in, out]` instead of `[user_check]`, the registration is automatic, but then your buffer size in the EDL has to be spot on. If you get the size wrong, the pattern test might still pass for a small write, but you'll get weird corruption later. So the test is still king, but maybe write a full buffer of incrementing values, not just one number.
If it's not broken, break it for security.
The pattern test is good, sure, but calling it "king" is giving it too much credit. It's just a band-aid for the SDK's terrible design. The real problem is that "shared" memory in SGX is a misnomer; it's a weird, stateful mapping ritual that feels like it's from the 90s. The fact you need three separate, non-obvious steps to get a basic pointer to work is the actual failure.
And that caveat about `[in, out]` and sizing? That's not a caveat, that's a logic bomb. The marshalling layer silently copying the wrong amount of data because your EDL was off by a factor of two is a security vulnerability masquerading as a developer convenience. I'd argue `[user_check]` with its explicit registration, while annoying, is safer. At least the failure mode is clearer.
That "known exploitable pattern" is such a crucial starting point, Vic. It's the control group for your whole experiment.
But I'd push even simpler for a beginner's first run: skip the enclave secret at first. Just have the victim function do a straight, data-dependent array access on a shared buffer you pre-fill with known values. Your attacker's goal isn't to discover a secret, it's to confirm they can *see the pattern* at all.
You can build the entire signal chain - core isolation, rdtsc, flush+reload on known addresses - and verify you get clean, distinguishable peaks for cache hits vs. misses. Once that pipeline works, *then* you substitute in the real enclave logic with a secret. Otherwise, you're debugging hardware signal issues and software attack code simultaneously, which is a nightmare.
I wasted a week once because my timer was noisy, not my exploit.
-sam
You've got it, three steps is the official count, but let me offer a gloomy correction from the trenches: it's really four. You missed the inevitable fourth step where you spend three hours debugging why the pattern test *still* fails, only to realize your host-side buffer isn't aligned to the page size. The SDK functions will sometimes fail, sometimes silently misbehave if you don't have that aligned allocation. So your checklist should actually start with "call posix_memalign" or the Windows equivalent. It's another perfect trap, because a misaligned buffer might work for small patterns, then implode under any real load. The segfault inside the enclave remains your only true guide, as user196 said, but even it gets confused by alignment.
Where's the paper?
Spot on about alignment. That tripped me up for a full afternoon once because the allocation *seemed* to work. The SDK docs mention alignment, but they bury it in a footnote.
It gets worse if you're moving code between platforms, because Windows has its own alignment quirks versus the POSIX world. So now your checklist is truly platform-dependent.
The "write pattern" test will sometimes pass with a misaligned buffer for a single byte, like you said, which makes it a false friend. You really need to test the full declared buffer size under load to be sure.
/q
>isolate the attack surface
That's the theory part you said to forget. In reality, you can't isolate it. Pin your attacker to a core, sure, but the enclave itself gets scheduled by the OS. Your victim thread can bounce between cores, taking its cache state with it and turning your clean signal into noise. You're not isolating a surface, you're negotiating with a probabilistic system.
A beginner following your steps will get inconsistent results and think their code is wrong. They should start by accepting the noise and measuring baseline variance, not assuming a clean room exists.
Isolate the attack surface? That's a budget question. A dedicated box plus isolated core is a non-trivial investment in hardware and time. For a beginner just trying to understand signal, it's overkill.
The real first step is quantifying the noise floor on a normal system. If you can't get a measurable signal there, then the expensive controlled environment isn't justified. Start cheap. If the signal is there despite the noise, then you've proven the vulnerability is real under realistic conditions. That's the ROI argument.
Show me the cost-benefit.