diff --git a/documentation/source/BootROM_8890/images/ghidra_dwc3_dcfg_devaddr.png b/documentation/source/BootROM_8890/images/ghidra_dwc3_dcfg_devaddr.png new file mode 100644 index 0000000..19d8ff7 Binary files /dev/null and b/documentation/source/BootROM_8890/images/ghidra_dwc3_dcfg_devaddr.png differ diff --git a/documentation/source/BootROM_8890/index.rst b/documentation/source/BootROM_8890/index.rst index a42c3a8..f9c2514 100644 --- a/documentation/source/BootROM_8890/index.rst +++ b/documentation/source/BootROM_8890/index.rst @@ -34,8 +34,9 @@ When the ROM is unable to boot from the internal storage, it enters ``Exynos Rec In this mode the bootROM accepts data over USB. There is little functionality other than receiving data, meaning almost no additional attack surface except for the download protocol. -The Exynos BootROM uses a custom protocol to download a bootable image over USB. -This image is verified and executed by the BootROM. Unauthorized images are rejected. (TODO verify and document) +The Exynos BootROM uses a custom protocol to download a bootable image over USB. This image is verified and executed by the BootROM. Unauthorized images are rejected. Initial authorisation is done using the '_auth_bl1' function. + +(TODO verify and document) dldata ------ @@ -77,15 +78,48 @@ The base address of the usb controller (dwusb3) is mapped at 0x1540000, with a s }; };c - This is a basic USB controller, but some functions, that are also present in the linux kernel, should be visible in the bootROM as well. Available functions could be: `linux-kernel-dwc3 `_. +The USB host sends a USB_REQ_SET_ADDRESS, `'0x05' `_, which the connected device has to acknowledge, and will then start sending data to this address. Initially, the device will send data to '0x00'. + +.. code:: c + + usb_reqid { + USB_REQ_GET_STATUS = 0, + USB_REQ_CLEAR_FEATURE = 1, + USB_REQ_SET_FEATURE = 3, + USB_REQ_SET_ADDRESS = 5, + USB_REQ_GET_DESCRIPTOR = 6, + USB_REQ_SET_DESCRIPTOR = 7, + USB_REQ_GET_CONFIGURATION = 8, + USB_REQ_SET_CONFIGURATION = 9, + USB_REQ_GET_INTERFACE = 10, + USB_REQ_SET_INTERFACE = 11, + USB_REQ_SYNCH_FRAME = 12 + } + +Ghidra shows `DWC3_DCFG & 0xfffffc00 | DWC3_DCFG & 7 | (param_1 & 0x7f) << 3;`, essentially preserves bits 0-2 and 10-31, and sets bits 3-9 to the value of param_1, which is then likely the address of the device. + +.. figure:: images/ghidra_dwc3_dcfg_devaddr.png + + bootrom exynos 8890 dwc3_dcfg_devaddr + +Other general device descriptors are also sent from the device to the host (to describe the device), these are visible in/at 'usb_init_device_descriptor' (6098) and usb_init_descriptors (610c). Two end point addresses are visible: bEndpointAddress 0x81 and 0x02. 0x81 is 10000001 in binary, with bit 7 being '1', which means that the bulk transfer direction is IN. 0x02 is 00000010 in binary, with bit '7' being '0', which means that the bulk transfer direction is OUT. + +Data is transferred via Transfer Request Blocks (TRB), dwc3_depcmd_starttransfer is used. The TRB then contains a buffer address, where transferred data from the host is written to. The buffer allocation is done by 'usb_setup_event_buffer', which sets bufferHigh (DWC3_GEVNTADRLO), bufferLow (DWC3_GEVNTADRHI) and bufferSize (DWC3_GEVNTSIZ). + Bug 1(Integer underflow) ------------------------ +Originally described in this `blogpost `_. -https://github.com/LineageOS/android_kernel_samsung_universal8890/blob/lineage-18.1/arch/arm64/boot/dts/exynos8890.dtsi +The exynos bootrom uses a simple USB protocol to receive a bootloader binary from a USB host. The binary sent is called 'dldata'. In Ghidra, at 21518, we can see that it consists of unit32_t: ready?, uint32: size, ? : data, uint16: footer. The contents of this data are checked before being being written. -@TODO better explain frederick's bug. @JONHE +.. code:: c + if ((pdVar1->size < 0x206ffff) && (0x206ffff < pdVar1->size + remaining)) { + *(undefined *)&pdVar1->ready = 2; + } + +In essence, in the first conditions, it checks whether the size is smaller than 0x206fff (`pdVar1->size < 0x206ffff`) (34013183 in decimal), and in the second condition, it checks whether 0x206ffff is smaller than the size + remaining (`0x206ffff < pdVar1->size + remaining`). If both conditions are met, the ready flag is set to 2, and the function below to execute the *payload*, will NOT execute! Bug 2