chenxiaolong / avbroot

Sign (and root) Android A/B OTAs with custom keys while preserving Android Verified Boot
GNU General Public License v3.0
526 stars 43 forks source link

Unknown boot image format error #366

Open lkernan opened 4 days ago

lkernan commented 4 days ago

Hi, I'm doing some playing around with an OTA image for my cars infotainment unit. It's running Android 9.

avbroot had no problems extracting the boot image, but when I do a boot info command I get the error:

leon@cartman:~/Downloads/avbroot$ ./avbroot boot info -d --log-level trace --input boot.img 0.000s DEBUG cli=Cli { command: Boot(BootCli { command: Info(InfoCli { input: "boot.img" }), quiet: false, debug: true }), log_level: Level(Trace), log_format: Short } 0.000s ERROR Failed to read boot image: "boot.img"

Caused by: Unknown boot image format

I've verified it has extracted the boot image correctly.

My plan is to use the --rootless option since I mainly want to patch a file on the system partition.
The car manufacturer put some firewall commands in to block ADB port 5555 on all interfaces so at the moment we don't have ADB and I need to patch them out.

One thing we do know is that they signed everything with the test-keys so that part is not a concern.

A copy of the boot.img can be found here: https://www.dropbox.com/scl/fi/6edbvsk43gcv17j4kkh51/boot.img?rlkey=pbgktsrbnyidzm7jmh0j5tti3&st=nehlziw7&dl=0

chenxiaolong commented 4 days ago

Thanks for uploading the boot.img! It looks like it's a u-boot FIT image, not a standard Android boot image. I've never seen this combo of AVB 2.0 + non-Android boot image format before.

It's unlikely I'll add support parsing these boot images. The format is quite a bit more complex to parse than standard Android boot images and it's not very common. The best I could do is maybe add a --skip-ota-certs option, which in addition to --rootless, would make avbroot not touch the boot image at all (it would only do AVB and OTA signing).

❯ mkimage -l boot.img 
Image contains unit addresses @, this will break signing
FIT description: U-Boot fitImage for Android 147456/4.9/auto2712m1v1-initramfs
Created:         Mon Sep 11 03:51:55 2023
 Image 0 (kernel@1)
  Description:  Linux kernel
  Created:      Mon Sep 11 03:51:55 2023
  Type:         Kernel Image
  Compression:  lz4 compressed
  Data Size:    11582667 Bytes = 11311.20 KiB = 11.05 MiB
  Architecture: ARM
  OS:           Linux
  Load Address: 0x40008000
  Entry Point:  0x40008000
  Hash algo:    sha256
  Hash value:   dfde18fbb1d1fee962eebad7a548de59ca95e6eaea403792496edbd8ded522a7
 Image 1 (ramdisk@1)
  Description:  Ramdisk Image
  Created:      Mon Sep 11 03:51:55 2023
  Type:         RAMDisk Image
  Compression:  uncompressed
  Data Size:    7961761 Bytes = 7775.16 KiB = 7.59 MiB
  Architecture: ARM
  OS:           Linux
  Load Address: 0x4a000000
  Entry Point:  0x4a000000
  Hash algo:    sha256
  Hash value:   def3f7cee122d0951c070626c7ff1d17b6a6d36f06d959ed5aea172fde4f8019
 Image 2 (fdt@1)
  Description:  Flattened Device Tree blob
  Created:      Mon Sep 11 03:51:55 2023
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    98058 Bytes = 95.76 KiB = 0.09 MiB
  Architecture: ARM
  Load Address: 0x44000000
  Hash algo:    sha256
  Hash value:   1bb0072041178e90ad866eeffa7f6a08b4d57c94f777bec76b44f50e95167778
 Default Configuration: 'conf@1'
 Configuration 0 (conf@1)
  Description:  Boot Linux kernel with FDT blob
  Kernel:       kernel@1
  Init Ramdisk: ramdisk@1
  FDT:          fdt@1
  Sign algo:    sha256,rsa2048:dev
  Sign value:   unavailable
  Timestamp:    unavailable
dumpimage -T flat_dt -p 0 -o kernel boot.img
dumpimage -T flat_dt -p 1 -o ramdisk boot.img
dumpimage -T flat_dt -p 2 -o devicetree boot.img
lkernan commented 4 days ago

