diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 120129c50..ea9cb375c 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -31,7 +31,10 @@ #include #include +#include + #include +#include #include #include #include @@ -47,8 +50,10 @@ #include #include // for __android_log_is_debuggable() +#include "fs_mgr.h" +#include "fs_mgr_avb.h" #include "fs_mgr_priv.h" -#include "fs_mgr_priv_avb.h" +#include "fs_mgr_priv_dm_ioctl.h" #define KEY_LOC_PROP "ro.crypto.keyfile.userdata" #define KEY_IN_FOOTER "footer" @@ -707,6 +712,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 +772,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 +816,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], true /* wait_for_verity_dev */)) { LERROR << "Failed to set up AVB on partition: " << fstab->recs[i].mount_point << ", skipping!"; /* Skips mounting the device. */ @@ -934,10 +950,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 +988,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 +1028,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], true /* wait_for_verity_dev */)) { LERROR << "Failed to set up AVB on partition: " << fstab->recs[i].mount_point << ", skipping!"; /* Skips mounting the device. */ @@ -1079,9 +1085,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; } @@ -1259,3 +1262,97 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev return 0; } + +bool fs_mgr_load_verity_state(int* mode) { + /* return the default mode, unless any of the verified partitions are in + * logging mode, in which case return that */ + *mode = VERITY_MODE_DEFAULT; + + std::unique_ptr fstab(fs_mgr_read_fstab_default(), + fs_mgr_free_fstab); + if (!fstab) { + LERROR << "Failed to read default fstab"; + return false; + } + + for (int i = 0; i < fstab->num_entries; i++) { + if (fs_mgr_is_avb(&fstab->recs[i])) { + *mode = VERITY_MODE_RESTART; // avb only supports restart mode. + break; + } else if (!fs_mgr_is_verified(&fstab->recs[i])) { + continue; + } + + int current; + if (load_verity_state(&fstab->recs[i], ¤t) < 0) { + continue; + } + if (current != VERITY_MODE_DEFAULT) { + *mode = current; + break; + } + } + + return true; +} + +bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) { + if (!callback) { + return false; + } + + int mode; + if (!fs_mgr_load_verity_state(&mode)) { + return false; + } + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC))); + if (fd == -1) { + PERROR << "Error opening device mapper"; + return false; + } + + std::unique_ptr fstab(fs_mgr_read_fstab_default(), + fs_mgr_free_fstab); + if (!fstab) { + LERROR << "Failed to read default fstab"; + return false; + } + + alignas(dm_ioctl) char buffer[DM_BUF_SIZE]; + struct dm_ioctl* io = (struct dm_ioctl*)buffer; + bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true"; + + for (int i = 0; i < fstab->num_entries; i++) { + if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) { + continue; + } + + std::string mount_point; + if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) { + mount_point = "system"; + } else { + mount_point = basename(fstab->recs[i].mount_point); + } + + fs_mgr_verity_ioctl_init(io, mount_point, 0); + + const char* status; + if (ioctl(fd, DM_TABLE_STATUS, io)) { + if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) { + status = "V"; + } else { + PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str(); + continue; + } + } + + status = &buffer[io->data_start + sizeof(struct dm_target_spec)]; + + if (*status == 'C' || *status == 'V') { + callback(&fstab->recs[i], mount_point.c_str(), mode, *status); + } + } + + return true; +} diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp index 7512eb934..7c82bb1e6 100644 --- a/fs_mgr/fs_mgr_avb.cpp +++ b/fs_mgr/fs_mgr_avb.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -37,9 +38,9 @@ #include #include "fs_mgr.h" +#include "fs_mgr_avb.h" #include "fs_mgr_avb_ops.h" #include "fs_mgr_priv.h" -#include "fs_mgr_priv_avb.h" #include "fs_mgr_priv_dm_ioctl.h" #include "fs_mgr_priv_sha.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 +static std::pair 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 + static std::unique_ptr 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::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::unique_ptr avb_verifier(new FsManagerAvbVerifier()); + if (!avb_verifier) { + LERROR << "Failed to create unique_ptr"; + return nullptr; + } - std::string hash_alg; std::string digest; - + std::string hash_alg; for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) { std::vector 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 -static std::pair 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(verify_data, vbmeta_prop); - } else if (vbmeta_prop.hash_alg == kSHA512) { + verify_vbmeta_digest(verify_data, digest_); + } else if (hash_alg_ == kSHA512) { std::tie(total_size, digest_matched) = - verify_vbmeta_digest(verify_data, vbmeta_prop); + verify_vbmeta_digest(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; } @@ -319,7 +336,8 @@ static bool hashtree_load_verity_table(struct dm_ioctl* io, const std::string& d static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc, - const std::string& salt, const std::string& root_digest) { + const std::string& salt, const std::string& root_digest, + bool wait_for_verity_dev) { // Gets the device mapper fd. android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR)); if (fd < 0) { @@ -358,13 +376,12 @@ static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry, // Marks the underlying block device as read-only. fs_mgr_set_blk_ro(fstab_entry->blk_device); - // TODO(bowgotsai): support verified all partition at boot. // Updates fstab_rec->blk_device to verity device name. free(fstab_entry->blk_device); fstab_entry->blk_device = strdup(verity_blk_name.c_str()); // Makes sure we've set everything up properly. - if (fs_mgr_test_access(verity_blk_name.c_str()) < 0) { + if (wait_for_verity_dev && fs_mgr_test_access(verity_blk_name.c_str()) < 0) { 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,140 +457,97 @@ 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; - } - 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; +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; } - 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; + // Gets the expected hash value of vbmeta images from kernel cmdline. + std::unique_ptr avb_verifier = FsManagerAvbVerifier::Create(); + if (!avb_verifier) { + LERROR << "Failed to create FsManagerAvbVerifier"; + 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; - std::string slot; - if (fs_mgr_get_boot_config("slot", &slot)) { - ab_suffix = "_" + slot; - } else { - // remove slot_suffix once bootloaders update to new androidboot.slot param - fs_mgr_get_boot_config("slot_suffix", &ab_suffix); + FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle()); + if (!avb_handle) { + LERROR << "Failed to allocate FsManagerAvbHandle"; + return nullptr; } - 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); +bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry, bool wait_for_verity_dev) { + if (!fstab_entry) return false; + if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) { + return false; } - - if (fs_mgr_avb_ops != nullptr) { - fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops); - } -} - -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; + if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest, + wait_for_verity_dev)) { + 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,91 +39,10 @@ #include "fs_mgr_avb_ops.h" #include "fs_mgr_priv.h" -static std::string fstab_by_name_prefix; - -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": - // - // - /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); -} - -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., - // - // - /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; - - // Ensures the device path (a symlink created by init) is ready to - // access. fs_mgr_test_access() will test a few iterations if the - // path doesn't exist yet. - if (fs_mgr_test_access(path.c_str()) < 0) { - return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; - } - - 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; - } - - // If offset is negative, interprets its absolute value as the - // number of bytes from the end of the partition. - if (offset < 0) { - off64_t total_size = lseek64(fd, 0, SEEK_END); - if (total_size == -1) { - LERROR << "Failed to lseek64 to end of the partition"; - return AVB_IO_RESULT_ERROR_IO; - } - offset = total_size + offset; - // Repositions the offset to the beginning. - if (lseek64(fd, 0, SEEK_SET) == -1) { - LERROR << "Failed to lseek64 to the beginning of the partition"; - return AVB_IO_RESULT_ERROR_IO; - } - } - - // 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; - return AVB_IO_RESULT_ERROR_IO; - } - - if (out_num_read != nullptr) { - *out_num_read = num_read; - } - - return AVB_IO_RESULT_OK; +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 AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED, @@ -145,7 +64,6 @@ static AvbIOResult dummy_validate_vbmeta_public_key( // 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; } @@ -170,28 +88,86 @@ static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNU 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; +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; - // 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; + // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps. + avb_ops_.user_data = this; } -void fs_mgr_dummy_avb_ops_free(AvbOps* ops) { free(ops); } +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 = 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 + // path doesn't exist yet. + if (fs_mgr_test_access(path.c_str()) < 0) { + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + } + + 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; + } + + // If offset is negative, interprets its absolute value as the + // number of bytes from the end of the partition. + if (offset < 0) { + off64_t total_size = lseek64(fd, 0, SEEK_END); + if (total_size == -1) { + LERROR << "Failed to lseek64 to end of the partition"; + return AVB_IO_RESULT_ERROR_IO; + } + offset = total_size + offset; + // Repositions the offset to the beginning. + if (lseek64(fd, 0, SEEK_SET) == -1) { + LERROR << "Failed to lseek64 to the beginning of the partition"; + return AVB_IO_RESULT_ERROR_IO; + } + } + + // 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; + return AVB_IO_RESULT_ERROR_IO; + } + + if (out_num_read != nullptr) { + *out_num_read = num_read; + } + + return AVB_IO_RESULT_OK; +} + +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); +} 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 +// 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); -/* 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); + static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) { + return reinterpret_cast(ops->user_data); + } -/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */ -void fs_mgr_dummy_avb_ops_free(AvbOps* ops); + AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes, + void* buffer, size_t* out_num_read); -__END_DECLS + 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_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index a9a0df79e..0a694c145 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -572,7 +572,7 @@ static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file) cnt++; } /* If an A/B partition, modify block device to be the real block device */ - if (fs_mgr_update_for_slotselect(fstab) != 0) { + if (!fs_mgr_update_for_slotselect(fstab)) { LERROR << "Error updating for slotselect"; goto err; } @@ -814,6 +814,11 @@ int fs_mgr_is_verified(const struct fstab_rec *fstab) return fstab->fs_mgr_flags & MF_VERIFY; } +int fs_mgr_is_avb(const struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_AVB; +} + int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_VERIFYATBOOT; diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 377d2ecb0..c985462af 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -41,8 +41,6 @@ #define PWARNING PLOG(WARNING) << FS_MGR_TAG #define PERROR PLOG(ERROR) << FS_MGR_TAG -__BEGIN_DECLS - #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000" #define WAIT_TIMEOUT 20 @@ -114,10 +112,9 @@ __BEGIN_DECLS int fs_mgr_set_blk_ro(const char *blockdev); int fs_mgr_test_access(const char *device); -int fs_mgr_update_for_slotselect(struct fstab *fstab); +bool fs_mgr_update_for_slotselect(struct fstab *fstab); bool is_dt_compatible(); bool is_device_secure(); - -__END_DECLS +int load_verity_state(struct fstab_rec* fstab, int* mode); #endif /* __CORE_FS_MGR_PRIV_H */ diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h deleted file mode 100644 index dce9f617d..000000000 --- a/fs_mgr/fs_mgr_priv_avb.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CORE_FS_MGR_PRIV_AVB_H -#define __CORE_FS_MGR_PRIV_AVB_H - -#ifndef __cplusplus -#include -#endif - -#include "fs_mgr.h" - -__BEGIN_DECLS - -#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2) -#define FS_MGR_SETUP_AVB_FAIL (-1) -#define FS_MGR_SETUP_AVB_SUCCESS 0 - -bool fs_mgr_is_avb_used(); - -/* 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); - -void fs_mgr_unload_vbmeta_images(); - -int fs_mgr_setup_avb(struct fstab_rec* fstab_entry); - -__END_DECLS - -#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 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); } diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp index 7a4547334..9ca15e237 100644 --- a/fs_mgr/fs_mgr_slotselect.cpp +++ b/fs_mgr/fs_mgr_slotselect.cpp @@ -16,37 +16,47 @@ #include +#include + #include "fs_mgr.h" #include "fs_mgr_priv.h" -// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error. -int fs_mgr_update_for_slotselect(struct fstab *fstab) -{ +// Returns "_a" or "_b" based on two possible values in kernel cmdline: +// - androidboot.slot = a or b OR +// - androidboot.slot_suffix = _a or _b +// TODO: remove slot_suffix once it's deprecated. +std::string fs_mgr_get_slot_suffix() { + std::string slot; + std::string ab_suffix; + + if (fs_mgr_get_boot_config("slot", &slot)) { + ab_suffix = "_" + slot; + } else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) { + ab_suffix = ""; + } + return ab_suffix; +} + +// Updates |fstab| for slot_suffix. Returns true on success, false on error. +bool fs_mgr_update_for_slotselect(struct fstab *fstab) { int n; - int got_suffix = 0; - std::string suffix; + std::string ab_suffix; for (n = 0; n < fstab->num_entries; n++) { if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) { char *tmp; - - if (!got_suffix) { - std::string slot; - if (fs_mgr_get_boot_config("slot", &slot)) { - suffix = "_" + slot; - } else if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) { - // remove slot_suffix once bootloaders update to new androidboot.slot param - return -1; - } + if (ab_suffix.empty()) { + ab_suffix = fs_mgr_get_slot_suffix(); + // Returns false as non A/B devices should not have MF_SLOTSELECT. + if (ab_suffix.empty()) return false; } - - if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, suffix.c_str()) > 0) { + if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) { free(fstab->recs[n].blk_device); fstab->recs[n].blk_device = tmp; } else { - return -1; + return false; } } } - return 0; + return true; } diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index 8c7a8ca6d..0bf173bd8 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp @@ -653,8 +653,7 @@ static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset) offset); } -static int load_verity_state(struct fstab_rec *fstab, int *mode) -{ +int load_verity_state(struct fstab_rec* fstab, int* mode) { int match = 0; off64_t offset = 0; @@ -690,129 +689,6 @@ static int load_verity_state(struct fstab_rec *fstab, int *mode) return read_verity_state(fstab->verity_loc, offset, mode); } -int fs_mgr_load_verity_state(int *mode) -{ - int rc = -1; - int i; - int current; - struct fstab *fstab = NULL; - - /* return the default mode, unless any of the verified partitions are in - * logging mode, in which case return that */ - *mode = VERITY_MODE_DEFAULT; - - fstab = fs_mgr_read_fstab_default(); - if (!fstab) { - LERROR << "Failed to read default fstab"; - goto out; - } - - for (i = 0; i < fstab->num_entries; i++) { - if (!fs_mgr_is_verified(&fstab->recs[i])) { - continue; - } - - rc = load_verity_state(&fstab->recs[i], ¤t); - if (rc < 0) { - continue; - } - - if (current != VERITY_MODE_DEFAULT) { - *mode = current; - break; - } - } - - rc = 0; - -out: - if (fstab) { - fs_mgr_free_fstab(fstab); - } - - return rc; -} - -int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) -{ - alignas(dm_ioctl) char buffer[DM_BUF_SIZE]; - bool system_root = false; - std::string mount_point; - char propbuf[PROPERTY_VALUE_MAX]; - const char *status; - int fd = -1; - int i; - int mode; - int rc = -1; - struct dm_ioctl *io = (struct dm_ioctl *) buffer; - struct fstab *fstab = NULL; - - if (!callback) { - return -1; - } - - if (fs_mgr_load_verity_state(&mode) == -1) { - return -1; - } - - fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)); - if (fd == -1) { - PERROR << "Error opening device mapper"; - goto out; - } - - property_get("ro.build.system_root_image", propbuf, ""); - system_root = !strcmp(propbuf, "true"); - fstab = fs_mgr_read_fstab_default(); - if (!fstab) { - LERROR << "Failed to read default fstab"; - goto out; - } - - for (i = 0; i < fstab->num_entries; i++) { - if (!fs_mgr_is_verified(&fstab->recs[i])) { - continue; - } - - if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) { - mount_point = "system"; - } else { - mount_point = basename(fstab->recs[i].mount_point); - } - - fs_mgr_verity_ioctl_init(io, mount_point, 0); - - if (ioctl(fd, DM_TABLE_STATUS, io)) { - if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) { - status = "V"; - } else { - PERROR << "Failed to query DM_TABLE_STATUS for " - << mount_point.c_str(); - continue; - } - } - - status = &buffer[io->data_start + sizeof(struct dm_target_spec)]; - - if (*status == 'C' || *status == 'V') { - callback(&fstab->recs[i], mount_point.c_str(), mode, *status); - } - } - - rc = 0; - -out: - if (fstab) { - fs_mgr_free_fstab(fstab); - } - - if (fd) { - close(fd); - } - - return rc; -} - static void update_verity_table_blk_device(char *blk_device, char **table) { std::string result, word; diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 2fd5f65a4..fd63dfd38 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -22,6 +22,12 @@ #include #include +// C++ only headers +// TODO: move this into separate header files under include/fs_mgr/*.h +#ifdef __cplusplus +#include +#endif + // Magic number at start of verity metadata #define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 @@ -29,9 +35,7 @@ // turn verity off in userdebug builds. #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF" -#ifdef __cplusplus -extern "C" { -#endif +__BEGIN_DECLS // Verity modes enum verity_mode { @@ -110,8 +114,8 @@ int fs_mgr_do_tmpfs_mount(const char *n_name); int fs_mgr_unmount_all(struct fstab *fstab); int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size); -int fs_mgr_load_verity_state(int *mode); -int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback); +bool fs_mgr_load_verity_state(int* mode); +bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback); int fs_mgr_add_entry(struct fstab *fstab, const char *mount_point, const char *fs_type, const char *blk_device); @@ -120,6 +124,7 @@ int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab); int fs_mgr_is_nonremovable(const struct fstab_rec *fstab); int fs_mgr_is_verified(const struct fstab_rec *fstab); int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab); +int fs_mgr_is_avb(const struct fstab_rec *fstab); int fs_mgr_is_encryptable(const struct fstab_rec *fstab); int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab); void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab, @@ -142,8 +147,12 @@ int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer); #define FS_MGR_SETUP_VERITY_SUCCESS 0 int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev); +__END_DECLS + +// C++ only functions +// TODO: move this into separate header files under include/fs_mgr/*.h #ifdef __cplusplus -} +std::string fs_mgr_get_slot_suffix(); #endif #endif /* __CORE_FS_MGR_H */ diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h new file mode 100644 index 000000000..526a5ce06 --- /dev/null +++ b/fs_mgr/include/fs_mgr_avb.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CORE_FS_MGR_AVB_H +#define __CORE_FS_MGR_AVB_H + +#include +#include + +#include + +#include "fs_mgr.h" + +enum FsManagerAvbHandleStatus { + kFsManagerAvbHandleSuccess = 0, + kFsManagerAvbHandleHashtreeDisabled = 1, + kFsManagerAvbHandleFail = 2, +}; + +class FsManagerAvbHandle; +using FsManagerAvbUniquePtr = std::unique_ptr; + +// 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); + + // Sets up dm-verity on the given fstab entry. + // The 'wait_for_verity_dev' parameter makes this function wait for the + // verity device to get created before return. + // 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, bool wait_for_verity_dev); + + bool AvbHashtreeDisabled() { return status_ == kFsManagerAvbHandleHashtreeDisabled; } + + 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 + + ~FsManagerAvbHandle() { + if (avb_slot_data_) { + avb_slot_verify_data_free(avb_slot_data_); + } + }; + + protected: + FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {} + + private: + AvbSlotVerifyData* avb_slot_data_; + FsManagerAvbHandleStatus status_; +}; + +#endif /* __CORE_FS_MGR_AVB_H */ diff --git a/init/Android.mk b/init/Android.mk index e97f4f2f2..6dc02293f 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -109,8 +109,8 @@ LOCAL_STATIC_LIBRARIES := \ libfec_rs \ libsquashfs_utils \ liblogwrap \ - libcutils \ libext4_utils \ + libcutils \ libbase \ libc \ libselinux \ diff --git a/init/builtins.cpp b/init/builtins.cpp index 75b3c6104..2be70bf5f 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -678,11 +678,11 @@ static int do_sysclktz(const std::vector& args) { static int do_verity_load_state(const std::vector& args) { int mode = -1; - int rc = fs_mgr_load_verity_state(&mode); - if (rc == 0 && mode != VERITY_MODE_DEFAULT) { + bool loaded = fs_mgr_load_verity_state(&mode); + if (loaded && mode != VERITY_MODE_DEFAULT) { ActionManager::GetInstance().QueueEventTrigger("verity-logging"); } - return rc; + return loaded ? 0 : 1; } static void verity_update_property(fstab_rec *fstab, const char *mount_point, @@ -692,7 +692,7 @@ static void verity_update_property(fstab_rec *fstab, const char *mount_point, } static int do_verity_update_state(const std::vector& args) { - return fs_mgr_update_verity_state(verity_update_property); + return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1; } static int do_write(const std::vector& args) { diff --git a/init/init.cpp b/init/init.cpp index d07c308a5..b05311a31 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -57,6 +57,7 @@ #include "bootchart.h" #include "devices.h" #include "fs_mgr.h" +#include "fs_mgr_avb.h" #include "import_parser.h" #include "init.h" #include "init_parser.h" @@ -478,42 +479,73 @@ static void export_kernel_boot_props() { } } -static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android"; - -static bool is_dt_compatible() { - std::string dt_value; - std::string file_name = StringPrintf("%s/compatible", android_dt_dir); - - if (android::base::ReadFileToString(file_name, &dt_value)) { - // trim the trailing '\0' out, otherwise the comparison - // will produce false-negatives. - dt_value.resize(dt_value.size() - 1); - if (dt_value == "android,firmware") { +/* Reads the content of device tree file into dt_value. + * Returns true if the read is success, false otherwise. + */ +static bool read_dt_file(const std::string& file_name, std::string* dt_value) { + if (android::base::ReadFileToString(file_name, dt_value)) { + if (!dt_value->empty()) { + dt_value->pop_back(); // Trim the trailing '\0' out. return true; } } - return false; } -static bool is_dt_fstab_compatible() { - std::string dt_value; - std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab"); +static const std::string kAndroidDtDir("/proc/device-tree/firmware/android/"); - if (android::base::ReadFileToString(file_name, &dt_value)) { - dt_value.resize(dt_value.size() - 1); - if (dt_value == "android,fstab") { +static bool is_dt_value_expected(const std::string& dt_file_suffix, + const std::string& expected_value) { + std::string dt_value; + std::string file_name = kAndroidDtDir + dt_file_suffix; + + if (read_dt_file(file_name, &dt_value)) { + if (dt_value == expected_value) { return true; } } - return false; } +static inline bool is_dt_compatible() { + return is_dt_value_expected("compatible", "android,firmware"); +} + +static inline bool is_dt_fstab_compatible() { + return is_dt_value_expected("fstab/compatible", "android,fstab"); +} + +static inline bool is_dt_vbmeta_compatible() { + return is_dt_value_expected("vbmeta/compatible", "android,vbmeta"); +} + +// Gets the vbmeta config from device tree. Specifically, the 'parts' and 'by_name_prefix'. +// /{ +// firmware { +// android { +// vbmeta { +// compatible = "android,vbmeta"; +// parts = "vbmeta,boot,system,vendor" +// by_name_prefix="/dev/block/platform/soc.0/f9824900.sdhci/by-name/" +// }; +// }; +// }; +// } +static bool get_vbmeta_config_from_dt(std::string* vbmeta_partitions, + std::string* device_file_by_name_prefix) { + std::string file_name = kAndroidDtDir + "vbmeta/parts"; + if (!read_dt_file(file_name, vbmeta_partitions)) return false; + + file_name = kAndroidDtDir + "vbmeta/by_name_prefix"; + if (!read_dt_file(file_name, device_file_by_name_prefix)) return false; + + return true; +} + static void process_kernel_dt() { if (!is_dt_compatible()) return; - std::unique_ptrdir(opendir(android_dt_dir), closedir); + std::unique_ptr dir(opendir(kAndroidDtDir.c_str()), closedir); if (!dir) return; std::string dt_file; @@ -523,7 +555,7 @@ static void process_kernel_dt() { continue; } - std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name); + std::string file_name = kAndroidDtDir + dp->d_name; android::base::ReadFileToString(file_name, &dt_file); std::replace(dt_file.begin(), dt_file.end(), ',', '.'); @@ -944,38 +976,100 @@ static void set_usb_controller() { } } -static bool early_mount_one(struct fstab_rec* rec) { - if (rec && fs_mgr_is_verified(rec)) { - // setup verity and create the dm-XX block device - // needed to mount this partition - int ret = fs_mgr_setup_verity(rec, false); - if (ret == FS_MGR_SETUP_VERITY_FAIL) { - PLOG(ERROR) << "early_mount: Failed to setup verity for '" << rec->mount_point << "'"; +// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX. +static void device_init_dm_device(const std::string& dm_device) { + const std::string device_name(basename(dm_device.c_str())); + const std::string syspath = "/sys/block/" + device_name; + + device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t { + if (uevent->device_name && device_name == uevent->device_name) { + LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device; + return COLDBOOT_STOP; + } + return COLDBOOT_CONTINUE; + }); + device_close(); +} + +static bool vboot_1_0_mount_partitions(const std::vector& fstab_recs) { + if (fstab_recs.empty()) return false; + + for (auto rec : fstab_recs) { + bool need_create_dm_device = false; + if (fs_mgr_is_verified(rec)) { + // setup verity and create the dm-XX block device + // needed to mount this partition + int ret = fs_mgr_setup_verity(rec, false /* wait_for_verity_dev */); + if (ret == FS_MGR_SETUP_VERITY_DISABLED) { + LOG(INFO) << "verity disabled for '" << rec->mount_point << "'"; + } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) { + need_create_dm_device = true; + } else { + PLOG(ERROR) << "early_mount: failed to setup verity for '" << rec->mount_point + << "'"; + return false; + } + } + if (need_create_dm_device) { + // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX". + // Need to create it because ueventd isn't started during early mount. + device_init_dm_device(rec->blk_device); + } + if (fs_mgr_do_mount_one(rec)) { + PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'"; return false; } - - // The exact block device name is added as a mount source by - // fs_mgr_setup_verity() in ->blk_device as "/dev/block/dm-XX" - // We create that device by running coldboot on /sys/block/dm-XX - std::string dm_device(basename(rec->blk_device)); - std::string syspath = StringPrintf("/sys/block/%s", dm_device.c_str()); - device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t { - if (uevent->device_name && !strcmp(dm_device.c_str(), uevent->device_name)) { - LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device; - return COLDBOOT_STOP; - } - return COLDBOOT_CONTINUE; - }); - } - - if (rec && fs_mgr_do_mount_one(rec)) { - PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'"; - return false; } return true; } +static bool vboot_2_0_mount_partitions(const std::vector& fstab_recs, + const std::string& device_file_by_name_prefix) { + if (fstab_recs.empty()) return false; + + FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(device_file_by_name_prefix); + if (!avb_handle) { + LOG(INFO) << "Failed to Open FsManagerAvbHandle"; + return false; + } + + for (auto rec : fstab_recs) { + bool need_create_dm_device = false; + if (fs_mgr_is_avb(rec)) { + if (avb_handle->AvbHashtreeDisabled()) { + LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'"; + } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) { + need_create_dm_device = true; + } else { + PLOG(ERROR) << "early_mount: failed to set up AVB on partition: '" + << rec->mount_point << "'"; + return false; + } + } + if (need_create_dm_device) { + // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX". + // Need to create it because ueventd isn't started during early mount. + device_init_dm_device(rec->blk_device); + } + if (fs_mgr_do_mount_one(rec)) { + PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'"; + return false; + } + } + + return true; +} + +static bool mount_early_partitions(const std::vector& fstab_recs, + const std::string& device_file_by_name_prefix) { + if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity. + return vboot_2_0_mount_partitions(fstab_recs, device_file_by_name_prefix); + } else { + return vboot_1_0_mount_partitions(fstab_recs); + } +} + // Creates devices with uevent->partition_name matching one in the in/out // partition_names. Note that the partition_names MUST have A/B suffix // when A/B is used. Found partitions will then be removed from the @@ -1018,12 +1112,10 @@ static void early_device_init(std::set* partition_names) { }); } -static bool get_early_partitions(const std::vector& early_fstab_recs, - std::set* out_partitions, bool* out_need_verity) { +static bool vboot_1_0_early_partitions(const std::vector& early_fstab_recs, + std::set* out_partitions, + bool* out_need_verity) { std::string meta_partition; - out_partitions->clear(); - *out_need_verity = false; - for (auto fstab_rec : early_fstab_recs) { // don't allow verifyatboot for early mounted partitions if (fs_mgr_is_verifyatboot(fstab_rec)) { @@ -1062,6 +1154,40 @@ static bool get_early_partitions(const std::vector& early_fstab_recs return true; } +// a.k.a. AVB (external/avb) +static bool vboot_2_0_early_partitions(std::set* out_partitions, bool* out_need_verity, + std::string* out_device_file_by_name_prefix) { + std::string vbmeta_partitions; + if (!get_vbmeta_config_from_dt(&vbmeta_partitions, out_device_file_by_name_prefix)) { + return false; + } + // libavb verifies AVB metadata on all verified partitions at once. + // e.g., The vbmeta_partitions will be "vbmeta,boot,system,vendor" + // for libavb to verify metadata, even if we only need to early mount /vendor. + std::vector partitions = android::base::Split(vbmeta_partitions, ","); + std::string ab_suffix = fs_mgr_get_slot_suffix(); + for (const auto& partition : partitions) { + out_partitions->emplace(partition + ab_suffix); + } + *out_need_verity = true; + return true; +} + +static bool get_early_partitions(const std::vector& early_fstab_recs, + std::set* out_partitions, bool* out_need_verity, + std::string* out_device_file_by_name_prefix) { + *out_need_verity = false; + out_partitions->clear(); + out_device_file_by_name_prefix->clear(); + + if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity. + return vboot_2_0_early_partitions(out_partitions, out_need_verity, + out_device_file_by_name_prefix); + } else { + return vboot_1_0_early_partitions(early_fstab_recs, out_partitions, out_need_verity); + } +} + /* Early mount vendor and ODM partitions. The fstab is read from device-tree. */ static bool early_mount() { // skip early mount if we're in recovery mode @@ -1096,9 +1222,11 @@ static bool early_mount() { if (early_fstab_recs.empty()) return true; bool need_verity; + std::string device_file_by_name_prefix; std::set partition_names; // partition_names MUST have A/B suffix when A/B is used - if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) { + if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity, + &device_file_by_name_prefix)) { return false; } @@ -1121,10 +1249,9 @@ static bool early_mount() { [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; }); } - for (auto fstab_rec : early_fstab_recs) { - if (!early_mount_one(fstab_rec)) goto done; + if (mount_early_partitions(early_fstab_recs, device_file_by_name_prefix)) { + success = true; } - success = true; done: device_close();