chenxiaolong / avbroot

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

Failure Signing OTA #328

Closed aaronfhamilton closed 1 month ago

aaronfhamilton commented 1 month ago

I'm getting the following error when trying to sign an OTA image on 3.4.1. Any idea how to resolve this?

  2024-07-31T08:42:51.694436Z DEBUG avbroot::cli::args: cli: Cli { command: Ota(OtaCli { command: Patch(PatchCli { input: "sdm660_update.zip", output: None, key_avb: "avb.pk8.key", key_ota: "ota.pk8.pem", cert_ota: "testkey.x509.pem", 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, dsu: false, clear_vbmeta_flags: false, boot_partition: None }) }), log_level: Debug, log_format: Long }
    at avbroot/src/cli/args.rs:156

  2024-07-31T08:42:51.773696Z  INFO avbroot::cli::ota: Replacing zip entry: META-INF/com/android/otacert
    at avbroot/src/cli/ota.rs:1013
    in avbroot::cli::ota::zip with entry: "META-INF/com/android/otacert"

  2024-07-31T08:42:51.780921Z  INFO avbroot::cli::ota: Copying zip entry: apex_info.pb
    at avbroot/src/cli/ota.rs:1059
    in avbroot::cli::ota::zip with entry: "apex_info.pb"

  2024-07-31T08:42:51.781203Z  INFO avbroot::cli::ota: Copying zip entry: care_map.pb
    at avbroot/src/cli/ota.rs:1059
    in avbroot::cli::ota::zip with entry: "care_map.pb"

  2024-07-31T08:42:51.781392Z  INFO avbroot::cli::ota: Copying zip entry: custom.txt
    at avbroot/src/cli/ota.rs:1059
    in avbroot::cli::ota::zip with entry: "custom.txt"

  2024-07-31T08:42:51.781721Z  INFO avbroot::cli::ota: Patching zip entry: payload.bin
    at avbroot/src/cli/ota.rs:1019
    in avbroot::cli::ota::zip with entry: "payload.bin"

  2024-07-31T08:42:51.857980Z  INFO avbroot::cli::ota: Extracting from original payload: system
    at avbroot/src/cli/ota.rs:170
    in avbroot::cli::ota::image with name: "system"
    in avbroot::cli::ota::zip with entry: "payload.bin"

  2024-07-31T08:42:51.900864Z ERROR avbroot: Failed to patch OTA zip

Caused by:
    0: Failed to patch payload: payload.bin
    1: Failed to create temp file for: system
    2: No such file or directory (os error 2)
    at avbroot/src/main.rs:31
pascallj commented 1 month ago

This seems awful similar to #325. Could you verify what version of avbroot you are running on what OS?

aaronfhamilton commented 1 month ago

Ah, yes using export TMPDIR=/tmp seemed to get past that error. Now I'm getting a "No compatible boot image found for OtaCertPatcher"

I'm guessing I should be using avbroot-3.41.-x86_64-unknown-linux-gnu.zip?

pascallj commented 1 month ago

I'm guessing I should be using avbroot-3.41.-x86_64-unknown-linux-gnu.zip?

I think that would be better, but I don't think that is the cause of your new issue. What device are you trying to run avbroot for?

aaronfhamilton commented 1 month ago

Generic AI Box from Carlinkit. This is the build.prop from the extracted system image:

