Lenovo-YTX703-Devel / android_device_lenovo_YTX703-common

1 stars 1 forks source link

How to lose your DRM keys #24

Open Quallenauge opened 6 years ago

Quallenauge commented 6 years ago

From @vladimiroltean on February 19, 2018 21:34

Together with Christian I started looking into the bootloader's source code to understand what exactly triggered the deletion of my (or should I say our) DRM keys. In fact, I was monitoring my DRM L1 security level status quite closely, and I am quite confident that the moment I lost my DRM keys was exactly during the process of flashing back the stock image, in fastboot, for some tests. Basically there are 2 places in app/aboot/aboot.c where the send_delete_keys_to_tz() function is called:

  1. Now this pretty much says it all: we are looking at the void cmd_erase_mmc(const char *arg, void *data, unsigned sz) function. If you ask it to erase any other partition except userdata, it looks like "bam", you lose your encryption keys.
    2550 #if VERIFIED_BOOT
    2551 #if !VBOOT_MOTA
    2552 »       if(!(strncmp(arg, "userdata", 8)))
    2553 »       »       if(send_delete_keys_to_tz())
    2554 »       »       »       ASSERT(0);
    2555 #endif
    2556 #endif
  2. I don't quite understand this very well, so feedback is appreciated. Trigger dm-verity and enrage the gods of trust? Under what conditions can we enter reboot_mode == DM_VERITY_KEYSCLEAR?
    4304 #if VERIFIED_BOOT
    4305 #if !VBOOT_MOTA
    4306 »       else if (reboot_mode == DM_VERITY_ENFORCING)
    4307 »       {
    4308 »       »       device.verity_mode = 1;
    4309 »       »       write_device_info(&device);
    4310 »       } else if(reboot_mode == DM_VERITY_LOGGING) {
    4311 »       »       device.verity_mode = 0;
    4312 »       »       write_device_info(&device);
    4313 »       } else if(reboot_mode == DM_VERITY_KEYSCLEAR) {
    4314 »       »       if(send_delete_keys_to_tz())
    4315 »       »       »       ASSERT(0);
    4316 »       }
    4317 #endif
    4318 #endif

Of course, losing my encryption keys would be too graphic a scene to be shown in this open-source bootloader code, that's why they are just sending the "delete keys" command to the trusted OS that's running in TZ (ARM TrustZone) so it can do the deeds.

Quite unfortunately for my, I deliberately backed up my /dev/block/mmcblk0p29 (keystore) partition and put it to cold storage for moments like this. As it turns out, what I had actually backed up was a zero-filled partition.

So, moral of the story: don't play with fastboot erase, kids! Also, dm-verity something :) We should consider building the bootloader from source, simply remove the lines that delete the DRM keys (or maybe even disable verified boot altogether), and then distribute it as part of the firmware images (emmc_appsboot.mbn).

Copied from original issue: Quallenauge/Yoga-Tab-3-Plus-Issue-Tracker#18

Quallenauge commented 6 years ago

That's quite interesting! So I think I can also reconstruct at which point I loosed my keys - when playing around with the fastboot erase command.

Regarding to point 1) if(!(strncmp(arg, "userdata", 8))) It's more like, if exactly the partition userdata should be erased, then all keys should also be deleted (when using encryption, I assume). strncmp() returns 0 if the strings are equal. The result is negated ( ! ) to match if rules.

Sadly we can't backup the partition, where the keys belongs to. It seems they are stored within a special partition, so called rpmb, see Replay Protected Memory Block (RPMB) subsystemor eMMC Security. A strace of the widevine command shows the access to that device:

648   ioctl(13</dev/qseecom>, _IOC(0, 0x97, 0x5, 0) <unfinished ...>
632   ioctl(10</dev/qseecom>, _IOC(0, 0x97, 0x5, 0) <unfinished ...>
568   ioctl(7</dev/qseecom>, _IOC(0, 0x97, 0x5, 0) <unfinished ...>
518   rt_sigsuspend([], 8 <unfinished ...>
568   <... ioctl resumed> , 0x5000)     = 0
568   ioctl(5</dev/block/mmcblk0rpmb>, _IOC(_IOC_READ|_IOC_WRITE, 0xb3, 0, 0xd8), 0x791bbff2b0) = 0
568   getuid()                          = 1000
568   writev(3<UNIX:[13111]>, [{iov_base="\0008\2\300/vZ5\233r8", iov_len=11}, {iov_base="\6", iov_len=1}, {iov_base="rpmb_emmc\0", iov_len=10}, {iov_base="----------------------------rpmb_emmc_read-----------------------------\0", iov_len=72}], 4) = 94
568   getuid()                          = 1000
568   writev(4</dev/pmsg0>, [{iov_base="le\0\350\3\6\2", iov_len=7}, {iov_base="\0008\2\300/vZ5\233r8", iov_len=11}, {iov_base="\6", iov_len=1}, {iov_base="rpmb_emmc\0", iov_len=10}, {iov_base="----------------------------rpmb_emmc_read-----------------------------\0", iov_len=72}], 5) = 101
568   ioctl(7</dev/qseecom>, _IOC(0, 0x97, 0x6, 0), 0x14) = 0
568   ioctl(7</dev/qseecom>, _IOC(0, 0x97, 0x5, 0) <unfinished ...>
655   <... ioctl resumed> , 0x7e000)    = 0
655   openat(AT_FDCWD, "/persist/data/widevine/widevine", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 32</persist/data/widevine/widevine>
655   unlinkat(AT_FDCWD, "/persist/data/widevine/widevine", AT_REMOVEDIR)

As I understand, the rpbm partition exposes only some special ioctls for controlling it, not the ones to create a backup or so.

Building the bootloader for our device should work, bot not flashing and executing them, since these binaries are digitally signed and our boards doesn't accept wrong or no signed binaries. That's part of qcoms secure boot feature (see secure-boot-and-image-authentication-technical-overview.pdfand qualcomm-bl-signature-vulnerability-android-secure-boot). Also a very interesting document is the following: Exploiting Qualcomm EDL Programmers (1): Gaining Access & PBL Internals.

To make further tests, you can generate some testcertifcates via the oemwvtest binary, which is included in the stock rom: # oemwvtest wideprov. Then make some actions and verify what really kills the keys.