Thanks, at least for my purposes not touching the boot image at all would work. As long as I can patch the file in /system/bin and put the payload.bin back together.

The whole system has been confusing the heck out of me. Probably not a surprise it's based on a Mediatek SDK. I'm reluctant to do too much since fastboot and recovery aren't easily accessible either.
I think the uboot console might be on a serial console but that's probably going to require opening the unit.

edit: I did a little more digging and found a mention of this AVB setup in the u-boot docs. https://github.com/u-boot/u-boot/blob/master/doc/android/avb2.rst

chenxiaolong commented 3 days ago

Car infotainment systems definitely seem to be quite a bit more... interesting than phones.

I totally get the reluctance to try stuff. I haven't messed with my car's infotainment system because it can only boot into recovery or fastboot with adb reboot. There's no other physical way to do so, even if disassembled. People who've flashed an unbootable boot.img have had to manually reflash a working image with a NAND programmer to get things going again.


Please give #367 a try, which adds a new --skip-recovery-ota-cert option. Prebuilt binaries can be found at the bottom of this page: https://github.com/chenxiaolong/avbroot/actions/runs/11674513228?pr=367

lkernan commented 3 days ago

I've given it a try and it looks like it's still trying to do something with the boot.img

leon@cartman:~/Downloads/avbroot$ ./avbroot ota patch --input usb_ota_update.zip --key-ota testkey.x509.key --key-avb testkey.x509.key --cert-ota testkey.x509.crt --rootless --skip-recovery-ota-cert --log-level trace 0.000s DEBUG cli=Cli { command: Ota(OtaCli { command: Patch(PatchCli { input: "usb_ota_update.zip", output: None, key_avb: "testkey.x509.key", key_ota: "testkey.x509.key", cert_ota: "testkey.x509.crt", pass_avb_env_var: None, pass_avb_file: None, pass_ota_env_var: None, pass_ota_file: None, signing_helper: None, replace: [], root: RootGroup { magisk: None, prepatched: None, rootless: true }, magisk_preinit_device: None, magisk_random_seed: None, ignore_magisk_warnings: false, ignore_prepatched_compat: 0, skip_recovery_ota_cert: true, dsu: false, clear_vbmeta_flags: false, zip_mode: Streaming, boot_partition: None }) }), log_level: Level(Trace), log_format: Short } 0.000s WARN Not inserting OTA cert into recovery image; sideloading further updates may fail 0.001s INFO zip{entry="META-INF/com/android/otacert"}: Replacing zip entry: META-INF/com/android/otacert 0.001s INFO zip{entry="care_map.txt"}: Copying zip entry: care_map.txt 0.001s INFO zip{entry="checksoc.txt"}: Copying zip entry: checksoc.txt 0.001s INFO zip{entry="compatibility.zip"}: Copying zip entry: compatibility.zip 0.001s INFO zip{entry="payload.bin"}: Patching zip entry: payload.bin 0.002s INFO zip{entry="payload.bin"}:image{name="system"}: Extracting from original payload: system 1.952s INFO zip{entry="payload.bin"}:image{name="boot"}: Extracting from original payload: boot 1.999s INFO zip{entry="payload.bin"}:image{name="vbmeta"}: Extracting from original payload: vbmeta 2.000s INFO zip{entry="payload.bin"}: Candidate boot images: boot 2.337s ERROR Failed to patch OTA zip

Caused by: 0: Failed to patch payload: payload.bin 1: Failed to patch boot images: boot 2: Boot image error 3: Unknown boot image format leon@cartman:~/Downloads/avbroot$

chenxiaolong commented 3 days ago

Ah shoot, yeah, it was still loading boot images even when there was nothing to patch. ce87757fd1041fc4af8facee235e6211424241dd should fix that. New test build: https://github.com/chenxiaolong/avbroot/actions/runs/11686270136?pr=367

lkernan commented 2 days ago

Thanks, that got a lot further.
Does that error mean I messed up the keys somewhere?

leon@cartman:~/Downloads/avbroot$ ./avbroot ota patch --input usb_ota_update.zip --key-ota testkey.x509.key --key-avb testkey.x509.key --cert-ota testkey.x509.crt --rootless --skip-recovery-ota-cert 0.000s WARN Not inserting OTA cert into recovery image; sideloading further updates may fail 0.001s INFO Replacing zip entry: META-INF/com/android/otacert 0.001s INFO Copying zip entry: care_map.txt 0.001s INFO Copying zip entry: checksoc.txt 0.001s INFO Copying zip entry: compatibility.zip 0.001s INFO Patching zip entry: payload.bin 0.001s INFO Extracting from original payload: vbmeta 0.002s INFO Extracting from original payload: system 1.880s INFO Extracting from original payload: boot 1.926s INFO Candidate boot images: boot 1.930s INFO Patching system image: system 4.566s INFO Patched otacerts.zip offsets in system: [1474662400..1474663473] 4.566s INFO Patching vbmeta images: vbmeta 4.900s ERROR Failed to patch OTA zip

Caused by: 0: Failed to patch payload: payload.bin 1: RSA public key exponent not supported: 3

chenxiaolong commented 2 days ago

Hmm, yeah, it looks like testkey.x509.key is definitely not the AVB test key they originally used. The AVB 2.0 public key file format physically can't store public keys with an exponent of 3.

I would suggest trying this to determine which AVB test key they used (assuming that they did):

  1. Extract vbmeta.img from the OTA

  2. Copy the public key used to sign vbmeta.img:

    avbroot avb info -i vbmeta.img

    (The field is AvbInfo -> header -> public_key)

  3. Decode the public key from hex to binary:

    echo '<public_key value>' | xxd -r -p > avb_pkmd.bin
  4. Convert from the AVB 2.0 format to the standard PKCS8 format:

    avbroot key decode-avb -k avb_pkmd.bin -o avb_public.key
  5. Show the modulus value:

    openssl rsa -pubin -in avb_public.key -noout -text
  6. Download each of the AVB test keys (testkey_rsa{2048,4096,8192}.pem) and see if the modulus in:

    openssl rsa -in <test key> -noout -text

    matches the public key you extracted.

lkernan commented 1 day ago

Well I haven't tried using the result yet, but looking good!

avbroot ota patch --input usb_ota_update.zip --key-ota testkey.x509.key --key-avb testkey_rsa2048.key --cert-ota ota.cert --rootless --skip-recovery-ota-cert

←[2m 0.003s←[0m ←[33m WARN←[0m Not inserting OTA cert into recovery image; sideloading further updates may fail ←[2m 0.035s←[0m ←[32m INFO←[0m Replacing zip entry: META-INF/com/android/otacert ←[2m 0.036s←[0m ←[32m INFO←[0m Copying zip entry: care_map.txt ←[2m 0.036s←[0m ←[32m INFO←[0m Copying zip entry: checksoc.txt ←[2m 0.036s←[0m ←[32m INFO←[0m Copying zip entry: compatibility.zip ←[2m 0.037s←[0m ←[32m INFO←[0m Patching zip entry: payload.bin ←[2m 0.039s←[0m ←[32m INFO←[0m Extracting from original payload: system ←[2m 30.722s←[0m ←[32m INFO←[0m Extracting from original payload: boot ←[2m 31.199s←[0m ←[32m INFO←[0m Extracting from original payload: vbmeta ←[2m 31.202s←[0m ←[32m INFO←[0m Candidate boot images: boot ←[2m 31.208s←[0m ←[32m INFO←[0m Patching system image: system ←[2m 49.066s←[0m ←[32m INFO←[0m Patched otacerts.zip offsets in system: [1474662400..1474663473] ←[2m 49.066s←[0m ←[32m INFO←[0m Patching vbmeta images: vbmeta ←[2m 49.073s←[0m ←[32m INFO←[0m Compressing partial image: system: [1474662400..1474663473, 2641915904..2683782144, 2684354496..2684354560] ←[2m 56.079s←[0m ←[32m INFO←[0m Compressing full image: vbmeta ←[2m 56.081s←[0m ←[32m INFO←[0m Generating new OTA payload ←[2m 58.961s←[0m ←[32m INFO←[0m Patching zip entry: payload_properties.txt ←[2m 58.961s←[0m ←[32m INFO←[0m Generating new OTA metadata ←[2m 58.965s←[0m ←[32m INFO←[0m Verifying metadata offsets ←[2m 58.970s←[0m ←[32m INFO←[0m Successfully patched OTA

lkernan commented 1 day ago

I'm not sure if I've made another mistake but the system doesn't like the update I generated.
I'm getting the error: Bad payload format -- invalid delta magic.

That was after generating an image like above, except I'd extracted system.img and modified it first.

avbroot ota patch --input usb_ota_update.zip --key-ota testkey.x509.key --key-avb testkey_rsa2048.key --cert-ota testkey.x509.cert --rootless --skip-recovery-ota-cert --replace system system.img

←[2m 0.000s←[0m ←[33m WARN←[0m Not inserting OTA cert into recovery image; sideloading further updates may fail ←[2m 0.004s←[0m ←[32m INFO←[0m Replacing zip entry: META-INF/com/android/otacert ←[2m 0.005s←[0m ←[32m INFO←[0m Copying zip entry: care_map.txt ←[2m 0.005s←[0m ←[32m INFO←[0m Copying zip entry: checksoc.txt ←[2m 0.005s←[0m ←[32m INFO←[0m Copying zip entry: compatibility.zip ←[2m 0.006s←[0m ←[32m INFO←[0m Patching zip entry: payload.bin ←[2m 0.007s←[0m ←[32m INFO←[0m Extracting from original payload: vbmeta ←[2m 0.011s←[0m ←[32m INFO←[0m Opening external image: system: "system.img" ←[2m 0.011s←[0m ←[32m INFO←[0m Extracting from original payload: boot ←[2m 0.331s←[0m ←[32m INFO←[0m Candidate boot images: boot ←[2m 0.337s←[0m ←[32m INFO←[0m Patching system image: system ←[2m 33.200s←[0m ←[32m INFO←[0m Patched otacerts.zip offsets in system: [1474662400..1474663473] ←[2m 33.200s←[0m ←[32m INFO←[0m Patching vbmeta images: vbmeta ←[2m 33.208s←[0m ←[32m INFO←[0m Compressing full image: vbmeta ←[2m 33.210s←[0m ←[32m INFO←[0m Compressing full image: system ←[2m121.090s←[0m ←[32m INFO←[0m Generating new OTA payload ←[2m125.008s←[0m ←[32m INFO←[0m Patching zip entry: payload_properties.txt ←[2m125.009s←[0m ←[32m INFO←[0m Generating new OTA metadata ←[2m125.015s←[0m ←[32m INFO←[0m Verifying metadata offsets ←[2m125.020s←[0m ←[32m INFO←[0m Successfully patched OTA

lkernan commented 1 day ago

Nevermind, I just saw issue #328 which had the same problem. Added the --zip-mode seekable and the car accepted the update.

It processed the update but it looks like the AB update did it's job and booted the old one. Will have to dig into that a little more now.

chenxiaolong commented 23 hours ago

Just to double check: when system.img was edited, was it re-signed? (eg. doing avbroot avb unpack -i system.img -> edit raw.img -> avbroot avb pack -o system.img -k testkey_rsa2048.key)

You can also verify with avbroot ota verify -i <name>.patched.

lkernan commented 18 hours ago

I did the unpack / edit raw.img / repack but I didn't add the -k testkey_rsa2048.key Gave it a try now and it didn't make any difference.

avbroot ota verify doesn't work, it stops as soon as it hits the unknown boot image format.

chenxiaolong commented 17 hours ago

Ah okay, if avbroot avb pack didn't fail without -k testkey_rsa2048.key, it means system.img isn't signed (instead, its checksum is stored in vbmeta.img, which is signed).

avbroot ota verify doesn't work, it stops as soon as it hits the unknown boot image format.

Crap, yeah, I'll need to add a flag to skip the otacerts check there.

lkernan commented 7 hours ago

I did a test with the new version: avbroot ota verify --skip-recovery-ota-cert --input usb_ota_update.zip ←[2m 0.000s←[0m ←[32m INFO←[0m Verifying whole-file signature ←[2m 2.012s←[0m ←[31mERROR←[0m Zip error

Caused by: specified file not found in archive

the file contains the same as usual: META-INF folder care_map.txt checksoc.txt compatibility.zip payload.bin payload_properties.txt

If it helps, you can get a copy of the ota zip file on Google Drive: https://drive.google.com/file/d/1b8cZUbDz7s_AiolRdLy5s5GEpyAaRG4X/view