####################################
# from generate-common-build-props
# These properties identify this partition image.
####################################
ro.product.system.brand=qti
ro.product.system.device=sdm660_64
ro.product.system.manufacturer=QUALCOMM
ro.product.system.model=sdm660 for arm64
ro.product.system.name=sdm660_64
ro.system.product.cpu.abilist=arm64-v8a,armeabi-v7a,armeabi
ro.system.product.cpu.abilist32=armeabi-v7a,armeabi
ro.system.product.cpu.abilist64=arm64-v8a
ro.system.build.date=Tue May  7 17:10:10 CST 2024
ro.system.build.date.utc=1715073010
ro.system.build.fingerprint=qti/sdm660_64/sdm660_64:13/S10A_123/jiangds05071710:user/release-keys
ro.system.build.id=S10A_123
ro.system.build.tags=release-keys
ro.system.build.type=user
ro.system.build.version.incremental=eng.jiangd.20240507.171242
ro.system.build.version.release=13
ro.system.build.version.release_or_codename=13
ro.system.build.version.sdk=33
####################################
# from out/target/product/sdm660_64/obj/PACKAGING/system_build_prop_intermediates/buildinfo.prop
####################################
# begin build properties
# autogenerated by buildinfo.sh
ro.build.id=S10A_123
ro.build.keys=release-keys
ro.build.display.id=SC218-T6.00.05
ro.build.version.incremental=eng.jiangd.20240507.171242
ro.build.version.sdk=33
ro.boot.oem.pkg=X13-NA-00-00
ro.build.version.preview_sdk=0
ro.build.version.preview_sdk_fingerprint=REL
ro.build.version.codename=REL
ro.build.version.all_codenames=REL
ro.build.version.known_codenames=Base,Base11,Cupcake,Donut,Eclair,Eclair01,EclairMr1,Froyo,Gingerbread,GingerbreadMr1,Honeycomb,HoneycombMr1,HoneycombMr2,IceCreamSandwich,IceCreamSandwichMr1,JellyBean,JellyBeanMr1,JellyBeanMr2,Kitkat,KitkatWatch,Lollipop,LollipopMr1,M,N,NMr1,O,OMr1,P,Q,R,S,Sv2,Tiramisu
ro.build.version.release=13
ro.build.version.release_or_codename=13
ro.build.version.release_or_preview_display=13
ro.build.version.security_patch=2022-12-05
ro.build.version.base_os=
ro.build.version.min_supported_target_sdk=23
ro.build.date=Tue May  7 17:10:10 CST 2024
ro.build.date.utc=1715073010
ro.build.type=user
ro.build.user=jiangds
ro.build.host=hello-PowerEdge-T440
ro.build.tags=release-keys
ro.build.flavor=sdm660_64-user
# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,
# use ro.product.cpu.abilist instead.
ro.product.cpu.abi=arm64-v8a
ro.wifi.channels=
# Do not try to parse thumbprint
# set ro.build.oem.name chelianyi-led
ro.board.reverse.custom=chelianyi-led
ro.build.oem.name=chelianyi-led
ro.build.box.hardware.id=1
persist.sys.oem.brand=Tbox Ambient
persist.sys.show.loading=true
ro.sys.has.navibar=true
ro.build.version.release=13
ro.product.locale=en-US
persist.hotspot.wifi.not.only=0
# begin fota properties
ro.fota.platform=SC218
ro.fota.type=box
ro.fota.oem=Yunlian-Y
ro.fota.device=CPC200-Tbox-Ambient
ro.fota.version=X13-SC218-58 A13 2024-05-07 17:07
ro.fota.product.id=1697705429
ro.fota.secret.id=5e6ac22c30564532906ecb829d8ecd8a
# end fota properties
# end build properties
####################################
# from device/qcom/sdm660_64/system.prop
####################################
#
# system.prop for sdm660
#
#rild.libpath=/system/lib/libreference-ril.so
rild.libpath=/system/vendor/lib64/libril-qc-qmi-1.so
#rild.libargs=-d /dev/smd0
persist.rild.nitz_plmn=
persist.rild.nitz_long_ons_0=
persist.rild.nitz_long_ons_1=
persist.rild.nitz_long_ons_2=
persist.rild.nitz_long_ons_3=
persist.rild.nitz_short_ons_0=
persist.rild.nitz_short_ons_1=
persist.rild.nitz_short_ons_2=
persist.rild.nitz_short_ons_3=
ril.subscription.types=NV,RUIM
DEVICE_PROVISIONED=1
#
# Set network mode to (T/L/G/W/1X/EVDO, T/G/W/L) for 7+5 mode device on DSDS mode
#
ro.telephony.default_network=31,31
debug.sf.enable_hwc_vds=1
debug.sf.hw=1
debug.sf.latch_unsignaled=1
debug.gralloc.enable_fb_ubwc=1
dalvik.vm.heapsize=36m
dev.pm.dyn_samplingrate=1
ro.config.media_vol_default=15
ro.config.vc_call_vol_default=7
ro.config.alarm_vol_default=15
ro.config.system_vol_default=15
persist.demo.hdmirotationlock=false
#Disable Skip Validate
sdm.debug.disable_skip_validate=1
#Property to enable display default color mode
vendor.display.enable_default_color_mode=1
# Display Properties as per treble compliance
vendor.gralloc.enable_fb_ubwc=1
vendor.display.disable_skip_validate=1
#ro.hdmi.enable=true
#
# system props for the cne module
#
persist.vendor.cne.feature=1
#system props for the MM modules
media.stagefright.enable-player=true
media.stagefright.enable-http=true
media.stagefright.enable-aac=true
media.stagefright.enable-qcp=true
media.stagefright.enable-scan=true
mmp.enable.3g2=true
media.aac_51_output_enabled=true
media.settings.xml=/vendor/etc/media_profiles_vendor.xml
#codecs:(PARSER_)AAC AC3 AMR_NB AMR_WB ASF AVI DTS FLV 3GP 3G2 MKV MP2PS MP2TS MP3 OGG QCP WAV FLAC AIFF APE DSD
vendor.mm.enable.qcom_parser=13631487
persist.mm.enable.prefetch=true
#prefer HW codec over SW for thumbnail
media.stagefright.thumbnail.prefer_hw_codecs=true
#property to enable narrow search range for video encoding
vidc.enc.target_support_bframe=1
vendor.vidc.enc.disable_bframes=1
vendor.vidc.dec.enable.downscalar=1
# enable PQ feature by default
vendor.vidc.enc.disable.pq=false
# Additional buffers shared between Camera and Video
vidc.enc.dcvs.extra-buff-count=2
#
# system props for the data modules
#
ro.vendor.use_data_netmgrd=true
persist.vendor.data.mode=concurrent
#system props for time-services
persist.timed.enable=true
# System property for cabl
ro.qualcomm.cabl=2
ro.vendor.display.cabl=2
#
# System props for telephony
# System prop to turn on CdmaLTEPhone always
telephony.lteOnCdmaDevice=1
#Simulate sdcard on /data/media
#
persist.fuse_sdcard=true
#
#snapdragon value add features
#
#minimum duration for offload playback in secs
audio.offload.min.duration.secs=30
#enable offload audio video playback by default
audio.offload.video=true
#enable music through deep buffer
audio.deep_buffer.media=true
#set AudioFlinger client heap size
ro.af.client_heap_size_kbyte=7168
#system prop for RmNet Data
persist.data.df.dev_name=rmnet_usb0
#
# system property determining camera HAL to be used for a Video call
#
# 1 is camera1
# 2 or anything else is camera2
persist.radio.VT_CAM_INTERFACE=2
#property to enable user to access Google WFD settings
persist.debug.wfd.enable=1
#Enable stm-events
persist.debug.coresight.config=stm-events
##property to choose between virtual/external wfd display
persist.sys.wfd.virtual=0
# system prop for NFC DT
ro.nfc.port=I2C
ro.build.selinux=1
#hwui properties
ro.hwui.texture_cache_size=72
ro.hwui.layer_cache_size=48
ro.hwui.r_buffer_cache_size=8
ro.hwui.path_cache_size=32
ro.hwui.gradient_cache_size=1
ro.hwui.drop_shadow_cache_size=6
ro.hwui.texture_cache_flushrate=0.4
ro.hwui.text_small_cache_width=1024
ro.hwui.text_small_cache_height=1024
ro.hwui.text_large_cache_width=2048
ro.hwui.text_large_cache_height=2048
#Bringup properties
persist.vendor.radio.atfwd.start=true
#property to enable VDS WFD solution
persist.hwc.enable_vds=1
#Settings to enable sensors
#Device Orientation sensor
ro.vendor.sensors.dev_ori=true
#Persistent Motion Detector
ro.vendor.sensors.pmd=true
#Stationary Detector
ro.vendor.sensors.sta_detect=true
#Motion Detector
ro.vendor.sensors.mot_detect=true
#Expose aux camera for below packages
vendor.camera.aux.packagelist=org.codeaurora.snapcam
#Whitelisting the below packages
persist.vendor.camera.privapp.list=org.codeaurora.snapcam
persist.camera.privapp.list=org.codeaurora.snapcam
#disable UBWC for camera
persist.vendor.camera.preview.ubwc=0
#set maximum supported adapter voltage
persist.chg.max_volt_mv=9000
#system prop for Bluetooth
ro.bluetooth.library_name=libbluetooth_qti.so
# Property for backup NTP Server
persist.backup.ntpServer="0.pool.ntp.org"
# enable IZat OptInApp overlay
persist.vendor.overlay.izat.optin=rro
# Add Airplane attribute by Guoyanbo for JIRA MC0310-468
sys.sleep.test.ready=false
ro.boot.ftmode=true
#Set reading BT MAC from NV JIRA:MC0310-382
persist.vendor.bluetooth.modem_nv_support=true
####################################
# from variable ADDITIONAL_SYSTEM_PROPERTIES
####################################
ro.treble.enabled=true
ro.actionable_compatible_property.enabled=true
ro.postinstall.fstab.prefix=/system
ro.secure=1
security.perf_harden=1
ro.adb.secure=0
ro.allow.mock.location=0
ro.debuggable=0
dalvik.vm.lockprof.threshold=500
net.bt.name=Android
ro.vendor.qti.va_aosp.support=1
persist.vendor.ssr.restart_level=ALL_ENABLE
####################################
# from variable PRODUCT_SYSTEM_PROPERTIES
####################################
debug.atrace.tags.enableflags=0
persist.traced.enable=1
dalvik.vm.image-dex2oat-Xms=64m
dalvik.vm.image-dex2oat-Xmx=64m
dalvik.vm.dex2oat-Xms=64m
dalvik.vm.dex2oat-Xmx=512m
dalvik.vm.usejit=true
dalvik.vm.usejitprofiles=true
dalvik.vm.dexopt.secondary=true
dalvik.vm.dexopt.thermal-cutoff=2
dalvik.vm.appimageformat=lz4
ro.dalvik.vm.native.bridge=0
pm.dexopt.first-boot=verify
pm.dexopt.boot-after-ota=verify
pm.dexopt.post-boot=extract
pm.dexopt.install=speed-profile
pm.dexopt.install-fast=skip
pm.dexopt.install-bulk=speed-profile
pm.dexopt.install-bulk-secondary=verify
pm.dexopt.install-bulk-downgraded=verify
pm.dexopt.install-bulk-secondary-downgraded=extract
pm.dexopt.bg-dexopt=speed-profile
pm.dexopt.ab-ota=speed-profile
pm.dexopt.inactive=verify
pm.dexopt.cmdline=verify
pm.dexopt.shared=speed
dalvik.vm.dex2oat-resolve-startup-strings=true
dalvik.vm.dex2oat-max-image-block-size=524288
dalvik.vm.minidebuginfo=true
dalvik.vm.dex2oat-minidebuginfo=true
dalvik.vm.madvise.vdexfile.size=104857600
dalvik.vm.madvise.odexfile.size=104857600
dalvik.vm.madvise.artfile.size=4294967295
####################################
# from variable PRODUCT_SYSTEM_DEFAULT_PROPERTIES
####################################
# end of file
chenxiaolong commented 1 month ago

Any chance you know of an alternate place to download the OTA?

It looks like they throttle downloads from https://www.carlinkit.com/download.html to exactly 200Kbps for me.

(If not, no worries! I can take a look tomorrow when the download finishes.)

aaronfhamilton commented 1 month ago

Try https://drive.google.com/file/d/12Gsme8fLP2_c3yTFn5EsI6JvOlo0O3c0/view?usp=drive_link

chenxiaolong commented 1 month ago

Thanks, got it! 30 seconds much better than a few hours. Taking a look now.

chenxiaolong commented 1 month ago

The issue is that the OTA doesn't contain a recovery image. Without that, avbroot can't patch the OTA verification certificate stored in it, so sideloading OTAs signed by your own keys wouldn't be possible.

Since the OTA is incomplete, I don't think there's much you can do, unfortunately.

aaronfhamilton commented 1 month ago

Does it possibly use boot and system_ext (or something else) to make the recovery image?

Here is the recovery partition as read using QFIL after applying the update:

https://drive.google.com/file/d/14_zigxxg2mdyk7HFo2DvDP9XzYN_bglB/view?usp=drive_link

chenxiaolong commented 1 month ago

Thanks for uploading the recovery image. Is it a completely unmodified image?

If it's unmodified and recovery mode actually boots while the bootloader is locked, then I think signature verification is broken on your device. You wouldn't gain any additional security by using avbroot vs. just leaving the bootloader unlocked.


Details:

The AVB metadata of recovery itself lists this version number and checksum:

$ footer=$(grep -boa AVBf recovery.bin | cut -d: -f1)
$ cp recovery.bin recovery.bin.2
$ truncate -s $((footer + 64)) recovery.bin.2
$ avbroot avb info -i recovery.bin.2
...
                    hash_algorithm: "sha256",
                    partition_name: "recovery",
                    salt: "55b0f1b9a3f090af8c1758331be5b691432626518de7a1e3924851149dc9c99e",
                    root_digest: "466b7938a4f780bcc455985da976cf278e94c8f32df8e68c3e4e4e7355353f59",
...
                    key: "com.android.build.recovery.fingerprint",
                    value: "qti/sdm660_64/sdm660_64:13/S10A_123/zhangzy07121100:user/release-keys",
...

(I had to chop of a bunch of excess 0's at the end of the file. If those weren't added by QFIL and the partition is actually like that, then it's yet another way that things are broken on this device.)

However, the AVB metadata of vbmeta from the OTA lists a different version number and checksum for recovery:

$ avbroot ota extract -i sdm660_update.zip -d extracted -a
$ avbroot avb info -i extracted/vbmeta.img
...
                    key: "com.android.build.recovery.fingerprint",
                    value: "qti/sdm660_64/sdm660_64:13/S10A_123/jiangds05071710:user/release-keys",
...
                    hash_algorithm: "sha256",
                    partition_name: "recovery",
                    salt: "8ad31065a5a845c31c11b1bb47c41d2f134403105816578af3d21ce036289a36",
                    root_digest: "156518a41536f193ec924f67f3a17fce71afb18a5e088325bfd93280b45d34fa",
...

vbmeta is what the bootloader actually uses to verify the signatures of all the partitions. This shouldn't be able to boot.


Does it possibly use boot and system_ext (or something else) to make the recovery image?

It doesn't look like it. I searched for various strings from your recovery image, like zhangzy07121100, and they don't appear in any of the other partitions.

aaronfhamilton commented 1 month ago

As far as I'm aware, it should be unmodified. Here is a separate recovery image that was provided by the vendor for QFIL recovery: https://drive.google.com/file/d/14epN_MlxeS2t0QTb1UVEmo_NChECPJn8/view?usp=drive_link

Not sure if related at all, but the device does have funky behavior where it states "device not activated" after flashing with QFIL until it gets an internet connection.

chenxiaolong commented 1 month ago

Ah, yep, that file no longer has the extra 0's at the end of the file, but is otherwise identical to the previous recovery image you uploaded.


I took a further look and it definitely seems like this OEM doesn't care about security at all.

These private keys are all publicly available and should never be used. Given that and the fact that the recovery image doesn't match the checksums in vbmeta, I highly doubt that the bootloader is properly implemented and verifying anything.


Not sure if related at all, but the device does have funky behavior where it states "device not activated" after flashing with QFIL until it gets an internet connection.

This comes from /system/app/CarDataManager/CarDataManager.apk. I didn't dig deeply into it, but I have no idea why QFIL would have any impact. Anyway, I think you can bypass it and avoid sending data to their servers by running this as root:

setprop persist.chelianyi.activate.state 1
aaronfhamilton commented 1 month ago

Yes, most the Chinese CarPlay based "AI Box" devices all use the keys from the Google repos. Nice find on the CarDataManager.apk, especially considering I just posted it yesterday.

Could avbroot be tricked into working I placed the recovery.img into the build/payload folder and modified manifest.json to include "recovery" in "partsToUpdate" field?

chenxiaolong commented 1 month ago

Could avbroot be tricked into working I placed the recovery.img into the build/payload folder and modified manifest.json to include "recovery" in "partsToUpdate" field?

I'm not familiar with this manifest.json you're referring to. Can you send me a link to the tool that processes this file?

aaronfhamilton commented 1 month ago

Oops, was looking at the wrong folder. There is no manifest.json.

Is it possible the recovery partition isn't used since it's an A/B device (or tries to be), and that recovery partition is unused? I'm seeing in the Google A/B docs (https://source.android.com/docs/core/ota/ab/ab_implement#partitions), the recovery is now contained in boot.img.

chenxiaolong commented 1 month ago

The recovery program (/system/bin/recovery) could exist in boot, vendor_boot (most common nowadays), or recovery. This particular device doesn't put it in boot though.

aaronfhamilton commented 1 month ago

Does it use update_engine instead of /system/bin/recovery by chance?

chenxiaolong commented 1 month ago

update_engine is the tool that installs the contents of payload.bin into the actual partitions. Recovery mode runs that (and Android does too if the device has an A/B OTA updater app).

chenxiaolong commented 1 month ago

By the way, I'm looking to see if I can easily implement avbroot payload {pack,unpack} commands so that you can manually add your recovery.img into payload.bin before patching it with avbroot ota patch.

aaronfhamilton commented 1 month ago

What would be awesome!!

chenxiaolong commented 1 month ago

I just merged #331 and released version 3.5.0 with the change. Can you give this a try?

  1. Extract payload.bin from the OTA:

    unzip sdm660_update.zip payload.bin
  2. Unpack the payload binary:

    avbroot payload unpack -q -i payload.bin
  3. Copy your recovery.img to payload_images/recovery.img. Make sure you use the one without the extra zeros at the end of the file. You can check if it is valid by running:

    avbroot avb info -i recovery.img

    (The bad one will fail with an error.)

  4. Edit payload.toml and add an entry for recovery to the end (the order doesn't matter):

    [[manifest.partitions]]
    partition_name = "recovery"
  5. Pack a new payload binary. It doesn't matter which key you use since it'll get re-signed later anyway.

    mv payload.bin payload.bin.orig
    avbroot payload pack -q -o payload.bin -k ota.key
  6. Create a new OTA zip with the modified payload binary.

    cp sdm660_update.zip sdm660_update.with_recovery.zip
    zip -u -0 sdm660_update.with_recovery.zip payload.bin

    Two important things:

    • The payload must be stored in the zip without compression (-0).
    • This zip is not flashable! You can't use this to go back to the stock OS.
  7. Patch sdm660_update.with_recovery.zip with avbroot ota patch.

aaronfhamilton commented 1 month ago

I was able to run the avbroot commands without errors when using the unmodified contents, but if I do the following, then I get an error:

e2fsck -f system.img
resize2fs system.img 2G
e2fsck -E unshare_blocks system.img
mount -t ext4 -o loop,rw system.img ../system
# Modify system contents
umount ../system
e2fsck -f system.img
resize2fs -M system.img
e2fsck -f system.img

Pack using avbroot ...

avbroot payload pack -q -o payload.bin -k ota.key
cp sdm660_update.zip sdm660_update.new.zip
zip -u -0 sdm660_update.new.zip payload.bin

Zip command runs and indicates:

updating: payload.bin (stored 0%)

Patch command returns error:

avbroot ota patch --input sdm660_update.new.zip --key-avb avb4096.pk8 --key-ota ota.key.pem --cert-ota ota.x509.pem --rootless

  0.002s  INFO Replacing zip entry: META-INF/com/android/otacert
  0.002s  INFO Copying zip entry: apex_info.pb
  0.002s  INFO Copying zip entry: care_map.pb
  0.002s  INFO Copying zip entry: custom.txt
  0.002s  INFO Patching zip entry: payload.bin
  0.003s  INFO Extracting from original payload: system
  4.977s  INFO Extracting from original payload: boot
  5.054s  INFO Extracting from original payload: vbmeta
  5.104s  INFO Extracting from original payload: recovery
  5.208s  INFO Extracting from original payload: vbmeta_system
  5.208s  INFO Patching boot images: boot, recovery
  6.802s  INFO Patching system image: system
  6.949s 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]
aaronfhamilton commented 1 month ago

... also I tried the steps as recommended for adding the recovery.img partition (without other changes), but the device does not take the patched file. Here's the log file:

08-18 08:13:23.880 E/UpdateManager( 8131): applyPayload start 
08-18 08:13:23.888 I/update_engine( 1246): [INFO:update_attempter_android.cc(320)] Using this install plan:
08-18 08:13:23.894 I/update_engine( 1246): [INFO:install_plan.cc(80)] InstallPlan: 
08-18 08:13:23.894 I/update_engine( 1246): type: new_update
08-18 08:13:23.894 I/update_engine( 1246): version: 
08-18 08:13:23.894 I/update_engine( 1246): source_slot: B
08-18 08:13:23.894 I/update_engine( 1246): target_slot: A
08-18 08:13:23.894 I/update_engine( 1246): initial url: file:///data/update.zip
08-18 08:13:23.894 I/update_engine( 1246): hash_checks_mandatory: true
08-18 08:13:23.894 I/update_engine( 1246): powerwash_required: false
08-18 08:13:23.894 I/update_engine( 1246): switch_slot_on_reboot: true
08-18 08:13:23.894 I/update_engine( 1246): run_post_install: true
08-18 08:13:23.894 I/update_engine( 1246): is_rollback: false
08-18 08:13:23.894 I/update_engine( 1246): rollback_data_save_requested: false
08-18 08:13:23.894 I/update_engine( 1246): write_verity: true
08-18 08:13:23.894 I/update_engine( 1246): Payload: 0
08-18 08:13:23.894 I/update_engine( 1246):   urls: ()
08-18 08:13:23.894 I/update_engine( 1246):   size: 2075195198
08-18 08:13:23.894 I/update_engine( 1246):   metadata_size: 125336
08-18 08:13:23.894 I/update_engine( 1246):   metadata_signature: 
08-18 08:13:23.894 I/update_engine( 1246):   hash: 12AE5F955E21C1B2471B6A7AD93AA985A9530073D5CF9B525EA4427CC738A075
08-18 08:13:23.894 I/update_engine( 1246):   type: unknown
08-18 08:13:23.894 I/update_engine( 1246):   fingerprint: 
08-18 08:13:23.894 I/update_engine( 1246):   app_id: 
08-18 08:13:23.894 I/update_engine( 1246):   already_applied: false
08-18 08:13:23.897 I/update_engine( 1246): [INFO:postinstall_runner_action.cc(95)] postinstall mount point: /postinstall
08-18 08:13:23.900 D/UpdateManager( 8131): onStatusUpdate invoked, status=2, progress=0.00
08-18 08:13:23.900 D/OTA     ( 8131): UITYPE_UPGRADE onProgressUpdate=0.0
08-18 08:13:23.900 I/update_engine( 1246): [INFO:metrics_utils.cc(318)] Number of Reboots during current update attempt = 0
08-18 08:13:23.904 I/update_engine( 1246): [INFO:metrics_utils.cc(326)] Payload Attempt Number = 1
08-18 08:13:23.908 I/update_engine( 1246): [INFO:metrics_utils.cc(343)] Update Monotonic Timestamp Start = 1/1/1970 0:10:18 GMT
08-18 08:13:23.915 I/update_engine( 1246): [INFO:metrics_utils.cc(352)] Update Boot Timestamp Start = 1/1/1970 0:10:18 GMT
08-18 08:13:23.919 I/update_engine( 1246): [INFO:update_attempter_android.cc(821)] Clearing update complete marker.
08-18 08:13:23.925 I/update_engine( 1246): [INFO:update_attempter_android.cc(701)] Scheduling an action processor start.
08-18 08:13:23.928 E/UpdateManager( 8131): applyPayload end 
08-18 08:13:23.928 I/update_engine( 1246): [INFO:action_processor.cc(51)] ActionProcessor: starting UpdateBootFlagsAction
08-18 08:13:23.931 I/update_engine( 1246): [INFO:update_boot_flags_action.cc(36)] Already updated boot flags. Skipping.
08-18 08:13:23.933 I/update_engine( 1246): [INFO:action_processor.cc(116)] ActionProcessor: finished UpdateBootFlagsAction with code ErrorCode::kSuccess
08-18 08:13:23.933 D/UpdateManager( 8131): onStatusUpdate invoked, status=11, progress=0.00
08-18 08:13:23.934 D/OTA     ( 8131): UITYPE_UPGRADE onProgressUpdate=0.0
08-18 08:13:23.936 I/update_engine( 1246): [INFO:action_processor.cc(143)] ActionProcessor: starting CleanupPreviousUpdateAction
08-18 08:13:23.939 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(149)] Starting/resuming CleanupPreviousUpdateAction
08-18 08:13:23.942 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(189)] Boot completed, waiting on markBootSuccessful()
08-18 08:13:23.946 I/update_engine( 1246): EnsureMetadataMounted does nothing in Android mode.
08-18 08:13:23.947 W/LocSvc_ApiV02( 1075): reportSv:3448] At least one RF_LOSS is 0 in gps.conf, please configure it
08-18 08:13:23.939 I/recordH264Scree(  804): type=1400 audit(0.0:3275): avc: denied { write } for path="socket:[30797]" dev="sockfs" ino=30797 scontext=u:r:init:s0 tcontext=u:r:init:s0 tclass=tcp_socket permissive=1
08-18 08:13:23.948 E/PowerManagerService( 1349): mScreenOffTimeoutSetting=-1  nextTimeout=-1
08-18 08:13:23.952 E/PowerManagerService( 1349): mScreenOffTimeoutSetting=-1  nextTimeout=-1
08-18 08:13:23.954 E/PowerManagerService( 1349): mScreenOffTimeoutSetting=-1  nextTimeout=-1
08-18 08:13:23.949 I/cat     (  790): type=1400 audit(0.0:3276): avc: denied { write } for path="/data/.X13_Log/X13_Log/kernel_6.ini" dev="sda10" ino=6897691 scontext=u:r:toolbox:s0 tcontext=u:object_r:system_data_file:s0 tclass=file permissive=1
08-18 08:13:23.957 E/PowerManagerService( 1349): mScreenOffTimeoutSetting=-1  nextTimeout=-1
08-18 08:13:23.957 I/update_engine( 1246): Read merge statistics file failed: No such file or directory
08-18 08:13:23.959 E/PowerManagerService( 1349): mScreenOffTimeoutSetting=-1  nextTimeout=-1
08-18 08:13:23.959 E/PowerManagerService( 1349): mScreenOffTimeoutSetting=-1  nextTimeout=-1
08-18 08:13:23.966 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(261)] Waiting for any previous merge request to complete. This can take up to several minutes.
08-18 08:13:23.969 I/update_engine( 1246): CheckMergeState for snapshots returned: 0
08-18 08:13:23.972 I/update_engine( 1246): ProcessUpdateState handling state: 0
08-18 08:13:23.974 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(297)] Can't find any snapshot to merge.
08-18 08:13:23.978 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(130)] Stopping/suspending/completing CleanupPreviousUpdateAction
08-18 08:13:23.982 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(479)] Not reporting merge stats because state is None
08-18 08:13:23.984 I/update_engine( 1246): [INFO:cleanup_previous_update_action.cc(130)] Stopping/suspending/completing CleanupPreviousUpdateAction
08-18 08:13:23.987 I/update_engine( 1246): [INFO:action_processor.cc(116)] ActionProcessor: finished CleanupPreviousUpdateAction with code ErrorCode::kSuccess
08-18 08:13:23.990 I/update_engine( 1246): [INFO:action_processor.cc(143)] ActionProcessor: starting InstallPlanAction
08-18 08:13:23.992 I/update_engine( 1246): [INFO:action_processor.cc(116)] ActionProcessor: finished InstallPlanAction with code ErrorCode::kSuccess
08-18 08:13:23.996 I/update_engine( 1246): [INFO:action_processor.cc(143)] ActionProcessor: starting DownloadAction
08-18 08:13:24.002 I/update_engine( 1246): [INFO:install_plan.cc(80)] InstallPlan: 
08-18 08:13:24.002 I/update_engine( 1246): type: new_update
08-18 08:13:24.002 I/update_engine( 1246): version: 
08-18 08:13:24.002 I/update_engine( 1246): source_slot: B
08-18 08:13:24.002 I/update_engine( 1246): target_slot: A
08-18 08:13:24.002 I/update_engine( 1246): initial url: file:///data/update.zip
08-18 08:13:24.002 I/update_engine( 1246): hash_checks_mandatory: true
08-18 08:13:24.002 I/update_engine( 1246): powerwash_required: false
08-18 08:13:24.002 I/update_engine( 1246): switch_slot_on_reboot: true
08-18 08:13:24.002 I/update_engine( 1246): run_post_install: true
08-18 08:13:24.002 I/update_engine( 1246): is_rollback: false
08-18 08:13:24.002 I/update_engine( 1246): rollback_data_save_requested: false
08-18 08:13:24.002 I/update_engine( 1246): write_verity: true
08-18 08:13:24.002 I/update_engine( 1246): Payload: 0
08-18 08:13:24.002 I/update_engine( 1246):   urls: ()
08-18 08:13:24.002 I/update_engine( 1246):   size: 2075195198
08-18 08:13:24.002 I/update_engine( 1246):   metadata_size: 125336
08-18 08:13:24.002 I/update_engine( 1246):   metadata_signature: 
08-18 08:13:24.002 I/update_engine( 1246):   hash: 12AE5F955E21C1B2471B6A7AD93AA985A9530073D5CF9B525EA4427CC738A075
08-18 08:13:24.002 I/update_engine( 1246):   type: unknown
08-18 08:13:24.002 I/update_engine( 1246):   fingerprint: 
08-18 08:13:24.002 I/update_engine( 1246):   app_id: 
08-18 08:13:24.002 I/update_engine( 1246):   already_applied: false
08-18 08:13:24.005 I/update_engine( 1246): [INFO:download_action.cc(86)] Marking new slot as unbootable
08-18 08:13:24.014 D/BTCallService( 3674): mRunnable mAudioVoice.....
08-18 08:13:24.049 I/update_engine( 1246): [INFO:multi_range_http_fetcher.cc(45)] starting first transfer
08-18 08:13:24.052 I/update_engine( 1246): [INFO:multi_range_http_fetcher.cc(74)] starting transfer of range 2446+2075195198
08-18 08:13:24.039 I/update_engine( 1246): type=1400 audit(0.0:3277): avc: denied { read } for name="update.zip" dev="sda10" ino=14 scontext=u:r:update_engine:s0 tcontext=u:object_r:system_data_root_file:s0 tclass=file permissive=1
08-18 08:13:24.039 I/update_engine( 1246): type=1400 audit(0.0:3278): avc: denied { open } for path="/data/update.zip" dev="sda10" ino=14 scontext=u:r:update_engine:s0 tcontext=u:object_r:system_data_root_file:s0 tclass=file permissive=1
08-18 08:13:24.039 I/update_engine( 1246): type=1400 audit(0.0:3279): avc: denied { getattr } for path="/data/update.zip" dev="sda10" ino=14 scontext=u:r:update_engine:s0 tcontext=u:object_r:system_data_root_file:s0 tclass=file permissive=1
08-18 08:13:24.055 D/UpdateManager( 8131): onStatusUpdate invoked, status=3, progress=0.00
08-18 08:13:24.055 D/OTA     ( 8131): UITYPE_UPGRADE onProgressUpdate=9.073844921658747E-6
08-18 08:13:24.058 I/update_engine( 1246): [INFO:delta_performer.cc(113)] Completed 0/? operations, 16384/2075195198 bytes downloaded (0%), overall progress 0%
08-18 08:13:24.062 E/update_engine( 1246): [ERROR:payload_metadata.cc(64)] Bad payload format -- invalid delta magic: 33265343 Expected: 43724155
08-18 08:13:24.064 E/update_engine( 1246): [ERROR:download_action.cc(227)] Error ErrorCode::kDownloadInvalidMetadataMagicString (21) in DeltaPerformer's Write method when processing the received payload -- Terminating processing
08-18 08:13:24.067 I/update_engine( 1246): [INFO:delta_performer.cc(215)] Discarding 24 unused downloaded bytes
08-18 08:13:24.069 I/update_engine( 1246): [INFO:multi_range_http_fetcher.cc(177)] Received transfer terminated.
08-18 08:13:24.072 I/update_engine( 1246): [INFO:multi_range_http_fetcher.cc(129)] TransferEnded w/ code 200
08-18 08:13:24.074 I/update_engine( 1246): [INFO:multi_range_http_fetcher.cc(131)] Terminating.
08-18 08:13:24.077 I/update_engine( 1246): [INFO:action_processor.cc(116)] ActionProcessor: finished DownloadAction with code ErrorCode::kDownloadInvalidMetadataMagicString
08-18 08:13:24.082 I/update_engine( 1246): [INFO:action_processor.cc(121)] ActionProcessor: Aborting processing due to failure.
08-18 08:13:24.085 I/update_engine( 1246): [INFO:update_attempter_android.cc(565)] Processing Done.
08-18 08:13:24.088 D/UpdateManager( 8131): onStatusUpdate invoked, status=0, progress=0.00
08-18 08:13:24.088 D/OTA     ( 8131): UITYPE_UPGRADE onProgressUpdate=0.0
08-18 08:13:24.088 D/UpdateManager( 8131): onPayloadApplicationComplete invoked, errorCode=21
08-18 08:13:24.088 D/UpdateManager( 8131): setUpdaterState invoked newState=1
08-18 08:13:24.088 I/OTA     ( 8131): UpdaterStateChange state=ERROR/1
08-18 08:13:24.088 D/OTA     ( 8131): uiStateError
08-18 08:13:24.088 I/OTA     ( 8131): PayloadApplicationCompleted - errorCode=null/21 FAILURE
08-18 08:13:24.090 D/UpdateManager( 8131): resetUpdate invoked
08-18 08:13:24.090 D/UpdateManager( 8131): setUpdaterState invoked newState=0
08-18 08:13:24.090 I/OTA     ( 8131): UpdaterStateChange state=IDLE/0
08-18 08:13:24.090 I/update_engine( 1246): [INFO:metrics_reporter_android.cc(159)] Current update attempt downloads 0 bytes data
08-18 08:13:24.095 I/update_engine( 1246): [INFO:update_attempter_android.cc(402)] Attempting to reset state from UPDATE_STATUS_IDLE to UpdateStatus::IDLE
08-18 08:13:24.098 I/update_engine( 1246): [INFO:update_attempter_android.cc(410)] Cleaning up reserved space for compressed APEX (if any)
08-18 08:13:24.101 I/update_engine( 1246): [INFO:update_attempter_android.cc(821)] Clearing update complete marker.
08-18 08:13:24.104 I/update_engine( 1246): [INFO:dynamic_partition_control_android.cc(1306)] ResetUpdate resetting update state and deleting snapshots.
08-18 08:13:24.107 I/update_engine( 1246): [INFO:delta_performer.cc(1281)] Resetting recorded hash for prepared partitions.
chenxiaolong commented 1 month ago

I was able to run the avbroot commands without errors when using the unmodified contents

Great!

but if I do the following, then I get an error:

Ah, by using resize2fs, you wiped out the AVB metadata. I'd recommend this instead:

avbroot avb unpack -i system.img

This will create avb.toml and raw.img. Modify raw.img instead of system.img with your commands.

Then, recreate system.img with:

avbroot avb pack -o system.img --recompute-size

... also I tried the steps as recommended for adding the recovery.img partition (without other changes), but the device does not take the patched file.

Hmm, that's extremely odd. Any chance you could upload the patched OTA you were flashing?

The error is:

08-18 08:13:24.062 E/update_engine( 1246): [ERROR:payload_metadata.cc(64)] Bad payload format -- invalid delta magic: 33265343 Expected: 43724155

It's saying the first 4 bytes of payload.bin are 3&SC instead of CrAU. I have no idea what could possibly screw that up.

aaronfhamilton commented 1 month ago

Here’s the patched file with just recovery partition added:

https://drive.google.com/file/d/14quLMwMToMFFRFGul8TY8S7OTJEaUq8P/view?usp=drivesdk

On Sun, Aug 18, 2024 at 11:49 Andrew Gunnerson @.***> wrote:

I was able to run the avbroot commands without errors when using the unmodified contents

Great!

but if I do the following, then I get an error:

Ah, by using resize2fs, you wiped out the AVB metadata. I'd recommend this instead:

avbroot avb unpack -i system.img

This will create avb.toml and raw.img. Modify raw.img instead of system.img with your commands.

Then, recreate system.img with:

avbroot avb pack -o system.img --recompute-size

... also I tried the steps as recommended for adding the recovery.img partition (without other changes), but the device does not take the patched file.

Hmm, that's extremely odd. Any chance you could upload the patched OTA you were flashing?

The error is:

08-18 08:13:24.062 E/update_engine( 1246): [ERROR:payload_metadata.cc(64)] Bad payload format -- invalid delta magic: 33265343 Expected: 43724155

It's saying the first 4 bytes of payload.bin are 3&SC instead of CrAU. I have no idea what could possibly screw that up.

— Reply to this email directly, view it on GitHub https://github.com/chenxiaolong/avbroot/issues/328#issuecomment-2295355029, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABCQGSMG3D6XSSRVYRRAV7DZSDUERAVCNFSM6AAAAABMOZ2BMSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJVGM2TKMBSHE . You are receiving this because you authored the thread.Message ID: @.***>

chenxiaolong commented 1 month ago

Thanks! Unfortunately, this is probably not fixable because update_engine on your device has a broken zip file parser.


Details:

This is a hex dump of the portion of the zip file where payload.bin starts:

image

The incorrect offset is exactly 64 bytes before where it should be reading.

Looking at the zip, payload.bin is 5th entry:

❯ unzip -l sdm660_update.new.zip.patched 
Archive:  sdm660_update.new.zip.patched
signed by avbroot
  Length      Date    Time    Name
---------  ---------- -----   ----
     1675  01-01-1980 00:00   META-INF/com/android/otacert
        0  01-01-1980 00:00   apex_info.pb
      525  01-01-1980 00:00   care_map.pb
       24  01-01-1980 00:00   custom.txt
2075195198  01-01-1980 00:00   payload.bin
      156  01-01-1980 00:00   payload_properties.txt
      678  01-01-1980 00:00   META-INF/com/android/metadata
     1097  01-01-1980 00:00   META-INF/com/android/metadata.pb
---------                     -------
2075199353                     8 files

Every entry has a 16 byte data descriptor:

❯ zipdetails -vv --no-language-encoding sdm660_update.new.zip.patched
...
00000000 00000003 00000004 50 4B 03 04 LOCAL HEADER #1       04034B50 (67324752)
0000001E 00000039 0000001C 4D 45 54 41 Filename              'META-INF/com/android/otacert'
000006C5 000006C8 00000004 50 4B 07 08 DATA DESCRIPTOR       08074B50 (134695760)
000006C9 000006CC 00000004 54 09 FC C3 CRC                   C3FC0954 (3288074580)
000006CD 000006D0 00000004 8B 06 00 00 Compressed Size       0000068B (1675)
000006D1 000006D4 00000004 8B 06 00 00 Uncompressed Size     0000068B (1675)
...
000006D5 000006D8 00000004 50 4B 03 04 LOCAL HEADER #2       04034B50 (67324752)
000006F3 000006FE 0000000C 61 70 65 78 Filename              'apex_info.pb'
000006FF 00000702 00000004 50 4B 07 08 DATA DESCRIPTOR       08074B50 (134695760)
00000703 00000706 00000004 00 00 00 00 CRC                   00000000 (0)
00000707 0000070A 00000004 00 00 00 00 Compressed Size       00000000 (0)
0000070B 0000070E 00000004 00 00 00 00 Uncompressed Size     00000000 (0)
...
0000070F 00000712 00000004 50 4B 03 04 LOCAL HEADER #3       04034B50 (67324752)
0000072D 00000737 0000000B 63 61 72 65 Filename              'care_map.pb'
00000945 00000948 00000004 50 4B 07 08 DATA DESCRIPTOR       08074B50 (134695760)
00000949 0000094C 00000004 6B 51 CA AD CRC                   ADCA516B (2915717483)
0000094D 00000950 00000004 0D 02 00 00 Compressed Size       0000020D (525)
00000951 00000954 00000004 0D 02 00 00 Uncompressed Size     0000020D (525)
...
00000955 00000958 00000004 50 4B 03 04 LOCAL HEADER #4       04034B50 (67324752)
00000973 0000097C 0000000A 63 75 73 74 Filename              'custom.txt'
00000995 00000998 00000004 50 4B 07 08 DATA DESCRIPTOR       08074B50 (134695760)
00000999 0000099C 00000004 78 0A 43 1F CRC                   1F430A78 (524487288)
0000099D 000009A0 00000004 18 00 00 00 Compressed Size       00000018 (24)
000009A1 000009A4 00000004 18 00 00 00 Uncompressed Size     00000018 (24)
...
000009A5 000009A8 00000004 50 4B 03 04 LOCAL HEADER #5       04034B50 (67324752)
000009C3 000009CD 0000000B 70 61 79 6C Filename              'payload.bin'
...

So (4 files before payload.bin) times (16 bytes per data descriptor) = 64 bytes. I very strongly suspect that your device's update_engine has a broken zip parser and fails to handle data descriptors properly.

I tried flashing your zip on one of my test devices with some safety checks removed (nobody reading this should ever attempt this!) and it was able to successfully read the file.

While data descriptors are optional (and the original sdm660_update.zip doesn't use them), it is a part of the zip file standard. avbroot's OTA signing logic requires using data descriptors and cannot function without them.

aaronfhamilton commented 1 month ago

I thought the data descriptors were 12 bytes? Is the 4-byte descriptor a new(er) version of the spec? Also, I'm seeing data descriptors are used in the original file I have. They all have bit 3 set in the general purpose flag (0x0800).

Does it have anything to do with the original zip using zip spec 1.0 and the patched one using spec 2.0?

chenxiaolong commented 1 month ago

Oh huh, I missed that in the original file. It does indeed have a data descriptor, but only for META-INF/com/android/otacert.

The data descriptors can be either 12 or 16 bytes (or more for zip64) because the 4 byte 0x08074b50 marker is optional (section 4.3.9.3). AOSP supports parsing data descriptors with and without the marker (source).

I don't think the zip spec field has anything to do with it. At least in AOSP, that field is completely ignored.

aaronfhamilton commented 1 month ago

Would it be a heavy lift to modify the signing logic to support zip files without data descriptors? I'd be happy to donate to the project to make it happen.

chenxiaolong commented 1 month ago

I don't accept donations for my projects anymore, but thank you for offering!

Please give #337 a try. Test builds can be found at: https://github.com/chenxiaolong/avbroot/actions/runs/10463414808?pr=337. When patching, you'll want to use the new --zip-mode seekable option to prevent data descriptors from being written.

aaronfhamilton commented 1 month ago

You are an Android genius!!! Now on to checkout your Custota project.

chenxiaolong commented 1 month ago

337 has been merged and will be included in the upcoming 3.7.0 release!