Yahallo: Free memory access
The Yahallo exploit uses a security vulnerability in the NVIDIA Tegra 3 / Tegra 4 UEFI firmware to disable the SMMU memory protection. As a result you can access all memory.
Disclaimer Most information only applies to SurfaceRT, but some yahallo information applies to Surface RT 2 too.
Because NVIDIA/Microsoft didn't implement a check for maximum buffer size when using a SMC instruction to register a new shared buffer, it is possible to create a buffer overflow, which is then used to overwrite the area where a BootServices->SetMem UEFI call writes its memory.
First, you need to know which values are used from the SMC in the calculation, we don't care about parameters 1 and 2. Parameter 3 is request_area, so in yahallo source 0x40000000. Parameter 4 is area_slice, so in yahallo source 0x6001e0e0.
The calculation has the following formular:
response_area = (request_area + (area_slice >> 1))Examples:
0x7000_f070 = (0x4000_0000 + (0x6001_e0e0 >> 1) 0x7000_f010 = (0x4000_0000 + (0x6001_e020 >> 1))
The Tegra 3 Technical Reference Manual (TRM) has important information about virtual addressing and configuration registers in section 18. You can download it here, but downloading requires a NVIDIA developer account.
The SMMU (System Memory Managment Unit) is part of the SOC, and not part of the Cortex-A9 cores. The CPU cores have a MMU too, you can simply disable it with a
ArmDisableMmu()call in the edk2 source tree. Yahallo reconfigures the SMMU, so all SMMU memory protection is gone. The CPU MMU still protects this memory, but you can easily disable it.
To disable the SMMU, you need to write 0's to the SMMU Enable Register (0x7000f010). This can only be done when you are in secure mode, so it doesn't work if you just disable the CPU MMU. With the help of the Yahallo exploit we can write to all memory locations in secure mode, because the BootServices->SetMem call executes in secure mode. (UEFI firmware operates in secure mode generally)
Yahallo writes 32 bytes of 0's to 0x7000f070, so it writes the Secure Region Configuration Base register, Secure Region Configuration Bound register and the Protected Region Configuration Bound register.
This makes the Trustzone 0MB in size (SMMU side), so you have access to non-trustzone-secured* memory, when CPU doesn't restrict memory access. The CPU restrictions can be removed by disabling the MMU.
* Some registers are restricted to be only accessible from Trustzone-secured CPU memory access. (e.g. from the SMMU_ENABLE register from TRM: This register can only be accessed by Trustzone-Secured accesses from the CPU.)