-
Notifications
You must be signed in to change notification settings - Fork 42
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
Investigate Pixel's new repair mode feature #216
Comments
Repair mode is fully working in an avbroot setup, but with a big caveat (see bottom of post). But first, this is how the feature is implemented:
WARNING!There's is one big caveat with avbroot + repair mode. Repair mode will also be rooted! All it takes is installing the Magisk/KernelSU app and root access will be granted. This is problematic because with root access, it's trivial for someone to manually mount the original EDIT: Per @pascallj's suggestion below, a good way to work around this is by sideloading an unrooted avbroot-signed OTA prior to entering repair mode. This can be done by patching with the EDIT 2: This helps close the unauthenticated root access vulnerability, but it's not perfectly safe. In repair mode, Google's original OTA updater is enabled by default and could potentially run. avbroot's |
Thanks for researching this! When I noticed this feature in the feature drop, it immediately peaked my interest. I agree that giving a device with avbroot to any sort of official repair shop is a bad idea. It will raise red flags and I think they will just reset the device then anyway. However if you're just getting your screen replaced at the local phone shop around the corner, this mode would still be sufficient. Flashing the stock OS will force you to wipe your device as we have established that it cannot (or won't) decrypt userdata written with custom keys. Would flashing a rootless variant of the system fix this issue? There won't be any way to get root on the system now and because the bootloader is locked it is impossible to revert to the other version. You can flash a root-enabled variant when the device returns and everything should work as is. |
That's brilliant! I didn't think of that at all. Yes, that completely solves the problem. Switching between avbroot-signed rootless and rooted builds is just an adb sideload away. I'll update my message above to suggest that. |
One downside I was later thinking of, is that the 'clearotacerts' module is not running. Therefore maybe the system might get an accidental OTA update (if that works in repair mode) which breaks the system. |
|
I was wrong. I tested with Custota and it looks like OTA updates go through just fine in repair mode. It also looks like repair mode enables the OEM updater app too, which I suppose makes sense since that's the default. I don't see a good solution around this. I was trying finding a way to do what the I can't think of a way to use repair mode that's 100% safe against the accidental OTA update scenario at the moment. |
Thanks for testing! Avbroot supports repacking of images now right? What if we just replace the otacerts.zip and repack the image? |
That would be the best solution. avbroot can deal with all the AVB, dm-verify, and FEC parts, but it doesn't have the ability to write to an ext4 image or recreate an erofs image (since Android's copy of |
In userspace, as in userspace on the device avbroot is running on? We can just corrupt the file 🙈 Ext4 doesn't have checksums as far as I'm aware. |
I meant on the system that's running
😂 I guess that is indeed theoretically possible. Still would require some sort of ext4/erofs parser to find the blocks where the file is located though. (If there actually is a good way to find the block(s) containing |
Well, it turns out recovery's copy of I tested with ext4 and uncompressed erofs. fsck passes, the filesystem mounts, and the replaced Although this actually works well, I probably won't implement this because:
It sure would be nice if we could just:
during |
Interesting! I agree, it is not worth implementing it this way. It's a very niche use case. |
Previously, overriding otacerts.zip in the system partition required the user to flash a Magisk/KernelSU module that would bind mount over the file during boot. While this worked well enough, it's insufficient for unrooted setups, which has become more important since unrooting is the only safe way to use the new OEM repair mode feature. With the stock otacerts.zip, the OEM's default OTA updater app could run and install an OS upgrade that's not signed by the user's key. With this key, the raw otacerts.zip bytes in the system partition are directly replaced with a new zip that contains the user's certificate. This method was inspired by @pascallj's comment in #216 suggestiing intentionally corrupting the otacerts.zip data in the filesystem. Because avbroot does not have filesystem parsers for ext4/f2fs/erofs, we rely on a heuristic-based search on the raw filesystem image. The file is always smaller than one block (which is at least 4096 bytes on all known devices), so the file data is stored continguously on disk and in the case of erofs, won't be compressed. None of the three filesystems are copy-on-write and thus, have no filesystem-level data checksums. For the dm-verity layer one level up, avbroot already knows how to recompute the hash tree and FEC data. Since the new approach is doing a raw search and replace, the old and new files must have the same size. When the new zip is smaller, null bytes are added to the zip archive comment field to pad to the correct size. When the new zip is larger, avbroot will attempt the following to try and make the file size smaller: 1. Enable zip deflate compression 2. Strip the X.509 signature from the certificate 3. Clear out the issuer RDN sequence from the certificate 4. Clear out the subject RDN sequence from the certificate The latter three changes work because Android never performs any PKI operations with the certificate. There is no CA certificate chain. The X.509 certificate file is nothing more than a way to transport an RSA public key. avbroot requires the user's key to be RSA 4096. If the original zip had the same key size, then none of these shrinking methods are needed. If it contained an RSA 2048 key, then the first two modifications are usually sufficient. The latter two modifications should only be needed if the user picked a really long subject value when generating the certificate. With these new changes, the OTA patching time will approximately double on a system with an SSD and modern CPU. This is dominated by the time it takes to XZ-compress the system partition image. The compression is already parallelized and scales linearly with the number of cores. There's likely not much more that can be done to further speed this up. Finally, these new changes are currently excluded from the e2e tests because including the system partition in the stripped OTAs would increase the file size by an order of magnitude. This could potentially be solved in the future by generating our own small OTAs to use for testing instead of running against real device OTAs. Fixes: #225 Signed-off-by: Andrew Gunnerson <[email protected]>
Previously, overriding otacerts.zip in the system partition required the user to flash a Magisk/KernelSU module that would bind mount over the file during boot. While this worked well enough, it's insufficient for unrooted setups, which has become more important since unrooting is the only safe way to use the new OEM repair mode feature. With the stock otacerts.zip, the OEM's default OTA updater app could run and install an OS upgrade that's not signed by the user's key. With this key, the raw otacerts.zip bytes in the system partition are directly replaced with a new zip that contains the user's certificate. This method was inspired by @pascallj's comment in #216 suggesting intentionally corrupting the otacerts.zip data in the filesystem. Because avbroot does not have filesystem parsers for ext4/f2fs/erofs, we rely on a heuristic-based search on the raw filesystem image. The file is always smaller than one block (which is at least 4096 bytes on all known devices), so the file data is stored contiguously on disk and in the case of erofs, won't be compressed. None of the three filesystems are copy-on-write and thus, have no filesystem-level data checksums. For the dm-verity layer one level up, avbroot already knows how to recompute the hash tree and FEC data. Since the new approach is doing a raw search and replace, the old and new files must have the same size. When the new zip is smaller, null bytes are added to the zip archive comment field to pad to the correct size. When the new zip is larger, avbroot will attempt the following to try and make the file size smaller: 1. Enable zip deflate compression 2. Strip the X.509 signature from the certificate 3. Clear out the issuer RDN sequence from the certificate 4. Clear out the subject RDN sequence from the certificate The latter three changes work because Android never performs any PKI operations with the certificate. There is no CA certificate chain. The X.509 certificate file is nothing more than a way to transport an RSA public key. avbroot requires the user's key to be RSA 4096. If the original zip had the same key size, then none of these shrinking methods are needed. If it contained an RSA 2048 key, then the first two modifications are usually sufficient. The latter two modifications should only be needed if the user picked a really long subject value when generating the certificate. With these new changes, the OTA patching time will approximately double on a system with an SSD and modern CPU. This is dominated by the time it takes to XZ-compress the system partition image. The compression is already parallelized and scales linearly with the number of cores. There's likely not much more that can be done to further speed this up. Finally, these new changes are currently excluded from the e2e tests because including the system partition in the stripped OTAs would increase the file size by an order of magnitude. This could potentially be solved in the future by generating our own small OTAs to use for testing instead of running against real device OTAs. Fixes: #225 Signed-off-by: Andrew Gunnerson <[email protected]>
Previously, overriding otacerts.zip in the system partition required the user to flash a Magisk/KernelSU module that would bind mount over the file during boot. While this worked well enough, it's insufficient for unrooted setups, which has become more important since unrooting is the only safe way to use the new OEM repair mode feature. With the stock otacerts.zip, the OEM's default OTA updater app could run and install an OS upgrade that's not signed by the user's key. With this commit, the raw otacerts.zip bytes in the system partition are directly replaced with a new zip that contains the user's certificate. This method was inspired by @pascallj's comment in #216 suggesting intentionally corrupting the otacerts.zip data in the filesystem. Because avbroot does not have filesystem parsers for ext4/f2fs/erofs, we rely on a heuristic-based search on the raw filesystem image. The file is always smaller than one block (which is at least 4096 bytes on all known devices), so the file data is stored contiguously on disk and in the case of erofs, won't be compressed. None of the three filesystems are copy-on-write and thus, have no filesystem-level data checksums. For the dm-verity layer one level up, avbroot already knows how to recompute the hash tree and FEC data. To ensure that there are no false positives, any match that the search finds must correctly parse as a valid zip and every entry within the zip must have a filename that ends in .x509.pem. This matches what update_engine expects from a proper otacerts.zip file. Since the new approach is doing a raw search and replace, the old and new files must have the same size. When the new zip is smaller, null bytes are added to the zip archive comment field to pad to the correct size. When the new zip is larger, avbroot will attempt the following to try and make the file size smaller: 1. Enable zip deflate compression 2. Strip the X.509 signature from the certificate 3. Clear out the issuer RDN sequence from the certificate 4. Clear out the subject RDN sequence from the certificate The latter three changes work because Android never performs any PKI operations with the certificate. There is no CA certificate chain. The X.509 certificate file is nothing more than a way to transport an RSA public key. avbroot requires the user's key to be RSA 4096. If the original zip had the same key size, then none of these shrinking methods are needed. If it contained an RSA 2048 key, then the first two modifications are usually sufficient. The latter two modifications should only be needed if the user picked a really long subject value when generating the certificate. With these new changes, the OTA patching time will approximately double on a system with an SSD and modern CPU. This is dominated by the time it takes to XZ-compress the system partition image. The compression is already parallelized and scales linearly with the number of cores. There's likely not much more that can be done to further speed this up. Finally, these new changes are currently excluded from the e2e tests because including the system partition in the stripped OTAs would increase the file size by an order of magnitude. This could potentially be solved in the future by generating our own small OTAs to use for testing instead of running against real device OTAs. Fixes: #225 Signed-off-by: Andrew Gunnerson <[email protected]>
Previously, overriding otacerts.zip in the system partition required the user to flash a Magisk/KernelSU module that would bind mount over the file during boot. While this worked well enough, it's insufficient for unrooted setups, which has become more important since unrooting is the only safe way to use the new OEM repair mode feature. With the stock otacerts.zip, the OEM's default OTA updater app could run and install an OS upgrade that's not signed by the user's key. With this commit, the raw otacerts.zip bytes in the system partition are directly replaced with a new zip that contains the user's certificate. This method was inspired by @pascallj's comment in #216 suggesting intentionally corrupting the otacerts.zip data in the filesystem. Because avbroot does not have filesystem parsers for ext4/f2fs/erofs, we rely on a heuristic-based search on the raw filesystem image. The file is always smaller than one block (which is at least 4096 bytes on all known devices), so the file data is stored contiguously on disk and in the case of erofs, won't be compressed. None of the three filesystems are copy-on-write and thus, have no filesystem-level data checksums. For the dm-verity layer one level up, avbroot already knows how to recompute the hash tree and FEC data. To ensure that there are no false positives, any match that the search finds must correctly parse as a valid zip and every entry within the zip must have a filename that ends in .x509.pem. This matches what update_engine expects from a proper otacerts.zip file. Since the new approach is doing a raw search and replace, the old and new files must have the same size. When the new zip is smaller, null bytes are added to the zip archive comment field to pad to the correct size. When the new zip is larger, avbroot will attempt the following to try and make the file size smaller: 1. Enable zip deflate compression 2. Strip the X.509 signature from the certificate 3. Clear out the issuer RDN sequence from the certificate 4. Clear out the subject RDN sequence from the certificate The latter three changes work because Android never performs any PKI operations with the certificate. There is no CA certificate chain. The X.509 certificate file is nothing more than a way to transport an RSA public key. avbroot requires the user's key to be RSA 4096. If the original zip had the same key size, then none of these shrinking methods are needed. If it contained an RSA 2048 key, then the first two modifications are usually sufficient. The latter two modifications should only be needed if the user picked a really long subject value when generating the certificate. With these new changes, the OTA patching time will approximately double on a system with an SSD and modern CPU. This is dominated by the time it takes to XZ-compress the system partition image. The compression is already parallelized and scales linearly with the number of cores. There's likely not much more that can be done to further speed this up. Finally, these new changes are currently excluded from the e2e tests because including the system partition in the stripped OTAs would increase the file size by an order of magnitude. This could potentially be solved in the future by generating our own small OTAs to use for testing instead of running against real device OTAs. Fixes: #225 Signed-off-by: Andrew Gunnerson <[email protected]>
Previously, overriding otacerts.zip in the system partition required the user to flash a Magisk/KernelSU module that would bind mount over the file during boot. While this worked well enough, it's insufficient for unrooted setups, which has become more important since unrooting is the only safe way to use the new OEM repair mode feature. With the stock otacerts.zip, the OEM's default OTA updater app could run and install an OS upgrade that's not signed by the user's key. With this commit, the raw otacerts.zip bytes in the system partition are directly replaced with a new zip that contains the user's certificate. This method was inspired by @pascallj's comment in #216 suggesting intentionally corrupting the otacerts.zip data in the filesystem. Because avbroot does not have filesystem parsers for ext4/f2fs/erofs, we rely on a heuristic-based search on the raw filesystem image. The file is always smaller than one block (which is at least 4096 bytes on all known devices), so the file data is stored contiguously on disk and in the case of erofs, won't be compressed. None of the three filesystems are copy-on-write and thus, have no filesystem-level data checksums. For the dm-verity layer one level up, avbroot already knows how to recompute the hash tree and FEC data. To ensure that there are no false positives, any match that the search finds must correctly parse as a valid zip and every entry within the zip must have a filename that ends in .x509.pem. This matches what update_engine expects from a proper otacerts.zip file. Since the new approach is doing a raw search and replace, the old and new files must have the same size. When the new zip is smaller, null bytes are added to the zip archive comment field to pad to the correct size. When the new zip is larger, avbroot will attempt the following to try and make the file size smaller: 1. Enable zip deflate compression 2. Strip the X.509 signature from the certificate 3. Clear out the issuer RDN sequence from the certificate 4. Clear out the subject RDN sequence from the certificate The latter three changes work because Android never performs any PKI operations with the certificate. There is no CA certificate chain. The X.509 certificate file is nothing more than a way to transport an RSA public key. avbroot requires the user's key to be RSA 4096. If the original zip had the same key size, then none of these shrinking methods are needed. If it contained an RSA 2048 key, then the first two modifications are usually sufficient. The latter two modifications should only be needed if the user picked a really long subject value when generating the certificate. With these new changes, the OTA patching time will approximately double on a system with an SSD and modern CPU. This is dominated by the time it takes to XZ-compress the system partition image. The compression is already parallelized and scales linearly with the number of cores. There's likely not much more that can be done to further speed this up. Finally, these new changes are currently excluded from the e2e tests because including the system partition in the stripped OTAs would increase the file size by an order of magnitude. This could potentially be solved in the future by generating our own small OTAs to use for testing instead of running against real device OTAs. Fixes: #225 Signed-off-by: Andrew Gunnerson <[email protected]>
Closes: #216 Signed-off-by: Andrew Gunnerson <[email protected]>
The December 2023 Pixel OTA update added support for a "repair mode". I'd like to investigate to see if this has any impact to how things are signed for AVB.
The feature is not open source. There are parts of the implementation in
/system_ext/priv-app/SettingsGoogle
and/system_ext/app/RepairMode
. At first glance, it seems to be implemented on top of Android's DSU mechanism.The text was updated successfully, but these errors were encountered: