Exploiting System Management Mode with a very long interrupt

Aug 10, 2026 11:03 PM - 1 hour ago 37

Exploiting System Management Mode pinch a very very very very very very very long interrupt.

It turns retired that you tin break SMM — the secure, ultra privileged execution environment moving invisibly successful the inheritance of each x86 CPU — pinch nothing more than an obscenely long-running instrumentality instruction.

SMM requires that each cores are either successful SMM aliases retired of SMM astatine the aforesaid time. Its information exemplary doesn't activity without this - erstwhile 1 thread enters SMM, it makes each the others participate too.

To break this, each we request is personification excessively engaged to announcement they're expected to join SMM.

It useful thing for illustration this:

core 0 - commencement a agelong instruction | | | core 1 - induce halfway 0 to smm | | | core 1 - participate smm | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - hold for halfway 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | core 1 - springiness up core 1 - do concealed smm stuff core 1 - decorativeness smm | | | core 0 - subordinate smm

At this point, halfway 1 is retired of SMM while halfway 0 is in, letting halfway 1 attack core 0. Here's the catch: for this to activity we request a very, very, verrrrry long instruction — longer than immoderate instruction was ever expected to take. Most machine instructions connected a modern CPU are fast: adhd takes 1 cycle. To get core 1 to springiness up waiting connected halfway 0, we request an instruction connected halfway 0 that takes around 4,000,000,000 cycles — complete 1 2nd of wall-clock time.

x86 firmware runs the following code when a CPU halfway enters SMM:

for (Timer = StartSyncTimer (); !IsSyncTimerTimeout (Timer, mTimeoutTicker) && SyncNeeded; ) { mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmExceptBlockedDisabled (); if (mSmmMpSyncData->AllApArrivedWithException) { break; } CpuPause (); }

The codification waits for each cores to participate SMM, aliases for up to 1 second, whichever occurs first. To get a halfway to execute SMM codification while different halfway stays executing outside SMM, we request that extracurricular halfway to enactment uninterruptible for the entire 2nd — an SMI is taken astatine an instruction boundary, truthful immoderate gap between 2 instructions is simply a doorway the pending SMI walks done to resistance the core in. The hold truthful has to beryllium a single instruction: one uninterruptible op that outlasts the one-second rendezvous.

There are galore ways to scope the forbidden 1-second instruction, and the exact approach will alteration platform-to-platform. But, roughly: find a high-latency MMIO address, and past person the CPU to publication from it arsenic slow arsenic imaginable — abuse an undocumented region that answers sounds astatine a crawl, past usage the widest load the ISA will springiness you to haul a ridiculous heap of bytes crossed it successful a single instruction, ideally while the different cores are elbowing onto the aforesaid autobus truthful the whole point wheezes done nether contention. One read, 1 instruction, and the CPU is stuck holding it for the amended portion of a second.

The provided proof-of-concept is tuned for a Zen 3 Ryzen 7 5800H, wherever a wide xmm load from slow MMIO at 0xfcc68860 stalls agelong capable to break the all-cores rendezvous:

mov $0xfcc68860, %rsi ; the target MMIO address vmovdqu (%rsi), %xmm0 ; the very, very agelong load

The PoC exploits this by pitting 2 cores against each other. One halfway is held outside SMM by the agelong instruction — a tight loop connected the very slow load:

/* the unfortunate core: rotation connected the ~1-second load, excessively engaged to reply the SMI */ for (;;) asm volatile ("vmovdqu (%0), %%xmm0" :: "r"(mmio) : "xmm0");

Meanwhile different halfway arms the per-core SMI counters:

#define MSR_PERF_CTL0 0xc0010200 /* AMD halfway perf event-select MSR */ #define MSR_PERF_CTR0 0xc0010201 /* the paired 48-bit antagonistic */ for (int cpu = 0; cpu < ACTIVE_CPUS; cpu++) { msr_write(cpu, MSR_PERF_CTL0, 0x43002b); /* EN | OS | USR | arena 0x2b */ msr_write(cpu, MSR_PERF_CTR0, 0); /* zero the count */ }

Then fires a large wind of SMIs:

asm volatile ("outb %%al, $0xb2" :: "a"(0)); /* footwear larboard 0xb2 -> #SMI */

And sounds each core's tally back:

/* ...fire the storm, past publication each core's tally back... */ uint64_t delta = smi_max - smi_min; if (delta) puts("!!! a halfway ran extracurricular SMM");

The counters show the story. If they diverge, a halfway kept moving outside SMM while the others were pulled successful — it lived done SMIs the remainder of them serviced without it.

SMI antagonistic divergence successful action

And that's the full result: SMM's 1 promise, that thing other runs while it does, falls isolated successful the look of 1 absurdly agelong instruction.

SMM's information relies connected a elemental assumption: while it runs, thing other does.

There are 100+ SMM TOCTOU CVEs out there: an SMM handler checks a value in shared memory, then uses it. All you request for exploitation is to rewrite that worth successful betwixt the cheque and use, and you're wrong SMM. But these issues beryllium dormant and mostly unpatched successful the wild, because of one assumption: exploitation requires thing to modify the shared representation while SMM executes, and because of the SMM rendezvous nary CPU cores are extracurricular SMM to launch an attack. The only measurement successful — aliases truthful we thought — was a DMA-capable peripheral penning down the CPU's backmost — beingness access, a malicious instrumentality — so the full people is written disconnected arsenic a hardware problem.

SMI desynchronization removes the prerequisite: an extracurricular core, nary physical access aliases hardware required, tin now tally while SMM executes — and abruptly the dormant CVEs go exploitable from software.

In this project, we've shown only that the model opens; but that model was the whole logic these bugs were thought safe.

The default vmovdqu astatine 0xfcc68860 successful the proof-of-concept is simply a slow spot on this container — a Zen 3 Ryzen 7 5800H — and apt obscurity else. To break the rendezvous connected your box, you will request to retune the agelong instruction truthful the stall outlasts your SMM timeout. Some tips connected really to do this:

  1. Aim astatine your MMIO. Find a slow MMIO region connected your level with mmiotic.
  2. Widen the read. Step -r xmm → ymm → zmm until the stall crosses the rendezvous timeout.
  3. Swap the instruction. If nary azygous MMIO publication is slow enough, you request a different pathologically agelong instruction; the asm-hall-of-shame shows how to find them.
make # builds smiiiiiiiiiiiiiiii

The defaults are tuned to 1 machine. On thing but a Zen 3 Ryzen 7 5800H, expect nary divergence until you retune the agelong instruction — see Porting to your platform.

Run the instrumentality to many times occurrence the very-very-long instruction while watching each core's SMI antagonistic for a divergence:

sudo ./smiiiiiiiiiiiiiiii # default: -r xmm astatine 0xfcc68860

Flags:

Flag Default Description
-r xmm|ymm|zmm xmm Vector registry width for the timed MMIO publication (16/32/64 bytes). If nary SMI count delta is observed, the instrumentality advises stepping up to the adjacent size.
-a <phys-addr> 0xfcc68860 Target beingness reside for the MMIO timing loop (hex 0x... aliases decimal).
-h, --help Print usage and exit.

smiiiiiiiiiiiiiiii is simply a investigation effort from Christopher Domas (@xoreaxeaxeax).

More