3 ms·
> STOREALL, on the other hand, is used for a surprising purpose: as part of the sequence to exit from ICE mode! The reason is that it is the only instruction ca
by jart 4y ago
> STOREALL, on the other hand, is used for a surprising purpose: as part of the sequence to exit from ICE mode! The reason is that it is the only instruction capable of exiting protected mode, acting very much like a reset.
Ah so that's why Intel didn't want anyone to know about ICE. Could STOREALL be used to write a real exploit? It's interesting since I imagine that in order to know your security works, you have to violate it. I would just hope Intel's been practicing this in a way which doesn't let the bad guys do it too.
- bombcar 4y agoWasn’t this how you got unreal mode anyway? If you were executing things in ring 0 you already “pwnd” the box, after all.
- winocm 4y agoOn 286, yeah, 386/486 and later use a different sequence involving messing with segment descriptors and their limits in the 32-bit GDT. For reference, this file contains a canonical instruction sequence for entering and returning from big real mode: https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/Ia32/Thunk16.nasm https://github.com/tianocore/edk2/blob/master/MdePkg/Library... (x86_64 version: https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/X64/Thunk16.nasm https://github.com/tianocore/edk2/blob/master/MdePkg/Library...)
- anyfoo 4y agoYeah. The trick on the 386/486 is that the visible segment registers are only part of the actual registers. When you load a segment register, relevant data (base, limit, as far as I recall) from the descriptors get loaded into the invisible part (so a sort of "descriptor cache"). The "trick" was just to load the segment registers with a selector pointing to a descriptor with a large segment, and then just go back to real mode without immediately reloading the segment registers, as Intel very careful prescribes in their manual. The CPU would still use the unchanged hidden part of the registers for addressing. As soon as you load another value, that gets replaced with a real mode conformant 64k limit.
- Taniwha 4y agoSort depends on who's box you're trying to own - my box? (sure ring 0) Intel/bigmedia's key store's box? (then maybe something closer to the metal)
- rep_lodsb 4y agoAFAIK, nobody outside of Intel has a clear idea why they made the "protection enable" bit sticky on the 286. If the attacker controls ring 0, preventing them from exiting protected mode serves no purpose. No later CPU had this "security feature".
- anyfoo 4y agoAh, you think it was intended for "security"? I always imagined one of two things: 1) Intel didn't bother implementing or properly verifying that all the state transitions from protected to real mode work perfectly. But just the existence of LOADALL, and its use, pretty much completely invalidates that theory. Especially now that I learned from your article that ICEs were running the CPU in protected mode... 2) They really, really wanted to lure people away from real mode, and show protected mode as the future. Real mode being deprecated, ideally you would only use it to bootstrap into protected mode and nothing else. Somewhat related to that is the very exotic Intel 80376, which was essentially a 80386 with only protected mode! https://www.pagetable.com/?p=460 https://www.pagetable.com/?p=460
- TapamN 4y agoA quick search shows that LOADALL can only be run from ring 0, so the same might be true for STOREALL. So ring 0 kernel could use STOREALL to return to real mode, but ring 3 user code would probably get an illegal instruction trap.
- rep_lodsb 4y ago(author here) As mentioned in the post, LOAD/STOREALL only run in ring 0. Also you can't use it to return to real mode except from code running in ICE address space, which isn't accessible except on the special bond-out chip version. What you can do with STOREALL - with the F1 prefix - is store a bunch of internal registers to memory and then have an external chip (such as the AT keyboard controller) reset the CPU. Intel for some unknown reason tried really hard to make it impossible to exit protected mode!
- amluto 4y agoPrior to the introduction of SMM, Ring 0 (CPL0) was full privilege. The ability to kick the CPU into ICE mode, even if there was some way to actually do something in ICE mode [0] would have been, at most, a way to get at some Intel secret sauce. At attack against the system owner wasn’t in the cards, because the system owner never had any protection from CPL 0 code in the first place. (Unless the system could be induced to self destruct, but even a pretty good self destruct was likely possible from CPL 0 by destroying CMOS or potentially overwriting firmware.) Even with the addition of SMM, this wouldn’t have been a very big deal - SMM was mostly a kludge to allow system vendors to provide value-added (supposedly) features, and an SMM break would just allow reverse engineering of or interference with these. On a modern system, it’s a bigger deal. An attack against the ME is every bit as bad as it sounds. Even an attack against SMM breaks Secure Boot and protections against malicious firmware updates [1], which, in turn, could break some TPM protections. [0] Maybe with cache poisoning? If the instruction after STOREALL could be fetched from cache and regular ring 0 could poison that cache, code execution in ICE mode might be possible. [1] This is IMO a terrible design on Intel’s part. For some reason, UEFI secure variables are nearly universally implemented by protecting a region of flash from writes originating outside SMM mode. Once in SMM mode, they can be freely overwritten (at least unless SMM itself implements a protected kernel, which is the new hotness). Coming up with simpler and more secure designs is not terribly hard IMO.
- rep_lodsb 4y ago>Maybe with cache poisoning? If the instruction after STOREALL could be fetched from cache and regular ring 0 could poison that cache, code execution in ICE mode might be possible. The 286 had no internal cache (in the sense of CPUs today). It did have a queue of prefetched instruction bytes, as well as another queue of up to 3 decoded instructions. But that gets flushed by STOREALL, since it effectively returns the CPU to the same state as after a reset, only with the ICE mode flip-flop set. (Normal breakpoints, or any control transfer at all, also have to clear the queues, else the CPU would first execute whatever it had prefetched before continuing with code from the new location!) And yes, in my experiments with this I did try to stuff something in the prefetch queue anyway, as well as setting the IDT limit to zero and enabling the trap flag in the hope that it would cause a triple-fault while in ICE mode. No such luck. What might be possible is some external hardware that pushes opcode bytes onto the bus with the right timing. I'm not enough of a hardware person to design something like this, and don't think the DMA controller could be (ab)used for that purpose.