Loading fs_mgr/fs_mgr.cpp +14 −0 Original line number Diff line number Diff line Loading @@ -1090,6 +1090,13 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { // Skips mounting the device. continue; } } else if (!current_entry.avb_key.empty()) { if (AvbHandle::SetUpStandaloneAvbHashtree(¤t_entry) == AvbHashtreeResult::kFail) { LERROR << "Failed to set up AVB on standalone partition: " << current_entry.mount_point << ", skipping!"; // Skips mounting the device. continue; } } else if ((current_entry.fs_mgr_flags.verify)) { int rc = fs_mgr_setup_verity(¤t_entry, true); if (__android_log_is_debuggable() && Loading Loading @@ -1326,6 +1333,13 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, // Skips mounting the device. continue; } } else if (!fstab_entry.avb_key.empty()) { if (AvbHandle::SetUpStandaloneAvbHashtree(&fstab_entry) == AvbHashtreeResult::kFail) { LERROR << "Failed to set up AVB on standalone partition: " << fstab_entry.mount_point << ", skipping!"; // Skips mounting the device. continue; } } else if (fstab_entry.fs_mgr_flags.verify) { int rc = fs_mgr_setup_verity(&fstab_entry, true); if (__android_log_is_debuggable() && Loading fs_mgr/fs_mgr_fstab.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -338,6 +338,8 @@ static void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { } else if (StartsWith(flag, "zram_backing_dev_path=")) { entry->fs_mgr_flags.zram_backing_dev_path = true; entry->zram_backing_dev_path = arg; } else if (StartsWith(flag, "avb_key=")) { entry->avb_key = arg; } else { LWARNING << "Warning: unknown flag: " << flag; } Loading fs_mgr/include_fstab/fstab/fstab.h +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ struct FstabEntry { std::string zram_loopback_path; uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default; std::string zram_backing_dev_path; std::string avb_key; // TODO: Remove this union once fstab_rec is deprecated. It only serves as a // convenient way to convert between fstab_rec::fs_mgr_flags and these bools. Loading fs_mgr/libfs_avb/avb_util.cpp +138 −49 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "util.h" using android::base::Basename; using android::base::StartsWith; using android::base::unique_fd; Loading Loading @@ -61,7 +62,7 @@ std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) { // class VBMetaData // ---------------- std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) { auto vbmeta_header(std::make_unique<AvbVBMetaImageHeader>()); auto vbmeta_header = std::make_unique<AvbVBMetaImageHeader>(); if (!vbmeta_header) return nullptr; Loading Loading @@ -136,7 +137,7 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& } table.set_readonly(true); const std::string mount_point(basename(fstab_entry->mount_point.c_str())); const std::string mount_point(Basename(fstab_entry->mount_point)); android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); if (!dm.CreateDevice(mount_point, table)) { LERROR << "Couldn't create verity device!"; Loading @@ -163,12 +164,12 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& return true; } bool GetHashtreeDescriptor(const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, std::string* out_digest) { std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor( const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, std::string* out_salt, std::string* out_digest) { bool found = false; const uint8_t* desc_partition_name; auto hashtree_desc = std::make_unique<AvbHashtreeDescriptor>(); for (const auto& vbmeta : vbmeta_images) { size_t num_descriptors; Loading @@ -189,15 +190,15 @@ bool GetHashtreeDescriptor(const std::string& partition_name, desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashtreeDescriptor); if (!avb_hashtree_descriptor_validate_and_byteswap( (AvbHashtreeDescriptor*)descriptors[n], out_hashtree_desc)) { (AvbHashtreeDescriptor*)descriptors[n], hashtree_desc.get())) { continue; } if (out_hashtree_desc->partition_name_len != partition_name.length()) { if (hashtree_desc->partition_name_len != partition_name.length()) { continue; } // Notes that desc_partition_name is not NUL-terminated. std::string hashtree_partition_name((const char*)desc_partition_name, out_hashtree_desc->partition_name_len); hashtree_desc->partition_name_len); if (hashtree_partition_name == partition_name) { found = true; } Loading @@ -209,16 +210,43 @@ bool GetHashtreeDescriptor(const std::string& partition_name, if (!found) { LERROR << "Partition descriptor not found: " << partition_name.c_str(); return false; return nullptr; } const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len; *out_salt = BytesToHex(desc_salt, out_hashtree_desc->salt_len); const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len; *out_salt = BytesToHex(desc_salt, hashtree_desc->salt_len); const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len; *out_digest = BytesToHex(desc_digest, out_hashtree_desc->root_digest_len); const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len; *out_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len); return true; return hashtree_desc; } bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev, const std::vector<VBMetaData>& vbmeta_images, const std::string& ab_suffix, const std::string& ab_other_suffix) { // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix. std::string partition_name = DeriveAvbPartitionName(*fstab_entry, ab_suffix, ab_other_suffix); if (partition_name.empty()) { LERROR << "partition name is empty, cannot lookup AVB descriptors"; return false; } std::string salt; std::string root_digest; std::unique_ptr<AvbHashtreeDescriptor> hashtree_descriptor = GetHashtreeDescriptor(partition_name, vbmeta_images, &salt, &root_digest); if (!hashtree_descriptor) { return false; } // Converts HASHTREE descriptor to verity table to load into kernel. // When success, the new device path will be returned, e.g., /dev/block/dm-2. return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, salt, root_digest, wait_for_verity_dev); } // Converts a AVB partition_name (without A/B suffix) to a device partition name. Loading @@ -244,6 +272,38 @@ std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name, return sanitized_partition_name + append_suffix; } // Converts fstab_entry.blk_device (with ab_suffix) to a AVB partition name. // e.g., "/dev/block/by-name/system_a", slot_select => "system", // "/dev/block/by-name/system_b", slot_select_other => "system_other". // // Or for a logical partition (with ab_suffix): // e.g., "system_a", slot_select => "system", // "system_b", slot_select_other => "system_other". std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix, const std::string& ab_other_suffix) { std::string partition_name; if (fstab_entry.fs_mgr_flags.logical) { partition_name = fstab_entry.logical_partition_name; } else { partition_name = Basename(fstab_entry.blk_device); } if (fstab_entry.fs_mgr_flags.slot_select) { auto found = partition_name.rfind(ab_suffix); if (found != std::string::npos) { partition_name.erase(found); // converts system_a => system } } else if (fstab_entry.fs_mgr_flags.slot_select_other) { auto found = partition_name.rfind(ab_other_suffix); if (found != std::string::npos) { partition_name.erase(found); // converts system_b => system } partition_name += "_other"; // converts system => system_other } return partition_name; } off64_t GetTotalSize(int fd) { off64_t saved_current = lseek64(fd, 0, SEEK_CUR); if (saved_current == -1) { Loading @@ -268,19 +328,19 @@ off64_t GetTotalSize(int fd) { std::unique_ptr<AvbFooter> GetAvbFooter(int fd) { std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf; auto footer(std::make_unique<AvbFooter>()); auto footer = std::make_unique<AvbFooter>(); off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE; ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset)); if (num_read < 0 || num_read != AVB_FOOTER_SIZE) { PERROR << "Failed to read AVB footer"; PERROR << "Failed to read AVB footer at offset: " << footer_offset; return nullptr; } if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) { PERROR << "AVB footer verification failed."; PERROR << "AVB footer verification failed at offset " << footer_offset; return nullptr; } Loading Loading @@ -432,24 +492,22 @@ std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fat return chain_partitions; } VBMetaVerifyResult LoadAndVerifyVbmetaImpl( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_blob, bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection, std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) { // Loads the vbmeta from a given path. std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath( const std::string& image_path, const std::string& partition_name, const std::string& expected_public_key_blob, bool allow_verification_error, bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result) { // Ensures the device path (might be a symlink created by init) is ready to access. auto device_path = device_path_constructor( AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix)); if (!WaitForFile(device_path, 1s)) { PERROR << "No such partition: " << device_path; return VBMetaVerifyResult::kError; if (!WaitForFile(image_path, 1s)) { PERROR << "No such path: " << image_path; return nullptr; } unique_fd fd(TEMP_FAILURE_RETRY(open(device_path.c_str(), O_RDONLY | O_CLOEXEC))); unique_fd fd(TEMP_FAILURE_RETRY(open(image_path.c_str(), O_RDONLY | O_CLOEXEC))); if (fd < 0) { PERROR << "Failed to open: " << device_path; return VBMetaVerifyResult::kError; PERROR << "Failed to open: " << image_path; return nullptr; } VBMetaVerifyResult verify_result; Loading @@ -457,49 +515,80 @@ VBMetaVerifyResult LoadAndVerifyVbmetaImpl( VerifyVBMetaData(fd, partition_name, expected_public_key_blob, &verify_result); if (!vbmeta) { LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result; return VBMetaVerifyResult::kError; return nullptr; } vbmeta->set_vbmeta_path(image_path); if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) { LERROR << partition_name << ": allow verification error is not allowed"; return VBMetaVerifyResult::kError; return nullptr; } std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header = vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */); if (!vbmeta_header) { LERROR << partition_name << ": Failed to get vbmeta header"; return VBMetaVerifyResult::kError; return nullptr; } if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) { return VBMetaVerifyResult::kError; return nullptr; } // vbmeta flags can only be set by the top-level vbmeta image. if (is_chained_vbmeta && vbmeta_header->flags != 0) { LERROR << partition_name << ": chained vbmeta image has non-zero flags"; return VBMetaVerifyResult::kError; } if (out_vbmeta_images) { out_vbmeta_images->emplace_back(std::move(*vbmeta)); return nullptr; } // If verification has been disabled by setting a bit in the image, we're done. // Checks if verification has been disabled by setting a bit in the image. if (out_verification_disabled) { if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) { LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name; return verify_result; *out_verification_disabled = true; } else { *out_verification_disabled = false; } } if (out_verify_result) { *out_verify_result = verify_result; } return vbmeta; } VBMetaVerifyResult LoadAndVerifyVbmetaByPartition( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_blob, bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection, std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) { auto image_path = device_path_constructor( AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix)); bool verification_disabled = false; VBMetaVerifyResult verify_result; auto vbmeta = LoadAndVerifyVbmetaByPath( image_path, partition_name, expected_public_key_blob, allow_verification_error, rollback_protection, is_chained_vbmeta, &verification_disabled, &verify_result); if (!vbmeta) { return VBMetaVerifyResult::kError; } if (out_vbmeta_images) { out_vbmeta_images->emplace_back(std::move(*vbmeta)); } if (load_chained_vbmeta) { // Only loads chained vbmeta if AVB verification is NOT disabled. if (!verification_disabled && load_chained_vbmeta) { bool fatal_error = false; auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error); if (fatal_error) { return VBMetaVerifyResult::kError; } for (auto& chain : chain_partitions) { auto sub_ret = LoadAndVerifyVbmetaImpl( auto sub_ret = LoadAndVerifyVbmetaByPartition( chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob, allow_verification_error, load_chained_vbmeta, rollback_protection, device_path_constructor, true, /* is_chained_vbmeta */ Loading fs_mgr/libfs_avb/avb_util.h +29 −11 Original line number Diff line number Diff line Loading @@ -46,10 +46,9 @@ struct ChainInfo { }; // AvbHashtreeDescriptor to dm-verity table setup. bool GetHashtreeDescriptor(const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, std::string* out_digest); std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor( const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, std::string* out_salt, std::string* out_digest); bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt, const std::string& root_digest, const std::string& blk_device, Loading @@ -59,11 +58,20 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& const std::string& salt, const std::string& root_digest, bool wait_for_verity_dev); // Maps AVB partition name to a device partition name. // Searches a Avb hashtree descriptor in vbmeta_images for fstab_entry, to enable dm-verity. bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev, const std::vector<VBMetaData>& vbmeta_images, const std::string& ab_suffix, const std::string& ab_other_suffix); // Converts AVB partition name to a device partition name. std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix); // Converts by-name symlink to AVB partition name. std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix, const std::string& ab_other_suffix); // AvbFooter and AvbMetaImage maninpulations. off64_t GetTotalSize(int fd); Loading @@ -84,12 +92,22 @@ bool RollbackDetected(const std::string& partition_name, uint64_t rollback_index // Extracts chain partition info. std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error); VBMetaVerifyResult LoadAndVerifyVbmetaImpl( // Loads the single vbmeta from a given path. std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath( const std::string& image_path, const std::string& partition_name, const std::string& expected_public_key_blob, bool allow_verification_error, bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result); // Loads the top-level vbmeta and all its chained vbmeta images. // The actual device path is constructed at runtime by: // partition_name, ab_suffix, ab_other_suffix, and device_path_constructor. VBMetaVerifyResult LoadAndVerifyVbmetaByPartition( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_blob, bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection, std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images); std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images); } // namespace fs_mgr } // namespace android Loading
fs_mgr/fs_mgr.cpp +14 −0 Original line number Diff line number Diff line Loading @@ -1090,6 +1090,13 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { // Skips mounting the device. continue; } } else if (!current_entry.avb_key.empty()) { if (AvbHandle::SetUpStandaloneAvbHashtree(¤t_entry) == AvbHashtreeResult::kFail) { LERROR << "Failed to set up AVB on standalone partition: " << current_entry.mount_point << ", skipping!"; // Skips mounting the device. continue; } } else if ((current_entry.fs_mgr_flags.verify)) { int rc = fs_mgr_setup_verity(¤t_entry, true); if (__android_log_is_debuggable() && Loading Loading @@ -1326,6 +1333,13 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, // Skips mounting the device. continue; } } else if (!fstab_entry.avb_key.empty()) { if (AvbHandle::SetUpStandaloneAvbHashtree(&fstab_entry) == AvbHashtreeResult::kFail) { LERROR << "Failed to set up AVB on standalone partition: " << fstab_entry.mount_point << ", skipping!"; // Skips mounting the device. continue; } } else if (fstab_entry.fs_mgr_flags.verify) { int rc = fs_mgr_setup_verity(&fstab_entry, true); if (__android_log_is_debuggable() && Loading
fs_mgr/fs_mgr_fstab.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -338,6 +338,8 @@ static void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { } else if (StartsWith(flag, "zram_backing_dev_path=")) { entry->fs_mgr_flags.zram_backing_dev_path = true; entry->zram_backing_dev_path = arg; } else if (StartsWith(flag, "avb_key=")) { entry->avb_key = arg; } else { LWARNING << "Warning: unknown flag: " << flag; } Loading
fs_mgr/include_fstab/fstab/fstab.h +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ struct FstabEntry { std::string zram_loopback_path; uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default; std::string zram_backing_dev_path; std::string avb_key; // TODO: Remove this union once fstab_rec is deprecated. It only serves as a // convenient way to convert between fstab_rec::fs_mgr_flags and these bools. Loading
fs_mgr/libfs_avb/avb_util.cpp +138 −49 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "util.h" using android::base::Basename; using android::base::StartsWith; using android::base::unique_fd; Loading Loading @@ -61,7 +62,7 @@ std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) { // class VBMetaData // ---------------- std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) { auto vbmeta_header(std::make_unique<AvbVBMetaImageHeader>()); auto vbmeta_header = std::make_unique<AvbVBMetaImageHeader>(); if (!vbmeta_header) return nullptr; Loading Loading @@ -136,7 +137,7 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& } table.set_readonly(true); const std::string mount_point(basename(fstab_entry->mount_point.c_str())); const std::string mount_point(Basename(fstab_entry->mount_point)); android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); if (!dm.CreateDevice(mount_point, table)) { LERROR << "Couldn't create verity device!"; Loading @@ -163,12 +164,12 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& return true; } bool GetHashtreeDescriptor(const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, std::string* out_digest) { std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor( const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, std::string* out_salt, std::string* out_digest) { bool found = false; const uint8_t* desc_partition_name; auto hashtree_desc = std::make_unique<AvbHashtreeDescriptor>(); for (const auto& vbmeta : vbmeta_images) { size_t num_descriptors; Loading @@ -189,15 +190,15 @@ bool GetHashtreeDescriptor(const std::string& partition_name, desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashtreeDescriptor); if (!avb_hashtree_descriptor_validate_and_byteswap( (AvbHashtreeDescriptor*)descriptors[n], out_hashtree_desc)) { (AvbHashtreeDescriptor*)descriptors[n], hashtree_desc.get())) { continue; } if (out_hashtree_desc->partition_name_len != partition_name.length()) { if (hashtree_desc->partition_name_len != partition_name.length()) { continue; } // Notes that desc_partition_name is not NUL-terminated. std::string hashtree_partition_name((const char*)desc_partition_name, out_hashtree_desc->partition_name_len); hashtree_desc->partition_name_len); if (hashtree_partition_name == partition_name) { found = true; } Loading @@ -209,16 +210,43 @@ bool GetHashtreeDescriptor(const std::string& partition_name, if (!found) { LERROR << "Partition descriptor not found: " << partition_name.c_str(); return false; return nullptr; } const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len; *out_salt = BytesToHex(desc_salt, out_hashtree_desc->salt_len); const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len; *out_salt = BytesToHex(desc_salt, hashtree_desc->salt_len); const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len; *out_digest = BytesToHex(desc_digest, out_hashtree_desc->root_digest_len); const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len; *out_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len); return true; return hashtree_desc; } bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev, const std::vector<VBMetaData>& vbmeta_images, const std::string& ab_suffix, const std::string& ab_other_suffix) { // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix. std::string partition_name = DeriveAvbPartitionName(*fstab_entry, ab_suffix, ab_other_suffix); if (partition_name.empty()) { LERROR << "partition name is empty, cannot lookup AVB descriptors"; return false; } std::string salt; std::string root_digest; std::unique_ptr<AvbHashtreeDescriptor> hashtree_descriptor = GetHashtreeDescriptor(partition_name, vbmeta_images, &salt, &root_digest); if (!hashtree_descriptor) { return false; } // Converts HASHTREE descriptor to verity table to load into kernel. // When success, the new device path will be returned, e.g., /dev/block/dm-2. return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, salt, root_digest, wait_for_verity_dev); } // Converts a AVB partition_name (without A/B suffix) to a device partition name. Loading @@ -244,6 +272,38 @@ std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name, return sanitized_partition_name + append_suffix; } // Converts fstab_entry.blk_device (with ab_suffix) to a AVB partition name. // e.g., "/dev/block/by-name/system_a", slot_select => "system", // "/dev/block/by-name/system_b", slot_select_other => "system_other". // // Or for a logical partition (with ab_suffix): // e.g., "system_a", slot_select => "system", // "system_b", slot_select_other => "system_other". std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix, const std::string& ab_other_suffix) { std::string partition_name; if (fstab_entry.fs_mgr_flags.logical) { partition_name = fstab_entry.logical_partition_name; } else { partition_name = Basename(fstab_entry.blk_device); } if (fstab_entry.fs_mgr_flags.slot_select) { auto found = partition_name.rfind(ab_suffix); if (found != std::string::npos) { partition_name.erase(found); // converts system_a => system } } else if (fstab_entry.fs_mgr_flags.slot_select_other) { auto found = partition_name.rfind(ab_other_suffix); if (found != std::string::npos) { partition_name.erase(found); // converts system_b => system } partition_name += "_other"; // converts system => system_other } return partition_name; } off64_t GetTotalSize(int fd) { off64_t saved_current = lseek64(fd, 0, SEEK_CUR); if (saved_current == -1) { Loading @@ -268,19 +328,19 @@ off64_t GetTotalSize(int fd) { std::unique_ptr<AvbFooter> GetAvbFooter(int fd) { std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf; auto footer(std::make_unique<AvbFooter>()); auto footer = std::make_unique<AvbFooter>(); off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE; ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset)); if (num_read < 0 || num_read != AVB_FOOTER_SIZE) { PERROR << "Failed to read AVB footer"; PERROR << "Failed to read AVB footer at offset: " << footer_offset; return nullptr; } if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) { PERROR << "AVB footer verification failed."; PERROR << "AVB footer verification failed at offset " << footer_offset; return nullptr; } Loading Loading @@ -432,24 +492,22 @@ std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fat return chain_partitions; } VBMetaVerifyResult LoadAndVerifyVbmetaImpl( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_blob, bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection, std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) { // Loads the vbmeta from a given path. std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath( const std::string& image_path, const std::string& partition_name, const std::string& expected_public_key_blob, bool allow_verification_error, bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result) { // Ensures the device path (might be a symlink created by init) is ready to access. auto device_path = device_path_constructor( AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix)); if (!WaitForFile(device_path, 1s)) { PERROR << "No such partition: " << device_path; return VBMetaVerifyResult::kError; if (!WaitForFile(image_path, 1s)) { PERROR << "No such path: " << image_path; return nullptr; } unique_fd fd(TEMP_FAILURE_RETRY(open(device_path.c_str(), O_RDONLY | O_CLOEXEC))); unique_fd fd(TEMP_FAILURE_RETRY(open(image_path.c_str(), O_RDONLY | O_CLOEXEC))); if (fd < 0) { PERROR << "Failed to open: " << device_path; return VBMetaVerifyResult::kError; PERROR << "Failed to open: " << image_path; return nullptr; } VBMetaVerifyResult verify_result; Loading @@ -457,49 +515,80 @@ VBMetaVerifyResult LoadAndVerifyVbmetaImpl( VerifyVBMetaData(fd, partition_name, expected_public_key_blob, &verify_result); if (!vbmeta) { LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result; return VBMetaVerifyResult::kError; return nullptr; } vbmeta->set_vbmeta_path(image_path); if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) { LERROR << partition_name << ": allow verification error is not allowed"; return VBMetaVerifyResult::kError; return nullptr; } std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header = vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */); if (!vbmeta_header) { LERROR << partition_name << ": Failed to get vbmeta header"; return VBMetaVerifyResult::kError; return nullptr; } if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) { return VBMetaVerifyResult::kError; return nullptr; } // vbmeta flags can only be set by the top-level vbmeta image. if (is_chained_vbmeta && vbmeta_header->flags != 0) { LERROR << partition_name << ": chained vbmeta image has non-zero flags"; return VBMetaVerifyResult::kError; } if (out_vbmeta_images) { out_vbmeta_images->emplace_back(std::move(*vbmeta)); return nullptr; } // If verification has been disabled by setting a bit in the image, we're done. // Checks if verification has been disabled by setting a bit in the image. if (out_verification_disabled) { if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) { LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name; return verify_result; *out_verification_disabled = true; } else { *out_verification_disabled = false; } } if (out_verify_result) { *out_verify_result = verify_result; } return vbmeta; } VBMetaVerifyResult LoadAndVerifyVbmetaByPartition( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_blob, bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection, std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) { auto image_path = device_path_constructor( AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix)); bool verification_disabled = false; VBMetaVerifyResult verify_result; auto vbmeta = LoadAndVerifyVbmetaByPath( image_path, partition_name, expected_public_key_blob, allow_verification_error, rollback_protection, is_chained_vbmeta, &verification_disabled, &verify_result); if (!vbmeta) { return VBMetaVerifyResult::kError; } if (out_vbmeta_images) { out_vbmeta_images->emplace_back(std::move(*vbmeta)); } if (load_chained_vbmeta) { // Only loads chained vbmeta if AVB verification is NOT disabled. if (!verification_disabled && load_chained_vbmeta) { bool fatal_error = false; auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error); if (fatal_error) { return VBMetaVerifyResult::kError; } for (auto& chain : chain_partitions) { auto sub_ret = LoadAndVerifyVbmetaImpl( auto sub_ret = LoadAndVerifyVbmetaByPartition( chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob, allow_verification_error, load_chained_vbmeta, rollback_protection, device_path_constructor, true, /* is_chained_vbmeta */ Loading
fs_mgr/libfs_avb/avb_util.h +29 −11 Original line number Diff line number Diff line Loading @@ -46,10 +46,9 @@ struct ChainInfo { }; // AvbHashtreeDescriptor to dm-verity table setup. bool GetHashtreeDescriptor(const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, std::string* out_digest); std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor( const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images, std::string* out_salt, std::string* out_digest); bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt, const std::string& root_digest, const std::string& blk_device, Loading @@ -59,11 +58,20 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& const std::string& salt, const std::string& root_digest, bool wait_for_verity_dev); // Maps AVB partition name to a device partition name. // Searches a Avb hashtree descriptor in vbmeta_images for fstab_entry, to enable dm-verity. bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev, const std::vector<VBMetaData>& vbmeta_images, const std::string& ab_suffix, const std::string& ab_other_suffix); // Converts AVB partition name to a device partition name. std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix); // Converts by-name symlink to AVB partition name. std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix, const std::string& ab_other_suffix); // AvbFooter and AvbMetaImage maninpulations. off64_t GetTotalSize(int fd); Loading @@ -84,12 +92,22 @@ bool RollbackDetected(const std::string& partition_name, uint64_t rollback_index // Extracts chain partition info. std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error); VBMetaVerifyResult LoadAndVerifyVbmetaImpl( // Loads the single vbmeta from a given path. std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath( const std::string& image_path, const std::string& partition_name, const std::string& expected_public_key_blob, bool allow_verification_error, bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result); // Loads the top-level vbmeta and all its chained vbmeta images. // The actual device path is constructed at runtime by: // partition_name, ab_suffix, ab_other_suffix, and device_path_constructor. VBMetaVerifyResult LoadAndVerifyVbmetaByPartition( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_blob, bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection, std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images); std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images); } // namespace fs_mgr } // namespace android