POSTED BY: Aris Thallas / 08.10.2020

Samsung Hypervisor (RKP) arbitrary zero write

CENSUS ID:CENSUS-2020-0002
CVE ID:CVE-2019-19273
Samsung ID:SVE-2019-16265 (Look for SVE-2019-16265)
Affected Products:Samsung mobile devices running Android O(8.0) and P(9.0) with Exynos 8895 chipset (tested on S8 and Note8 firmware)
Class:"Write What Where" Condition where "What" is always zero (CWE-123)
Discovered by:Aristeidis Thallas

CENSUS identified a bug in RKP, the Samsung EL2 Hypervisor implementation. The bug allows to write the zero 64-bit value to an arbitrary memory address. For the bug to be triggered, code execution is required in the context of the EL1 kernel. The bug was verified on the Samsung S8 and Note8 devices and was fixed by Samsung in the "SMR February-2020 Release 1". The bug may allow an adversary with kernel execution access to circumvent established security controls through the corruption of device memory. Users are urged to follow the latest security updates offered by Samsung for their mobile devices.

Vulnerability Details

CENSUS identified the bug on the RKP firmware found on S8 and Note8 devices.

In particular, the S8 device had the following firmware:

  • Firmware version: avalanche RKP64_8339d1c0
  • Firmware date: Nov 28 2018 - 19 17 33
  • Related Samsung version: G955FXXS5DSI1 - S8+ 2019/09
while the Note8 device carried the following firmware:
  • Firmware version: avalanche RKP64_a4d1f55c
  • Firmware date: Apr 5 2019 - 13 07 04
  • Related Samsung version: N950FXXU7DSJ1 - Note8 2019/10

All offsets provided in this report correspond to RKP version "avalanche RKP64_8339d1c0" of Samsung device firmware version "G955FXXS5DSI1".

Samsung RKP hypervisor invocations via the hvc command are handled by function rkp_main (found at 0xb010d000). The bug exists in the hvc command registered under identifier 0x9b. This is a "hidden" command, in the sense that we found no command reference or hints of invocation in the kernel source provided by Samsung in Samsung Open Source.

void rkp_main(uint64_t command, exception_frame *exception_frame)
{
    ...
    hvc_cmd_id = (command >> 12) & 0xFF;
    ...
    switch (hvc_cmd_id)
    {
    ...
    case 0x9B:
        sub_B0113AB4(exception_frame);
        break;
    ...
    }
} 

As demonstrated in the snippet bellow, the 0x9b command handler function's only argument is the exception frame during the hvc call. The function retrieves the second hvc argument (register X1) and adds it to immediate value 0x4080000000. The resulting value is used as an address to store global value qword_B013E658 (which is discussed next). There is no check or restriction regarding the value of X1.

int sub_B0113AB4(exception_frame *a1)
{
    *(a1->x1 + 0x4080000000) = qword_B013E658;
    rkp_debug_log("RKP_5675678c", qword_B013E658, 0, 0);
    return 0;
}

The value of qword_B013E658 is set to zero during RKP initialization as shown in the call-graph and snippet below, where the start() function is the RKP ELF entry point.

start() // entry point at 0xB0101000
\_ vmm_main() // function at 0xB0101818
    \_ sub_B0113A48()
 
int sub_B0113A48(void)
{
    if ( !dword_B013E660 )
    {
        qword_B013E658 = 0;
        dword_B013E660 = 1;
    }
    return 0;
}

As a result, an adversary can write the zero 64-bit value to arbitrary memory locations. The target address is a virtual address (not a physical one) and as such must be mapped as writable in the RKP page tables (see TTBR0_EL2).

Triggering the vulnerability

To call hvc and trigger this vulnerability, EL1 kernel code execution is required. In the hvc invocation the first argument (X0) must designate the desired command. Commands adhere to a certain format. Commands are expected to have a prefix value of 0x83800000. This prefix is ORed with the command identifier, after the command identifier has been shifted left by 12, to form the final command value. As a result, for command identifier 0x9b the hvc first argument (X0) value must be 0x8389b000.

The second argument (X1) is the value added to 0x4080000000 so its value must be the target virtual address subtracted by the aforementioned immediate value.

Example code (based on Samsung kernel code) is provided below to write a 64-bit zero value to virtual address target_va:

// C
rkp_call(0x8389b000, target_va - 0x4080000000, ...);
// asm
ENTRY(rkp_call)
hvc #0
ret
ENDPROC(rkp_call)

For more information regarding how to emulate a system for the RKP hypervisor and how to conduct vulnerability research on this component please see here.

Recommendation

Samsung has fixed the arbitrary memory write issue in the "SMR February-2020 Release 1" security patches. CENSUS strongly recommends to Samsung users to follow the latest security updates offered by the vendor for their mobile devices.

Disclosure Timeline

Vendor Contact:November 25, 2019
CVE Allocation:November 26, 2019
Vendor Confirmation:December 19, 2019
Vendor Fix Released:January 31, 2020
Public Advisory:October 8, 2020