system/core
修訂 | 7a4fb7a435459222b718ceb4607fb0577a7ed8a9 (tree) |
---|---|
時間 | 2019-04-11 10:44:13 |
作者 | Bowgo Tsai <bowgotsai@goog...> |
Commiter | Bowgo Tsai |
first-stage mount: support using other avb_keys
This change allows specifying additional avb keys to verify a fstab
entry. It can be used together with the original 'avb' flag. When both
'avb' and 'avb_keys' are present, it will try to use avb_keys to verify
this partition and extract the AVB descriptor from the end of it first.
When avb_key fails, it falls back to searching the AVB descriptor in the
built-in /vbmeta (and its chained partitions) with the matched partition
name.
An example of a fstab file:
system /system ext4 ro,barrier=1 wait,slotselect,avb=vbmeta,logical,first_stage_mount,avb_keys=/avb/gsi.avbpubkey
vendor /vendor ext4 ro,barrier=1 wait,slotselect,avb,logical,first_stage_mount
The overhead of adding an additional 'avb_keys' should not be significant,
as the typical size of a AVB Hashtree descriptor for /system is usually
less than 1000 bytes. e.g., on crosshatch, it's about 600 bytes, which
takes less than 1 millisecond for the following call to return failure.
We also checked the time spent on init's first stage on crosshatch, with the
following CL to set ro.boottime.init.first_stage. The testing result
shows no significant difference between them as well.
https://android-review.googlesource.com/c/platform/system/core/+/934536
With an additional avb_keys entry for /system
Without an additional avb_keys entry for /system
Bug: 124491153
Test: boot a device with above fstab settings
Change-Id: I0c81f816efb0dd40c93da2df304f2e215df9d105
Merged-In: I0c81f816efb0dd40c93da2df304f2e215df9d105
(cherry picked from commit a0f8b05d913855e3d8e9836f124fc9fdc755d450)
@@ -80,7 +80,7 @@ class FirstStageMount { | ||
80 | 80 | bool InitMappedDevice(const std::string& verity_device); |
81 | 81 | bool InitDeviceMapper(); |
82 | 82 | bool CreateLogicalPartitions(); |
83 | - bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry, | |
83 | + bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, | |
84 | 84 | Fstab::iterator* end = nullptr); |
85 | 85 | |
86 | 86 | bool MountPartitions(); |
@@ -437,21 +437,26 @@ bool FirstStageMount::InitMappedDevice(const std::string& dm_device) { | ||
437 | 437 | |
438 | 438 | uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback); |
439 | 439 | if (!found) { |
440 | - LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent"; | |
440 | + LOG(INFO) << "dm device '" << dm_device << "' not found in /sys, waiting for its uevent"; | |
441 | 441 | Timer t; |
442 | 442 | uevent_listener_.Poll(verity_callback, 10s); |
443 | - LOG(INFO) << "wait for dm-verity device returned after " << t; | |
443 | + LOG(INFO) << "wait for dm device '" << dm_device << "' returned after " << t; | |
444 | 444 | } |
445 | 445 | if (!found) { |
446 | - LOG(ERROR) << "dm-verity device not found after polling timeout"; | |
446 | + LOG(ERROR) << "dm device '" << dm_device << "' not found after polling timeout"; | |
447 | 447 | return false; |
448 | 448 | } |
449 | 449 | |
450 | 450 | return true; |
451 | 451 | } |
452 | 452 | |
453 | -bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry, | |
453 | +bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, | |
454 | 454 | Fstab::iterator* end) { |
455 | + // Sets end to begin + 1, so we can just return on failure below. | |
456 | + if (end) { | |
457 | + *end = begin + 1; | |
458 | + } | |
459 | + | |
455 | 460 | if (begin->fs_mgr_flags.logical) { |
456 | 461 | if (!fs_mgr_update_logical_partition(&(*begin))) { |
457 | 462 | return false; |
@@ -477,7 +482,7 @@ bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_us | ||
477 | 482 | mounted = (fs_mgr_do_mount_one(*current) == 0); |
478 | 483 | } |
479 | 484 | } |
480 | - if (erase_used_fstab_entry) { | |
485 | + if (erase_same_mounts) { | |
481 | 486 | current = fstab_.erase(begin, current); |
482 | 487 | } |
483 | 488 | if (end) { |
@@ -494,7 +499,7 @@ bool FirstStageMount::TrySwitchSystemAsRoot() { | ||
494 | 499 | return entry.mount_point == "/metadata"; |
495 | 500 | }); |
496 | 501 | if (metadata_partition != fstab_.end()) { |
497 | - if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) { | |
502 | + if (MountPartition(metadata_partition, true /* erase_same_mounts */)) { | |
498 | 503 | UseGsiIfPresent(); |
499 | 504 | } |
500 | 505 | } |
@@ -505,7 +510,7 @@ bool FirstStageMount::TrySwitchSystemAsRoot() { | ||
505 | 510 | |
506 | 511 | if (system_partition == fstab_.end()) return true; |
507 | 512 | |
508 | - if (MountPartition(system_partition, false)) { | |
513 | + if (MountPartition(system_partition, false /* erase_same_mounts */)) { | |
509 | 514 | if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) { |
510 | 515 | LOG(ERROR) << "check_most_at_once forbidden on external media"; |
511 | 516 | return false; |
@@ -560,7 +565,7 @@ bool FirstStageMount::MountPartitions() { | ||
560 | 565 | } |
561 | 566 | |
562 | 567 | Fstab::iterator end; |
563 | - if (!MountPartition(current, false, &end)) { | |
568 | + if (!MountPartition(current, false /* erase_same_mounts */, &end)) { | |
564 | 569 | if (current->fs_mgr_flags.no_fail) { |
565 | 570 | LOG(INFO) << "Failed to mount " << current->mount_point |
566 | 571 | << ", ignoring mount for no_fail partition"; |
@@ -797,11 +802,9 @@ bool FirstStageMountVBootV2::GetDmVerityDevices() { | ||
797 | 802 | bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) { |
798 | 803 | AvbHashtreeResult hashtree_result; |
799 | 804 | |
800 | - if (fstab_entry->fs_mgr_flags.avb) { | |
801 | - if (!InitAvbHandle()) return false; | |
802 | - hashtree_result = | |
803 | - avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */); | |
804 | - } else if (!fstab_entry->avb_keys.empty()) { | |
805 | + // It's possible for a fstab_entry to have both avb_keys and avb flag. | |
806 | + // In this case, try avb_keys first, then fallback to avb flag. | |
807 | + if (!fstab_entry->avb_keys.empty()) { | |
805 | 808 | if (!InitAvbHandle()) return false; |
806 | 809 | // Checks if hashtree should be disabled from the top-level /vbmeta. |
807 | 810 | if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled || |
@@ -813,14 +816,24 @@ bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) { | ||
813 | 816 | auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry); |
814 | 817 | if (!avb_standalone_handle) { |
815 | 818 | LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point; |
816 | - return false; | |
817 | - } | |
818 | - if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) { | |
819 | - return false; | |
819 | + // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set. | |
820 | + if (!fstab_entry->fs_mgr_flags.avb) return false; | |
821 | + LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point; | |
822 | + hashtree_result = | |
823 | + avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */); | |
824 | + } else { | |
825 | + // Sets up hashtree via the standalone handle. | |
826 | + if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) { | |
827 | + return false; | |
828 | + } | |
829 | + hashtree_result = avb_standalone_handle->SetUpAvbHashtree( | |
830 | + fstab_entry, false /* wait_for_verity_dev */); | |
820 | 831 | } |
821 | - hashtree_result = avb_standalone_handle->SetUpAvbHashtree( | |
822 | - fstab_entry, false /* wait_for_verity_dev */); | |
823 | 832 | } |
833 | + } else if (fstab_entry->fs_mgr_flags.avb) { | |
834 | + if (!InitAvbHandle()) return false; | |
835 | + hashtree_result = | |
836 | + avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */); | |
824 | 837 | } else { |
825 | 838 | return true; // No need AVB, returns true to mount the partition directly. |
826 | 839 | } |