Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brick on Xiaomi Redmi Note 13 Pro 5G (garnet) #405

Closed
misa-hase opened this issue Jan 21, 2025 · 4 comments
Closed

Brick on Xiaomi Redmi Note 13 Pro 5G (garnet) #405

misa-hase opened this issue Jan 21, 2025 · 4 comments
Assignees

Comments

@misa-hase
Copy link

There were some reports of avb_custom_key being supported on some Qualcomm-based Xiaomi models on #299 so I decided to take my chances and sign a custom ROM (crDroid) OTA for Xiaomi Redmi Note 13 Pro 5G which does use a Qualcomm SoC.

The OTA zip file came without a recovery which resulted in me getting a No compatible boot image found for OtaCertPatcher error.
So, I inserted a custom recovery using the instructions provided at #328 (comment) and then could proceed with the patch:

$ avbroot ota patch --input crDroidAndroid-15.0-20250119-garnet-v11.1-rec.zip --key-avb ../keys/avb.key --key-ota ../keys/ota.key --cert-ota ../keys/ota.crt --magisk ../magisk/Magisk-v28.1.apk --magisk-preinit-device sda17 --clear-vbmeta-flags
  0.036s  INFO Replacing zip entry: META-INF/com/android/otacert
  0.073s  INFO Copying zip entry: apex_info.pb
  0.074s  INFO Copying zip entry: care_map.pb
  0.074s  INFO Patching zip entry: payload.bin
  0.075s  INFO Extracting from original payload: system
 15.114s  INFO Extracting from original payload: vbmeta_system
 15.119s  INFO Extracting from original payload: recovery
 16.015s  INFO Extracting from original payload: vbmeta
 16.020s  INFO Extracting from original payload: boot
 16.315s  INFO Extracting from original payload: vendor_boot
 16.727s  INFO Candidate boot images: boot, recovery, vendor_boot
 17.868s  INFO Patching system image: system
 18.469s  INFO Patched otacerts.zip offsets in system: [331198464..331199649]
 18.469s  INFO Patching vbmeta images: vbmeta_system, vbmeta
 18.483s  INFO Compressing full image: vbmeta_system
 18.483s  INFO Compressing full image: recovery
 18.788s  INFO Compressing full image: boot
 19.153s  INFO Compressing partial image: system: [331198464..331199649, 1260408832..1280385920, 1280700352..1280700416]
 22.310s  INFO Compressing full image: vbmeta
 22.311s  INFO Generating new OTA payload
 49.058s  INFO Patching zip entry: payload_properties.txt
 49.058s  INFO Generating new OTA metadata
 49.066s  INFO Verifying metadata offsets
 49.073s  INFO Successfully patched OTA

And verifying the patched OTA file:

$ avbroot ota verify --input=crDroidAndroid-15.0-20250119-garnet-v11.1-rec.zip.patched --cert-ota ../keys/ota.crt --public-key-avb ../keys/avb_pkmd.bin
  0.000s  INFO Verifying whole-file signature
  1.026s  INFO Verifying payload
  2.897s  INFO Extracting partition images to temporary directory
  2.897s  INFO Extracting from the payload: boot, dtbo, odm, product, recovery, system, system_ext, vbmeta, vbmeta_system, vendor, vendor_boot, vendor_dlkm
155.936s  INFO Successfully extracted OTA
155.936s  INFO Verifying partition hashes
210.917s  INFO Checking recovery ramdisk's otacerts.zip
211.114s  INFO Verifying AVB signatures
211.115s  INFO vbmeta has a signed vbmeta header
211.116s  INFO recovery has a signed vbmeta header
211.116s  INFO vbmeta_system has a signed vbmeta header
211.116s  INFO Verifying hash tree descriptor for: vendor_dlkm
211.116s  INFO Verifying hash tree descriptor for: product
211.116s  INFO Verifying hash tree descriptor for: odm
211.116s  INFO Verifying hash tree descriptor for: system_ext
211.116s  INFO Verifying hash descriptor for: dtbo
211.116s  INFO Verifying hash descriptor for: recovery
211.116s  INFO Verifying hash descriptor for: boot
211.116s  INFO Verifying hash descriptor for: vendor_boot
211.116s  INFO Verifying hash tree descriptor for: system
211.116s  INFO Verifying hash tree descriptor for: vendor
235.482s  INFO Signatures are all valid!

