D384 - A gadget is not reached from a call site a compiler wrote
assumed - 2026-08-30
An access violation at
0xffffffffffffffff survived a dozen
eliminations across two sessions. It is not a wild pointer. It is what
Windows reports for a general-protection fault, and the
instruction that raised it was this:
0f 29 45 d0 movaps [rbp-0x30], xmm0
movaps is an aligned SSE store.
rbp was 0x600000800c58, so
rbp-0x30 was eight past a sixteen-byte boundary, and the
processor refused it. The optimiser had vectorised the copy of six saved
argument words into the dispatcher's own frame - a frame built on a
stack that was eight off.
Why only the gadget
Everything else a guest calls in this project arrives through a call site a compiler wrote: a relocation put a stub at an imported name, and the guest's own code called it with the stack the ABI requires. The run reports as much on every boot - all on a conforming stack - and that report has been true and has been checked.
A gadget is not reached that way. The guest holds a pointer where a
real system holds syscall; ret and goes through it however
its own code happens to, and ftpsrv arrives eight
off. Nothing was wrong with the guest: a raw gadget has no ABI,
so there is nothing for it to be wrong about.
The arithmetic in the gadget was right for a conforming caller and
had a comment explaining why, which is how it survived: the guest
called us, so rsp is eight past alignment. That
sentence is an assumption about the guest, written as though it were a
fact about the instruction set.
What it does now
push rbp the guest's, and where the old stack goes
mov rbp, rsp
and rsp, -16 aligned, whatever it was
...
call r11
mov rsp, rbp back to the guest's own, however it was aligned
pop rbp
rbp is callee-saved in both conventions, so the
dispatcher hands it back. The same change is made to the reporting
gadget stubs, which had the identical hazard by the identical route and
had simply never been pointed at a guest that arrives misaligned.
The general form
A boundary this project controls one side of must not assume the other side's ABI. It is the same shape as D381 - the dispatcher runs on the guest's stack, so it must not allocate - and this is the other half of it: the dispatcher runs on the guest's stack, so it must not assume it is aligned either.
ftpsrv reached its own main and ran to
completion the moment this changed, and every payload that keeps a
syscall gadget was one misaligned call away from the same fault.