Skip to content

Generic exploit for all version 7 (maybe others) LM32-based AMD SMU's used in APUs (and probably works on GPUs too)

License

Notifications You must be signed in to change notification settings

jevinskie/amd-lm32-smu-exploit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 

Repository files navigation

AMD LM32-based System Management Unit Exploitation and Bootrom Dumping

Generic exploit for all version 7 (maybe others) LM32-based AMD SMU's used in APUs (and probably works on GPUs too). Note that since Zen, the SMU/RSMU (Remote SMU) are Xtensa cores and thus this does not apply to them.

I'll be cleaning up and uploading the code to perform these exploits but for now I will just jot down a description of the exploit.

OK, so Rudolf Marek already exploited an LM32-based AMD SMU in his talk titled AMD x86 SMU firmware analysis Do you care about Matroshka processors? but AMD supposedly patched the SMU message handler vulnerability.

I am lazy, I didn't want to find a new software-based exploit in the SMU firmware even though I wrote a Ghidra LM32 Processor plugin in order to analyze the firmwares. Are there any other ways to get code execution in SMU? Once you do, you can dump its bootrom which contains the HMAC key so you can sign your own firmwares, and do cool stuff like read eFuses, get serial port IO and even read/write arbitrary DRAM. Pretty cool, huh?

The SMU's SRAM has an unlocked region at 0x3F000-0x40000 for communication between x86 world and SMU world. Trying to read out other parts, including the bootrom, will give you 0x55aa55aa or 0xaa55aa55 (TODO: I forget which, its read lockout value is stored in another SMU register).

Well it turns out AMD integrated the LM32 so completely that it retained its debug functionality. The attack proceeds as follows, all accessesss are done via an indirection addresss/data scheme to the PCI root complex:

  1. Monitor SMU SRAM 0x3F000-0x40000 to find suitable place for a code cave for your shellcode. I've provided a visualization of the activity there
  • I ended up picking 0x0003_F400-0x0003_F600 for my tiny shellcode stubs in one instance.
  1. Monitor SMU's Program Counter by polling in a loop the SMC_PC_C register at 0x80000370. Generate a histogram and pick the most executed instruction address.
  2. Write the register SMC_LM32_DEBA at 0x80000334 to point to your debug vector table residing in your shellcode, in the shared SRAM region.
  3. Write the register SMC_LM32_BP0 at 0x80000338 to point to the most commonly executed instruction address.
  4. Write the register SMC_LM32_DC at 0x80000330 to enable HW breakpoint zero.
  5. Wait until the firmware runs that common instruction address and the breakpoint will be triggered and jump to your debug vector table shellcode.
  6. From within the SMU you can turn off the read/write SRAM protections and read out the bootrom.

The bootrom will contain a hardcoded HMAC key but there is an eFuse bit that allows vendors to program a custom HMAC key in the eFuses. Luckily those can be dumped too.

This is the Ghidra decompilation from the bootrom of a Kaveri or Kabini APU (I forget which right now)

    AUTH_START_ADDR = (FIRMWARE_HEADER_V7 *)(efuse_read1 & 0x7fffffff);
    entry_point = (code *)AUTH_START_ADDR->EntryPoint;
    calc_digest[1] = 0xefcdab89;
    calc_digest[3] = 0x10325476;
    calc_digest[0] = 0x67452301;
    calc_digest[2] = 0x98badcfe;
                    // sha constant shit
    calc_digest[4] = 0xc3d2e1f0;
    do {
      efuse_read1 = read_volatile_4(SMU_FIRMWARE_AUTH);
                    // spin while SMU_KEY_RD_DONE != 11b
    } while ((efuse_read1 & 6) != 6);
    efuse_read1 = read_volatile_4(SMU_FIRMWARE_AUTH);
                    // SMU_KEY_SEL
    if ((efuse_read1 & 0x20000) == 0) {
      key[0] = 0x3818c563;
      key[1] = 0x2f4383c1;
      key[2] = 0x21853a57;
      key[3] = 0xd7c7169;
    }
    else {
      key[0] = read_volatile_4(SMU_SECURE_KEY_0);
      key[1] = read_volatile_4(SMU_SECURE_KEY_1);
      key[2] = read_volatile_4(SMU_SECURE_KEY_2);
      key[3] = read_volatile_4(SMU_SECURE_KEY_3);
    }
    hmac(&AUTH_START_ADDR->Version,key,calc_digest,AUTH_START_ADDR->CodeSize >> 2);

Related projects:

fxsheep's ROM dumper

zamaudio's smutool

About

Generic exploit for all version 7 (maybe others) LM32-based AMD SMU's used in APUs (and probably works on GPUs too)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published