Flashing the patched partitions using fastboot flashall did not work for me as I got Not enough space to resize partition errors when it tried to flash system.img for whatever reason (perhaps the fastbootd implementation on the custom recovery was borked). So I flashed the custom recovery from the patched OTA first and then flashed the entire patched OTA zip via adb sideload

I did verify that the recovery image indeed had correct signature:

$ avbroot avb verify --input extracted/recovery.img --public-key ../keys/avb_pkmd.bin 
 0.020s  INFO recovery has a signed vbmeta header
 0.021s  INFO Verifying hash descriptor for: recovery
 0.277s  INFO Successfully verified all vbmeta signatures and hashes

After which crDroid was successfully installed and the phone did boot up and once again I put the device into fastboot mode and flashed the avb_pkmd.bin into the avb_custom_key partition.

$ fastboot erase avb_custom_key
Erasing 'avb_custom_key'                           OKAY [  0.013s]
Finished. Total time: 0.022s
$ fastboot flash avb_custom_key ../keys/avb_pkmd.bin 
Warning: skip copying avb_custom_key image avb footer (avb_custom_key partition size: 0, avb_custom_key image size: 1032).
Sending 'avb_custom_key' (1 KB)                    OKAY [  0.002s]
Writing 'avb_custom_key'                           OKAY [  0.009s]
Finished. Total time: 0.038s

As mentioned in the 8th step of the README I checked whether AVB was working properly or not

# dmesg | grep libfs_avb
[    0.822286] init: Failed to copy /avb into /metadata/gsi/dsu/avb/: No such file or directory
[    0.831759] init: [libfs_avb] Returning avb_handle with status: Success
[    0.832537] init: [libfs_avb] : Error verifying vbmeta image: OK_NOT_SIGNED
[    0.832630] init: [libfs_avb] public key data shouldn't be empty for /system
[    0.832637] init: [libfs_avb] Found unknown public key used to sign /system
[    0.832641] init: [libfs_avb] Returning avb_handle for '/system' with status: VerificationError
[    0.832704] init: [libfs_avb] Built verity table: '1 /dev/block/dm-1 /dev/block/dm-1 4096 4096 307717 307717 sha256 9522ab76346b22a89bad2ce4b35b1473809c8d11669a1de0b8e9222234d3c2bb fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91 10 use_fec_from_device /dev/block/dm-1 fec_roots 2 fec_blocks 310142 fec_start 310142 restart_on_corruption ignore_zero_blocks'
[    0.840947] init: [libfs_avb] Built verity table: '1 /dev/block/dm-2 /dev/block/dm-2 4096 4096 275380 275380 sha1 40e5e6fc198d2dc4c6e62714cc67312f8db80411 fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91 10 use_fec_from_device /dev/block/dm-2 fec_roots 2 fec_blocks 277550 fec_start 277550 restart_on_corruption ignore_zero_blocks'
[    0.845676] init: [libfs_avb] Built verity table: '1 /dev/block/dm-0 /dev/block/dm-0 4096 4096 424849 424849 sha1 c080e04a270eec2dcdc54251f388b9477fb886a4 fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91 10 use_fec_from_device /dev/block/dm-0 fec_roots 2 fec_blocks 428196 fec_start 428196 restart_on_corruption ignore_zero_blocks'
[    0.849963] init: [libfs_avb] Built verity table: '1 /dev/block/dm-4 /dev/block/dm-4 4096 4096 583879 583879 sha1 a00f3a768e17489d6db96bc0edc05014749a29d1 fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91 10 use_fec_from_device /dev/block/dm-4 fec_roots 2 fec_blocks 588478 fec_start 588478 restart_on_corruption ignore_zero_blocks'
[    0.853730] init: [libfs_avb] Built verity table: '1 /dev/block/dm-5 /dev/block/dm-5 4096 4096 22995 22995 sha1 10cd9b158891864acc064741db1b3a0ee811fe5b fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91 10 use_fec_from_device /dev/block/dm-5 fec_roots 2 fec_blocks 23178 fec_start 23178 restart_on_corruption ignore_zero_blocks'
[    0.857603] init: [libfs_avb] Built verity table: '1 /dev/block/dm-3 /dev/block/dm-3 4096 4096 907 907 sha1 d3480f3ff556ba2247746fc6ab425669f9ff965c fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91 10 use_fec_from_device /dev/block/dm-3 fec_roots 2 fec_blocks 916 fec_start 916 restart_on_corruption ignore_zero_blocks'

While I got the message Returning avb_handle with status: Success, the Error verifying vbmeta image: OK_NOT_SIGNED and Returning avb_handle for '/system' with status: VerificationError were rather worrisome but according to #338 (comment) it should be fine?
Considering I could see the root digest of my signed system.img at the line Built verity table line for /dev/block/dm-1:

$ avbroot avb info -i extracted/system.img
AvbInfo {
    header: Header {
        required_libavb_version_major: 1,
        required_libavb_version_minor: 0,
        algorithm_type: None,
        hash: "",
        signature: "",
        public_key: "",
        public_key_metadata: "",
        descriptors: [
            HashTree(
                HashTreeDescriptor {
                    dm_verity_version: 1,
                    image_size: 1260408832,
                    tree_offset: 1260408832,
                    tree_size: 9932800,
                    data_block_size: 4096,
                    hash_block_size: 4096,
                    fec_num_roots: 2,
                    fec_offset: 1270341632,
                    fec_size: 10043392,
                    hash_algorithm: "sha256",
                    partition_name: "system",
                    salt: "fe4563e86930a1ecb6d28c37f4523eaf71a3ce26d4fb000ae38eb6fa29685f91",
                    root_digest: "9522ab76346b22a89bad2ce4b35b1473809c8d11669a1de0b8e9222234d3c2bb",
                    flags: 0,
                    reserved: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
                },
            ),
            Property(
                PropertyDescriptor {
                    key: "com.android.build.system.os_version",
                    value: "15",
                },
            ),
            Property(
                PropertyDescriptor {
                    key: "com.android.build.system.fingerprint",
                    value: "Redmi/lineage_garnet/garnet:15/AP4A.250105.002/eng.nobody.20250119.131843:userdebug/release-keys",
                },
            ),
            Property(
                PropertyDescriptor {
                    key: "com.android.build.system.security_patch",
                    value: "2025-01-05",
                },
            ),
        ],
        rollback_index: 0,
        flags: 0,
        rollback_index_location: 0,
        release_string: "avbtool 1.3.0",
        reserved: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    },
    footer: Some(
        Footer {
            version_major: 1,
            version_minor: 0,
            original_image_size: 1260408832,
            vbmeta_offset: 1280385024,
            vbmeta_size: 896,
            reserved: "00000000000000000000000000000000000000000000000000000000",
        },
    ),
    image_size: 1280700416,
}

But after locking the bootloader via fastboot flashing lock I got hit the infamous System has been destroyed screen on my phone.

I've got the means to fix my device but what I'd like to know is whether custom chain of trust is actually not supported on this model or perhaps I've done something wrong while trying to make things work?

@chenxiaolong
Copy link
Owner

Nice investigative work you did there--thanks for detailing all your findings!

As far as I can tell, you did everything right. The Not enough space to resize partition is definitely odd, but even if system didn't flash properly, it would fail much later in the boot process because the signatures of dynamic partitions (system, product, vendor, etc.) are verified by Android instead of the bootloader.

