chenxiaolong / avbroot

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

Patching fails for last Pixel 3a stock OTA image #274

Closed Dylan-Slogrove closed 1 month ago

Dylan-Slogrove commented 2 months ago

Image obtained from here, last sargo build as per https://developers.google.com/android/ota#sargo

Using avbroot-3.1.1-x86_64-unknown-linux-gnu

Log:

  0.000s DEBUG cli=Cli { command: Ota(OtaCli { command: Patch(PatchCli { input: "sargo-ota-sp2a.220505.008-2037245c.zip", output: None, key_avb: "secrets/avb.key", key_ota: "secrets/ota.key", cert_ota: "secrets/ota.crt", pass_avb_env_var: None, pass_avb_file: None, pass_ota_env_var: None, pass_ota_file: 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, clear_vbmeta_flags: false, boot_partition: None }) }), log_level: Trace, log_format: Short }
  0.075s  INFO zip{entry="META-INF/com/android/otacert"}: Replacing zip entry: META-INF/com/android/otacert
  0.075s  INFO zip{entry="apex_info.pb"}: Copying zip entry: apex_info.pb
  0.075s  INFO zip{entry="care_map.pb"}: Copying zip entry: care_map.pb
  0.075s  INFO zip{entry="payload.bin"}: Patching zip entry: payload.bin
  0.078s  INFO zip{entry="payload.bin"}:image{name="boot"}: Extracting from original payload: boot
  0.601s  INFO zip{entry="payload.bin"}:image{name="vbmeta"}: Extracting from original payload: vbmeta
  0.601s  INFO zip{entry="payload.bin"}:image{name="system"}: Extracting from original payload: system
 21.337s  INFO zip{entry="payload.bin"}: Patching boot images: boot
 21.407s TRACE zip{entry="payload.bin"}:image{name="boot"}: Loaded 67108864 byte boot image: boot
 21.529s TRACE zip{entry="payload.bin"}:patcher{name="OtaCertPatcher"}: Loaded Gzip ramdisk with 463 entries
 21.530s DEBUG zip{entry="payload.bin"}:patcher{name="OtaCertPatcher"}: Found patcher targets: ["boot"]
 21.530s DEBUG zip{entry="payload.bin"}: All patcher targets: [["boot"]]
 21.530s TRACE zip{entry="payload.bin"}:patcher{name="OtaCertPatcher"}: Generated new 2273 byte otacerts.zip
 21.640s TRACE zip{entry="payload.bin"}:patcher{name="OtaCertPatcher"}: Loaded Gzip ramdisk with 463 entries
 22.811s TRACE zip{entry="payload.bin"}:patcher{name="OtaCertPatcher"}: Wrote Gzip ramdisk with 463 entries
 22.969s  INFO zip{entry="payload.bin"}:image{name="system"}: Patching system image: system
 23.166s ERROR Failed to patch OTA zip

Caused by:
    0: Failed to patch payload: payload.bin
    1: Failed to patch system image: system
    2: AVB error
    3: Invalid VBMeta header magic: [0, 0, 0, 0]

Unfortunately the log doesn't give me anything further to investigate myself

chenxiaolong commented 2 months ago

This was an interesting one. I've been looking into this the past couple hours.

Over the years, Google has used some different partition layouts on Pixel devices. I drew a diagram to illustrate the problem:

image

Prior to the Pixel 3, devices had separate partitions for everything. The OTAs contained individual images that were directly flashed to the partitions.

After the Pixel 3, devices have a single super partition and dynamic partitions are created inside. When installing an OTA, Android will create the necessary dynamic partitions and then directly flash them using the individual images in the OTA.

However, with the Pixel 3, the device initially shipped with separate partitions and Google later switched to using dynamic partitions in an Android update. Since repartition a device is very risky, they instead took the existing separate system and vendor partitions and treat them as a combined "fake" super partition. They call this layout "retrofitted dynamic partitions".

Since the OTAs distributed on Google's website are full OTAs, they need to work in every scenario. They need to be installable no matter if the device previously had the old or new partition layout. To handle that, instead of shipping individual images in the OTA, Google is shipping raw partition images to convert the device to the new "retrofitted" layout.

The error you get when running avbroot is a result of this. Unfortunately, I don't think it's feasible for me to add support for these Pixel 3 OTAs. avbroot is very much designed for "normal" OTAs that contain individual images. It would take a significant amount of work to support Pixel 3 OTAs.


If you're really interested in using avbroot, I think this incredibly hacky method would work: The goal is to have a "normal" OTA where partition images are stored individually (not combined for the "retrofit" layout). We can make one by combining several sources: * Stock OTA: Contains individual images for everything except `product`/`system`/`system_ext`/`vendor`. * Stock factory zip: Contains individual images for `product`/`system`/`system_ext`/`vendor`. * Custom ROM OTA: Used only for the OTA file structure. The contents are discarded and replaced with the stock images. 1. Download a custom ROM where the OTA contains individual images. LineageOS is a good choice: https://download.lineageos.org/devices/sargo/builds. 2. Download both the stock OTA (`sargo-ota-sp2a.220505.008-2037245c.zip`) and factory zip (`sargo-sp2a.220505.008-factory-071e368a.zip`). 3. Extract the stock OTA. ```bash avbroot ota extract -i sargo-ota-sp2a.220505.008-2037245c.zip -d stock_ota -a ``` 4. Extract the images from the stock factory zip. ```bash unzip sargo-sp2a.220505.008-factory-071e368a.zip cd sargo-sp2a.220505.008 unzip image-sargo-sp2a.220505.008.zip ``` 5. Using the [`simg2img` tool](https://github.com/anestisb/android-simg2img), convert the factory images from sparse images to regular images. ```bash simg2img product.img product.img.raw simg2img system.img system.img.raw simg2img system_ext.img system_ext.img.raw simg2img vendor.img vendor.img.raw cd .. ``` 6. Extract `payload.bin` from the LineageOS OTA and put it into a copy of the stock OTA. ```bash unzip lineage-21.0-20240420-nightly-sargo-signed.zip payload.bin cp sargo-ota-sp2a.220505.008-2037245c.zip sargo-ota-sp2a.220505.008-2037245c.MODIFIED.zip zip -0 sargo-ota-sp2a.220505.008-2037245c.MODIFIED.zip payload.bin ``` 7. Patch the file. 100% of the images from the custom ROM are replaced with stock images. ```bash avbroot ota patch \ --input sargo-ota-sp2a.220505.008-2037245c.MODIFIED.zip \ --replace abl stock_ota/abl.img \ --replace aop stock_ota/aop.img \ --replace boot stock_ota/boot.img \ --replace cmnlib stock_ota/cmnlib.img \ --replace cmnlib64 stock_ota/cmnlib64.img \ --replace devcfg stock_ota/devcfg.img \ --replace dtbo stock_ota/dtbo.img \ --replace hyp stock_ota/hyp.img \ --replace keymaster stock_ota/keymaster.img \ --replace modem stock_ota/modem.img \ --replace qupfw stock_ota/qupfw.img \ --replace tz stock_ota/tz.img \ --replace vbmeta stock_ota/vbmeta.img \ --replace xbl stock_ota/xbl.img \ --replace xbl_config stock_ota/xbl_config.img \ --replace product sargo-sp2a.220505.008/product.img.raw \ --replace system sargo-sp2a.220505.008/system.img.raw \ --replace system_ext sargo-sp2a.220505.008/system_ext.img.raw \ --replace vendor sargo-sp2a.220505.008/vendor.img.raw \ ```