diff options
author | Bowgo Tsai <bowgotsai@google.com> | 2017-03-30 18:42:54 +0800 |
---|---|---|
committer | Bowgo Tsai <bowgotsai@google.com> | 2017-04-13 18:28:53 +0800 |
commit | 95c966a8599a069c40707c933c31155d625bd355 (patch) | |
tree | 4a5f2e7642cde674fe8f6b4b0fc428001d891c18 /fs_mgr | |
parent | 87d0836cda90b33ee97d63ef61a10dd23d82581a (diff) | |
download | core-95c966a8599a069c40707c933c31155d625bd355.tar.gz core-95c966a8599a069c40707c933c31155d625bd355.tar.bz2 core-95c966a8599a069c40707c933c31155d625bd355.zip |
fs_mgr_avb: refactors how vbmeta is loaded
Adds two classes FsManagerAvbhandle and FsManagerAvbVerifier to replace the
following functions or struct:
- fs_mgr_load_vbmeta_images() -> FsManagerAvbhandle::Open()
- fs_mgr_unload_vbmeta_images() -> deleted
- fs_mgr_setup_avb() -> FsManagerAvbhandle::SetUpAvb()
- androidboot_vbmeta -> FsManagerAvbVerifier
- load_vbmeta_prop() -> FsManagerAvbVerifier::Create()
- verify_vbmeta_images() -> FsManagerAvbVerifier::VerifyVbmetaImages()
And only invokes FsManagerAvbhandle::Open() when there is a fstab entry having
'avb' flag (need HASHTREE descriptor). fs_mgr_is_avb_used() can be
removed as it only checks system property "ro.boot.vbmeta.hash_alg" to
decide whether vbmeta needs to be loaded, which might not be accurate.
For example, there are only HASH descriptors in the verified chain but
no HASHTREE descriptors. In this case, the fs_mgr doesn't have to do
anything because it only takes care of HASHTREE descriptors.
Also adds a new class FsManagerAvbOps to provide the C++ binding
FsManagerAvbOps::AvbSlotVerify() for libavb->avb_slot_verify().
Bug: 33254008
Test: test AVB on bullhead
Change-Id: I8fe15ba01c277152630a2a5c1c5c7f25fbf34030
Diffstat (limited to 'fs_mgr')
-rw-r--r-- | fs_mgr/fs_mgr.cpp | 76 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_avb.cpp | 258 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_avb_ops.cpp | 176 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_avb_ops.h | 57 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_priv_avb.h | 89 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_priv_sha.h | 12 |
6 files changed, 331 insertions, 337 deletions
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 120129c50..78d0c070f 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -707,6 +707,23 @@ static int handle_encryptable(const struct fstab_rec* rec) } } +static std::string extract_by_name_prefix(struct fstab* fstab) { + // We assume that there's an entry for the /misc mount point in the + // fstab file and use that to get the device file by-name prefix. + // The device needs not to have an actual /misc partition. + // e.g., + // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc -> + // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ + struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc"); + if (fstab_entry == nullptr) { + LERROR << "/misc mount point not found in fstab"; + return ""; + } + std::string full_path(fstab_entry->blk_device); + size_t end_slash = full_path.find_last_of("/"); + return full_path.substr(0, end_slash + 1); +} + // TODO: add ueventd notifiers if they don't exist. // This is just doing a wait_for_device for maximum of 1s int fs_mgr_test_access(const char *device) { @@ -750,17 +767,12 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) int mret = -1; int mount_errno = 0; int attempted_idx = -1; - int avb_ret = FS_MGR_SETUP_AVB_FAIL; + FsManagerAvbUniquePtr avb_handle(nullptr); if (!fstab) { return -1; } - if (fs_mgr_is_avb_used() && - (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) { - return -1; - } - for (i = 0; i < fstab->num_entries; i++) { /* Don't mount entries that are managed by vold or not for the mount mode*/ if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) || @@ -799,16 +811,15 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); } - if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) { - /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we - * should set up the device without using dm-verity. - * The actual mounting still take place in the following - * mount_with_alternatives(). - */ - if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) { - LINFO << "AVB HASHTREE disabled"; - } else if (fs_mgr_setup_avb(&fstab->recs[i]) != - FS_MGR_SETUP_AVB_SUCCESS) { + if (fstab->recs[i].fs_mgr_flags & MF_AVB) { + if (!avb_handle) { + avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab)); + if (!avb_handle) { + LERROR << "Failed to open FsManagerAvbHandle"; + return -1; + } + } + if (!avb_handle->SetUpAvb(&fstab->recs[i])) { LERROR << "Failed to set up AVB on partition: " << fstab->recs[i].mount_point << ", skipping!"; /* Skips mounting the device. */ @@ -934,10 +945,6 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) } } - if (fs_mgr_is_avb_used()) { - fs_mgr_unload_vbmeta_images(); - } - if (error_count) { return -1; } else { @@ -976,17 +983,12 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, int mount_errors = 0; int first_mount_errno = 0; char *m; - int avb_ret = FS_MGR_SETUP_AVB_FAIL; + FsManagerAvbUniquePtr avb_handle(nullptr); if (!fstab) { return ret; } - if (fs_mgr_is_avb_used() && - (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) { - return ret; - } - for (i = 0; i < fstab->num_entries; i++) { if (!fs_match(fstab->recs[i].mount_point, n_name)) { continue; @@ -1021,16 +1023,15 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat); } - if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) { - /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we - * should set up the device without using dm-verity. - * The actual mounting still take place in the following - * mount_with_alternatives(). - */ - if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) { - LINFO << "AVB HASHTREE disabled"; - } else if (fs_mgr_setup_avb(&fstab->recs[i]) != - FS_MGR_SETUP_AVB_SUCCESS) { + if (fstab->recs[i].fs_mgr_flags & MF_AVB) { + if (!avb_handle) { + avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab)); + if (!avb_handle) { + LERROR << "Failed to open FsManagerAvbHandle"; + return -1; + } + } + if (!avb_handle->SetUpAvb(&fstab->recs[i])) { LERROR << "Failed to set up AVB on partition: " << fstab->recs[i].mount_point << ", skipping!"; /* Skips mounting the device. */ @@ -1079,9 +1080,6 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, } out: - if (fs_mgr_is_avb_used()) { - fs_mgr_unload_vbmeta_images(); - } return ret; } diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp index 3576b9caa..76ec236b5 100644 --- a/fs_mgr/fs_mgr_avb.cpp +++ b/fs_mgr/fs_mgr_avb.cpp @@ -28,6 +28,7 @@ #include <android-base/file.h> #include <android-base/parseint.h> #include <android-base/properties.h> +#include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <cutils/properties.h> @@ -85,24 +86,6 @@ hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_start */ \ VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART -AvbSlotVerifyData* fs_mgr_avb_verify_data = nullptr; -AvbOps* fs_mgr_avb_ops = nullptr; - -enum HashAlgorithm { - kInvalid = 0, - kSHA256 = 1, - kSHA512 = 2, -}; - -struct androidboot_vbmeta { - HashAlgorithm hash_alg; - uint8_t digest[SHA512_DIGEST_LENGTH]; - size_t vbmeta_size; - bool allow_verification_error; -}; - -androidboot_vbmeta fs_mgr_vbmeta_prop; - static inline bool nibble_value(const char& c, uint8_t* value) { FS_MGR_CHECK(value != nullptr); @@ -159,27 +142,78 @@ static std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) { return hex; } -static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) { - FS_MGR_CHECK(vbmeta_prop != nullptr); +template <typename Hasher> +static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data, + const uint8_t* expected_digest) { + size_t total_size = 0; + Hasher hasher; + for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) { + hasher.update(verify_data.vbmeta_images[n].vbmeta_data, + verify_data.vbmeta_images[n].vbmeta_size); + total_size += verify_data.vbmeta_images[n].vbmeta_size; + } + + bool matched = (memcmp(hasher.finalize(), expected_digest, Hasher::DIGEST_SIZE) == 0); + + return std::make_pair(total_size, matched); +} + +// Reads the following values from kernel cmdline and provides the +// VerifyVbmetaImages() to verify AvbSlotVerifyData. +// - androidboot.vbmeta.device_state +// - androidboot.vbmeta.hash_alg +// - androidboot.vbmeta.size +// - androidboot.vbmeta.digest +class FsManagerAvbVerifier { + public: + // The factory method to return a unique_ptr<FsManagerAvbVerifier> + static std::unique_ptr<FsManagerAvbVerifier> Create(); + bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data); + bool IsDeviceUnlocked() { return is_device_unlocked_; } + + protected: + FsManagerAvbVerifier() = default; + + private: + enum HashAlgorithm { + kInvalid = 0, + kSHA256 = 1, + kSHA512 = 2, + }; + + HashAlgorithm hash_alg_; + uint8_t digest_[SHA512_DIGEST_LENGTH]; + size_t vbmeta_size_; + bool is_device_unlocked_; +}; +std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() { std::string cmdline; - android::base::ReadFileToString("/proc/cmdline", &cmdline); + if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) { + LERROR << "Failed to read /proc/cmdline"; + return nullptr; + } - std::string hash_alg; - std::string digest; + std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier()); + if (!avb_verifier) { + LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>"; + return nullptr; + } + std::string digest; + std::string hash_alg; for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) { std::vector<std::string> pieces = android::base::Split(entry, "="); const std::string& key = pieces[0]; const std::string& value = pieces[1]; if (key == "androidboot.vbmeta.device_state") { - vbmeta_prop->allow_verification_error = (value == "unlocked"); + avb_verifier->is_device_unlocked_ = (value == "unlocked"); } else if (key == "androidboot.vbmeta.hash_alg") { hash_alg = value; } else if (key == "androidboot.vbmeta.size") { - if (!android::base::ParseUint(value.c_str(), &vbmeta_prop->vbmeta_size)) { - return false; + if (!android::base::ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) { + return nullptr; } } else if (key == "androidboot.vbmeta.digest") { digest = value; @@ -190,48 +224,31 @@ static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) { size_t expected_digest_size = 0; if (hash_alg == "sha256") { expected_digest_size = SHA256_DIGEST_LENGTH * 2; - vbmeta_prop->hash_alg = kSHA256; + avb_verifier->hash_alg_ = kSHA256; } else if (hash_alg == "sha512") { expected_digest_size = SHA512_DIGEST_LENGTH * 2; - vbmeta_prop->hash_alg = kSHA512; + avb_verifier->hash_alg_ = kSHA512; } else { LERROR << "Unknown hash algorithm: " << hash_alg.c_str(); - return false; + return nullptr; } // Reads digest. if (digest.size() != expected_digest_size) { LERROR << "Unexpected digest size: " << digest.size() << " (expected: " << expected_digest_size << ")"; - return false; + return nullptr; } - if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest), digest)) { + if (!hex_to_bytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) { LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str(); - return false; + return nullptr; } - return true; + return avb_verifier; } -template <typename Hasher> -static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data, - const androidboot_vbmeta& vbmeta_prop) { - size_t total_size = 0; - Hasher hasher; - for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) { - hasher.update(verify_data.vbmeta_images[n].vbmeta_data, - verify_data.vbmeta_images[n].vbmeta_size); - total_size += verify_data.vbmeta_images[n].vbmeta_size; - } - - bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest, Hasher::DIGEST_SIZE) == 0); - - return std::make_pair(total_size, matched); -} - -static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data, - const androidboot_vbmeta& vbmeta_prop) { +bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) { if (verify_data.num_vbmeta_images == 0) { LERROR << "No vbmeta images"; return false; @@ -240,17 +257,17 @@ static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data, size_t total_size = 0; bool digest_matched = false; - if (vbmeta_prop.hash_alg == kSHA256) { + if (hash_alg_ == kSHA256) { std::tie(total_size, digest_matched) = - verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop); - } else if (vbmeta_prop.hash_alg == kSHA512) { + verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_); + } else if (hash_alg_ == kSHA512) { std::tie(total_size, digest_matched) = - verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop); + verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_); } - if (total_size != vbmeta_prop.vbmeta_size) { - LERROR << "total vbmeta size mismatch: " << total_size - << " (expected: " << vbmeta_prop.vbmeta_size << ")"; + if (total_size != vbmeta_size_) { + LERROR << "total vbmeta size mismatch: " << total_size << " (expected: " << vbmeta_size_ + << ")"; return false; } @@ -408,8 +425,7 @@ static bool get_hashtree_descriptor(const std::string& partition_name, continue; } if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) { - desc_partition_name = - (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor); + desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor); if (!avb_hashtree_descriptor_validate_and_byteswap( (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) { continue; @@ -441,134 +457,96 @@ static bool get_hashtree_descriptor(const std::string& partition_name, return true; } -static bool init_is_avb_used() { - // When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg, - // size, digest} in kernel cmdline or in device tree. They will then be - // imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}. - // - // In case of early mount, init properties are not initialized, so we also - // ensure we look into kernel command line and device tree if the property is - // not found - // - // Checks hash_alg as an indicator for whether AVB is used. - // We don't have to parse and check all of them here. The check will - // be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will - // be returned when there is an error. - - std::string hash_alg; - if (!fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg)) { - return false; - } - if (hash_alg == "sha256" || hash_alg == "sha512") { - return true; +FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const std::string& device_file_by_name_prefix) { + if (device_file_by_name_prefix.empty()) { + LERROR << "Missing device file by-name prefix"; + return nullptr; } - return false; -} -bool fs_mgr_is_avb_used() { - static bool result = init_is_avb_used(); - return result; -} - -int fs_mgr_load_vbmeta_images(struct fstab* fstab) { - FS_MGR_CHECK(fstab != nullptr); - - // Gets the expected hash value of vbmeta images from - // kernel cmdline. - if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) { - return FS_MGR_SETUP_AVB_FAIL; + // Gets the expected hash value of vbmeta images from kernel cmdline. + std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create(); + if (!avb_verifier) { + LERROR << "Failed to create FsManagerAvbVerifier"; + return nullptr; } - fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab); - if (fs_mgr_avb_ops == nullptr) { - LERROR << "Failed to allocate dummy avb_ops"; - return FS_MGR_SETUP_AVB_FAIL; + FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle()); + if (!avb_handle) { + LERROR << "Failed to allocate FsManagerAvbHandle"; + return nullptr; } - // Invokes avb_slot_verify() to load and verify all vbmeta images. - // Sets requested_partitions to nullptr as it's to copy the contents - // of HASH partitions into fs_mgr_avb_verify_data, which is not required as - // fs_mgr only deals with HASHTREE partitions. - const char* requested_partitions[] = {nullptr}; - std::string ab_suffix = fs_mgr_get_slot_suffix(); - - AvbSlotVerifyResult verify_result = - avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(), - fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data); + FsManagerAvbOps avb_ops(device_file_by_name_prefix); + AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify( + fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_); // Only allow two verify results: // - AVB_SLOT_VERIFY_RESULT_OK. // - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state). if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) { - if (!fs_mgr_vbmeta_prop.allow_verification_error) { + if (!avb_verifier->IsDeviceUnlocked()) { LERROR << "ERROR_VERIFICATION isn't allowed"; - goto fail; + return nullptr; } } else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) { LERROR << "avb_slot_verify failed, result: " << verify_result; - goto fail; + return nullptr; } // Verifies vbmeta images against the digest passed from bootloader. - if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) { - LERROR << "verify_vbmeta_images failed"; - goto fail; + if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) { + LERROR << "VerifyVbmetaImages failed"; + return nullptr; } else { // Checks whether FLAGS_HASHTREE_DISABLED is set. AvbVBMetaImageHeader vbmeta_header; avb_vbmeta_image_header_to_host_byte_order( - (AvbVBMetaImageHeader*)fs_mgr_avb_verify_data->vbmeta_images[0].vbmeta_data, + (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data, &vbmeta_header); bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED); if (hashtree_disabled) { - return FS_MGR_SETUP_AVB_HASHTREE_DISABLED; + avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled; + return avb_handle; } } if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) { - return FS_MGR_SETUP_AVB_SUCCESS; + avb_handle->status_ = kFsManagerAvbHandleSuccess; + return avb_handle; } - -fail: - fs_mgr_unload_vbmeta_images(); - return FS_MGR_SETUP_AVB_FAIL; + return nullptr; } -void fs_mgr_unload_vbmeta_images() { - if (fs_mgr_avb_verify_data != nullptr) { - avb_slot_verify_data_free(fs_mgr_avb_verify_data); - } - - if (fs_mgr_avb_ops != nullptr) { - fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops); +bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry) { + if (!fstab_entry) return false; + if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) { + return false; } -} - -int fs_mgr_setup_avb(struct fstab_rec* fstab_entry) { - if (!fstab_entry || !fs_mgr_avb_verify_data || fs_mgr_avb_verify_data->num_vbmeta_images < 1) { - return FS_MGR_SETUP_AVB_FAIL; + if (status_ == kFsManagerAvbHandleHashtreeDisabled) { + LINFO << "AVB HASHTREE disabled on:" << fstab_entry->mount_point; + return true; } + if (status_ != kFsManagerAvbHandleSuccess) return false; std::string partition_name(basename(fstab_entry->mount_point)); if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) { LERROR << "Partition name: " << partition_name.c_str() << " is not valid UTF-8."; - return FS_MGR_SETUP_AVB_FAIL; + return false; } AvbHashtreeDescriptor hashtree_descriptor; std::string salt; std::string root_digest; - if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data, &hashtree_descriptor, - &salt, &root_digest)) { - return FS_MGR_SETUP_AVB_FAIL; + if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt, + &root_digest)) { + return false; } // Converts HASHTREE descriptor to verity_table_params. if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest)) { - return FS_MGR_SETUP_AVB_FAIL; + return false; } - - return FS_MGR_SETUP_AVB_SUCCESS; + return true; } diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp index 8e4966316..981e9fc04 100644 --- a/fs_mgr/fs_mgr_avb_ops.cpp +++ b/fs_mgr/fs_mgr_avb_ops.cpp @@ -39,45 +39,81 @@ #include "fs_mgr_avb_ops.h" #include "fs_mgr_priv.h" -static std::string fstab_by_name_prefix; +static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset, + size_t num_bytes, void* buffer, size_t* out_num_read) { + return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition( + partition, offset, num_bytes, buffer, out_num_read); +} -static std::string extract_by_name_prefix(struct fstab* fstab) { - // In AVB, we can assume that there's an entry for the /misc mount - // point in the fstab file and use that to get the device file for - // the misc partition. The device needs not to have an actual /misc - // partition. Then returns the prefix by removing the trailing "misc": +static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED, + size_t rollback_index_location ATTRIBUTE_UNUSED, + uint64_t* out_rollback_index) { + // rollback_index has been checked in bootloader phase. + // In user-space, returns the smallest value 0 to pass the check. + *out_rollback_index = 0; + return AVB_IO_RESULT_OK; +} + +static AvbIOResult dummy_validate_vbmeta_public_key( + AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED, + size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED, + size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) { + // vbmeta public key has been checked in bootloader phase. + // In user-space, returns true to pass the check. // - // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc -> - // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ + // Addtionally, user-space should check + // androidboot.vbmeta.{hash_alg, size, digest} against the digest + // of all vbmeta images after invoking avb_slot_verify(). + *out_is_trusted = true; + return AVB_IO_RESULT_OK; +} - struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc"); - if (fstab_entry == nullptr) { - LERROR << "/misc mount point not found in fstab"; - return ""; - } +static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED, + bool* out_is_unlocked) { + // The function is for bootloader to update the value into + // androidboot.vbmeta.device_state in kernel cmdline. + // In user-space, returns true as we don't need to update it anymore. + *out_is_unlocked = true; + return AVB_IO_RESULT_OK; +} - std::string full_path(fstab_entry->blk_device); - size_t end_slash = full_path.find_last_of("/"); +static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED, + const char* partition ATTRIBUTE_UNUSED, + char* guid_buf, size_t guid_buf_size) { + // The function is for bootloader to set the correct UUID + // for a given partition in kernel cmdline. + // In user-space, returns a faking one as we don't need to update + // it anymore. + snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition); + return AVB_IO_RESULT_OK; +} - return full_path.substr(0, end_slash + 1); +FsManagerAvbOps::FsManagerAvbOps(const std::string& device_file_by_name_prefix) + : device_file_by_name_prefix_(device_file_by_name_prefix) { + if (device_file_by_name_prefix_.back() != '/') { + device_file_by_name_prefix_ += '/'; + } + // We only need to provide the implementation of read_from_partition() + // operation since that's all what is being used by the avb_slot_verify(). + // Other I/O operations are only required in bootloader but not in + // user-space so we set them as dummy operations. + avb_ops_.read_from_partition = read_from_partition; + avb_ops_.read_rollback_index = dummy_read_rollback_index; + avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key; + avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked; + avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition; + + // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps. + avb_ops_.user_data = this; } -static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition, - int64_t offset, size_t num_bytes, void* buffer, - size_t* out_num_read) { - // The input |partition| name is with ab_suffix, e.g. system_a. - // Slot suffix (e.g. _a) will be appended to the device file path - // for partitions having 'slotselect' optin in fstab file, but it - // won't be appended to the mount point. - // - // Appends |partition| to the fstab_by_name_prefix, which is obtained - // by removing the trailing "misc" from the device file of /misc mount - // point. e.g., - // +AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset, + size_t num_bytes, void* buffer, + size_t* out_num_read) { + // Appends |partition| to the device_file_by_name_prefix_, e.g., // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ -> // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a - - std::string path = fstab_by_name_prefix + partition; + std::string path = device_file_by_name_prefix_ + partition; // Ensures the device path (a symlink created by init) is ready to // access. fs_mgr_test_access() will test a few iterations if the @@ -87,7 +123,6 @@ static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* } android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); - if (fd < 0) { PERROR << "Failed to open " << path.c_str(); return AVB_IO_RESULT_ERROR_IO; @@ -112,7 +147,6 @@ static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* // On Linux, we never get partial reads from block devices (except // for EOF). ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset)); - if (num_read < 0 || (size_t)num_read != num_bytes) { PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset " << offset; @@ -126,72 +160,14 @@ static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* return AVB_IO_RESULT_OK; } -static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED, - size_t rollback_index_location ATTRIBUTE_UNUSED, - uint64_t* out_rollback_index) { - // rollback_index has been checked in bootloader phase. - // In user-space, returns the smallest value 0 to pass the check. - *out_rollback_index = 0; - return AVB_IO_RESULT_OK; -} - -static AvbIOResult dummy_validate_vbmeta_public_key( - AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED, - size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED, - size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) { - // vbmeta public key has been checked in bootloader phase. - // In user-space, returns true to pass the check. - // - // Addtionally, user-space should check - // androidboot.vbmeta.{hash_alg, size, digest} against the digest - // of all vbmeta images after invoking avb_slot_verify(). - - *out_is_trusted = true; - return AVB_IO_RESULT_OK; -} - -static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED, - bool* out_is_unlocked) { - // The function is for bootloader to update the value into - // androidboot.vbmeta.device_state in kernel cmdline. - // In user-space, returns true as we don't need to update it anymore. - *out_is_unlocked = true; - return AVB_IO_RESULT_OK; -} - -static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED, - const char* partition ATTRIBUTE_UNUSED, - char* guid_buf, size_t guid_buf_size) { - // The function is for bootloader to set the correct UUID - // for a given partition in kernel cmdline. - // In user-space, returns a faking one as we don't need to update - // it anymore. - snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition); - return AVB_IO_RESULT_OK; -} - -AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) { - AvbOps* ops; - - fstab_by_name_prefix = extract_by_name_prefix(fstab); - if (fstab_by_name_prefix.empty()) return nullptr; - - ops = (AvbOps*)calloc(1, sizeof(AvbOps)); - if (ops == nullptr) { - LERROR << "Error allocating memory for AvbOps"; - return nullptr; - } - - // We only need these operations since that's all what is being used - // by the avb_slot_verify(); Most of them are dummy operations because - // they're only required in bootloader but not required in user-space. - ops->read_from_partition = read_from_partition; - ops->read_rollback_index = dummy_read_rollback_index; - ops->validate_vbmeta_public_key = dummy_validate_vbmeta_public_key; - ops->read_is_device_unlocked = dummy_read_is_device_unlocked; - ops->get_unique_guid_for_partition = dummy_get_unique_guid_for_partition; - - return ops; +AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix, + bool allow_verification_error, + AvbSlotVerifyData** out_data) { + // Invokes avb_slot_verify() to load and verify all vbmeta images. + // Sets requested_partitions to nullptr as it's to copy the contents + // of HASH partitions into handle>avb_slot_data_, which is not required as + // fs_mgr only deals with HASHTREE partitions. + const char* requested_partitions[] = {nullptr}; + return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), + allow_verification_error, out_data); } - -void fs_mgr_dummy_avb_ops_free(AvbOps* ops) { free(ops); } diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_avb_ops.h index bfdec9aef..ec4a8c94e 100644 --- a/fs_mgr/fs_mgr_avb_ops.h +++ b/fs_mgr/fs_mgr_avb_ops.h @@ -29,31 +29,34 @@ #include "fs_mgr.h" -__BEGIN_DECLS - -/* Allocates a "dummy" AvbOps instance solely for use in user-space. - * Returns nullptr on OOM. - * - * It mainly provides read_from_partitions() for user-space to get - * AvbSlotVerifyData.vbmeta_images[] and the caller MUST check their - * integrity against the androidboot.vbmeta.{hash_alg, size, digest} - * values from /proc/cmdline, e.g. verify_vbmeta_images() - * in fs_mgr_avb.cpp. - * - * Other I/O operations are only required in boot loader so we set - * them as dummy operations here. - * - Will allow any public key for signing. - * - returns 0 for any rollback index location. - * - returns device is unlocked regardless of the actual state. - * - returns a dummy guid for any partition. - * - * Frees with fs_mgr_dummy_avb_ops_free(). - */ -AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab); - -/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */ -void fs_mgr_dummy_avb_ops_free(AvbOps* ops); - -__END_DECLS - +// This class provides C++ bindings to interact with libavb, a small +// self-contained piece of code that's intended to be used in bootloaders. +// It mainly contains two functions: +// - ReadFromPartition(): to read AVB metadata from a given partition. +// It provides the implementation of AvbOps.read_from_partition() when +// reading metadata through libavb. +// - AvbSlotVerify(): the C++ binding of libavb->avb_slot_verify() to +// read and verify the metadata and store it into the out_data parameter. +// The caller MUST check the integrity of metadata against the +// androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline. +// e.g., see class FsManagerAvbVerifier for more details. +// +class FsManagerAvbOps { + public: + FsManagerAvbOps(const std::string& device_file_by_name_prefix); + + static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) { + return reinterpret_cast<FsManagerAvbOps*>(ops->user_data); + } + + AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes, + void* buffer, size_t* out_num_read); + + AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, bool allow_verification_error, + AvbSlotVerifyData** out_data); + + private: + AvbOps avb_ops_; + std::string device_file_by_name_prefix_; +}; #endif /* __CORE_FS_MGR_AVB_OPS_H */ diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h index dce9f617d..99a033e59 100644 --- a/fs_mgr/fs_mgr_priv_avb.h +++ b/fs_mgr/fs_mgr_priv_avb.h @@ -17,40 +17,77 @@ #ifndef __CORE_FS_MGR_PRIV_AVB_H #define __CORE_FS_MGR_PRIV_AVB_H -#ifndef __cplusplus -#include <stdbool.h> -#endif +#include <memory> +#include <string> + +#include <libavb/libavb.h> #include "fs_mgr.h" -__BEGIN_DECLS +enum FsManagerAvbHandleStatus { + kFsManagerAvbHandleSuccess = 0, + kFsManagerAvbHandleHashtreeDisabled = 1, + kFsManagerAvbHandleFail = 2, +}; -#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2) -#define FS_MGR_SETUP_AVB_FAIL (-1) -#define FS_MGR_SETUP_AVB_SUCCESS 0 +class FsManagerAvbHandle; +using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>; -bool fs_mgr_is_avb_used(); +// Provides a factory method to return a unique_ptr pointing to itself and the +// SetUpAvb() function to extract dm-verity parameters from AVB metadata to +// load verity table into kernel through ioctl. +class FsManagerAvbHandle { + public: + // The factory method to return a FsManagerAvbUniquePtr that holds + // the verified AVB (external/avb) metadata of all verified partitions + // in avb_slot_data_.vbmeta_images[]. + // + // The metadata is checked against the following values from /proc/cmdline. + // - androidboot.vbmeta.{hash_alg, size, digest}. + // + // A typical usage will be: + // - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open(); + // + // Possible return values: + // - nullptr: any error when reading and verifying the metadata, + // e.g., I/O error, digest value mismatch, size mismatch, etc. + // + // - a valid unique_ptr with status kFsMgrAvbHandleHashtreeDisabled: + // to support the existing 'adb disable-verity' feature in Android. + // It's very helpful for developers to make the filesystem writable to + // allow replacing binaries on the device. + // + // - a valid unique_ptr with status kFsMgrAvbHandleSuccess: the metadata + // is verified and can be trusted. + // + static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix); -/* Gets AVB metadata through external/avb/libavb for all partitions: - * AvbSlotVerifyData.vbmeta_images[] and checks their integrity - * against the androidboot.vbmeta.{hash_alg, size, digest} values - * from /proc/cmdline. - * - * Return values: - * - FS_MGR_SETUP_AVB_SUCCESS: the metadata cab be trusted. - * - FS_MGR_SETUP_AVB_FAIL: any error when reading and verifying the - * metadata, e.g. I/O error, digest value mismatch, size mismatch. - * - FS_MGR_SETUP_AVB_HASHTREE_DISABLED: to support the existing - * 'adb disable-verity' feature in Android. It's very helpful for - * developers to make the filesystem writable to allow replacing - * binaries on the device. - */ -int fs_mgr_load_vbmeta_images(struct fstab* fstab); + // Sets up dm-verity on the given fstab entry. + // Returns true if the mount point is eligible to mount, it includes: + // - status_ is kFsMgrAvbHandleHashtreeDisabled or + // - status_ is kFsMgrAvbHandleSuccess and sending ioctl DM_TABLE_LOAD + // to load verity table is success. + // Otherwise, returns false. + bool SetUpAvb(fstab_rec* fstab_entry); + + FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy + FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment + + FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move + FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment -void fs_mgr_unload_vbmeta_images(); + ~FsManagerAvbHandle() { + if (avb_slot_data_) { + avb_slot_verify_data_free(avb_slot_data_); + } + }; -int fs_mgr_setup_avb(struct fstab_rec* fstab_entry); + protected: + FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {} -__END_DECLS + private: + AvbSlotVerifyData* avb_slot_data_; + FsManagerAvbHandleStatus status_; +}; #endif /* __CORE_FS_MGR_PRIV_AVB_H */ diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/fs_mgr_priv_sha.h index 882411b40..5b53eea9e 100644 --- a/fs_mgr/fs_mgr_priv_sha.h +++ b/fs_mgr/fs_mgr_priv_sha.h @@ -20,16 +20,18 @@ #include <openssl/sha.h> class SHA256Hasher { - private: + private: SHA256_CTX sha256_ctx; uint8_t hash[SHA256_DIGEST_LENGTH]; - public: + public: enum { DIGEST_SIZE = SHA256_DIGEST_LENGTH }; SHA256Hasher() { SHA256_Init(&sha256_ctx); } - void update(const void* data, size_t data_size) { SHA256_Update(&sha256_ctx, data, data_size); } + void update(const uint8_t* data, size_t data_size) { + SHA256_Update(&sha256_ctx, data, data_size); + } const uint8_t* finalize() { SHA256_Final(hash, &sha256_ctx); @@ -38,11 +40,11 @@ class SHA256Hasher { }; class SHA512Hasher { - private: + private: SHA512_CTX sha512_ctx; uint8_t hash[SHA512_DIGEST_LENGTH]; - public: + public: enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH }; SHA512Hasher() { SHA512_Init(&sha512_ctx); } |