If you want to be extra sure that everything flashed properly, you can try running avbroot avb verify on the device itself (there's an Android build of avbroot available):

adb push avbroot /tmp/
adb push avb_pkmd.bin /tmp/

# Run as root on the device
su
cd /tmp/

# Create the directory structure that `avbroot avb verify` expects
suffix=$(getprop ro.boot.slot_suffix)
mkdir /dev/avbroot
for f in {/dev/block/by-name,/dev/block/mapper}/*"${suffix}"; do ln "$(realpath "${f}")" "/dev/avbroot/$(basename "${f%${suffix}}.img")"; done

# Verify on-device partitions
./avbroot avb verify -i /dev/avbroot/vbmeta.img -p avb_pkmd.bin

If that returns Signatures are all valid! like when you ran avbroot avb verify on your computer, then everything is definitely valid and properly flashed.

In that case, my only suggestion would be to try flashing the OTA from recovery twice so that both the A and B slots have something signed with your key. Some Pixel devices have bootloaders that check for this--not sure if Xiaomi's bootloader does something similar.

If that also doesn't work, then I'm afraid you're probably out of luck and your device doesn't support avb_custom_key properly.

@chenxiaolong chenxiaolong self-assigned this Jan 22, 2025
@misa-hase
Copy link
Author

As suggested I flashed the OTA twice from the recovery and made sure that both A and B slots boot into the same ROM.

Just in case before flashing the custom ROM I also flashed the official MIUI ROM on both slots to ensure the bootloader was up-to-date on both slots and Xiaomi's anti-rollback protection wouldn't cause issues.

On both slots (whether on the ROM itself or recovery) I did see the Returning avb_handle with status: Success message on the kernel logs.

Also ran the commands you mentioned. I weren't aware you could actually run avbroot on the phone itself to verify partitions, that's pretty cool!
And I got the same successful result on both A and B slots:

# ./avbroot avb verify -i /dev/avbroot/vbmeta.img -p avb_pkmd.bin
  0.012s  INFO vbmeta has a signed vbmeta header
  0.019s  INFO recovery has a signed vbmeta header
  0.022s  INFO vbmeta_system has a signed vbmeta header
  0.023s  INFO Verifying hash tree descriptor for: vendor
  0.023s  INFO Verifying hash descriptor for: vendor_boot
  0.023s  INFO Verifying hash tree descriptor for: odm
  0.024s  INFO Verifying hash descriptor for: recovery
  0.024s  INFO Verifying hash tree descriptor for: system_ext
  0.024s  INFO Verifying hash tree descriptor for: system
  0.204s  INFO Verifying hash tree descriptor for: product
  0.310s  INFO Verifying hash descriptor for: dtbo
  1.969s  INFO Verifying hash tree descriptor for: vendor_dlkm
  2.657s  INFO Verifying hash descriptor for: boot
 28.271s  INFO Successfully verified all vbmeta signatures and hashes

I also encountered a weird behavior when trying to flash the partition avb_custom_key, as it turns out the Xiaomi bootloader accepts any partition name starting with avb_custom_key. Should something like this really be happening...?

$ fastboot erase avb_custom_keyshouldthisreallybehappening
Erasing 'avb_custom_keyshouldthisreallybehappening' OKAY [  0.011s]
Finished. Total time: 0.024s
$ fastboot flash avb_custom_keyshouldthisreallybehappening avb_pkmd.bin 
Warning: skip copying avb_custom_keyshouldthisreallybehappening image avb footer (avb_custom_keyshouldthisreallybehappening partition size: 0, avb_custom_keyshouldthisreallybehappening image size: 1032).
Sending 'avb_custom_keyshouldthisreallybehappening' (1 KB) OKAY [  0.002s]
Writing 'avb_custom_keyshouldthisreallybehappening' OKAY [  0.009s]
Finished. Total time: 0.047s

That does not happen for other partitions like userdata

$ fastboot erase userdatablahblah
Erasing 'userdatablahblah'                         FAILED (remote: 'Check device console.')
fastboot: error: Command failed

I also checked whether the erase command accepted any partition name regardless of whether it existed or not, but that doesn't seem to be the case here (I tested avb_custom as a partition name that shouldn't exist):

$ fastboot erase avb_custom
Erasing 'avb_custom'                            FAILED (remote: 'Check device console.')
fastboot: error: Command failed

Just in case I also checked whether the above phenomenon is applicable to Pixel 8 but that doesn't seem to be the case:

$ fastboot erase avb_custom_keyshouldthisreallybehappening
Erasing 'avb_custom_keyshouldthisreallybehappening' FAILED (remote: 'partition not found')
fastboot: error: Command failed

I've got a feeling the avb_custom_key implementation on Xiaomi might be quite borked. Is there a way to verify whether custom_avb_key is successfully written to or I've got to actually lock the bootloader to verify that?

@chenxiaolong
Copy link
Owner

Wow, yeah, the Xiaomi bootloader's avb_custom_key handling definitely seems quite borked. I'm not aware of any way to check what the current value of avb_custom_key is (at least on Pixel devices). I think the only way to test is to lock the bootloader and see if it boots.

@misa-hase
Copy link
Author

Despite validating the signatures on device and flashing avb_custom_key (also tried flashing avb_custom_key_a and avb_custom_key_b partitions - which shouldn't exist - just in case if Xiaomi uses different key for A/B slots) I ended up in the same System has been destroyed screen as before.

I believe from all the work above we can conclude that Xiaomi's implementation of avb_custom_key is completely broken and despite getting OKAY's when flashing avb_custom_key it's either not actually written to or simply ignored during boot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants