| /* |
| * 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. |
| */ |
| |
| #include "fs_avb/fs_avb.h" |
| |
| #include <fcntl.h> |
| #include <libgen.h> |
| #include <string.h> |
| #include <sys/ioctl.h> |
| #include <sys/types.h> |
| |
| #include <algorithm> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include <android-base/file.h> |
| #include <android-base/parseint.h> |
| #include <android-base/stringprintf.h> |
| #include <android-base/strings.h> |
| #include <libavb/libavb.h> |
| #include <libdm/dm.h> |
| #include <libgsi/libgsi.h> |
| |
| #include "avb_ops.h" |
| #include "avb_util.h" |
| #include "fs_avb/fs_avb_util.h" |
| #include "sha.h" |
| #include "util.h" |
| |
| using android::base::Basename; |
| using android::base::ParseUint; |
| using android::base::ReadFileToString; |
| using android::base::Split; |
| using android::base::StringPrintf; |
| |
| namespace android { |
| namespace fs_mgr { |
| |
| template <typename Hasher> |
| std::pair<size_t, bool> VerifyVbmetaDigest(const std::vector<VBMetaData>& vbmeta_images, |
| const uint8_t* expected_digest) { |
| size_t total_size = 0; |
| Hasher hasher; |
| for (const auto& vbmeta : vbmeta_images) { |
| hasher.update(vbmeta.data(), vbmeta.size()); |
| total_size += vbmeta.size(); |
| } |
| |
| bool matched = (memcmp(hasher.finalize(), expected_digest, Hasher::DIGEST_SIZE) == 0); |
| |
| return std::make_pair(total_size, matched); |
| } |
| |
| template <typename Hasher> |
| std::pair<std::string, size_t> CalculateVbmetaDigest(const std::vector<VBMetaData>& vbmeta_images) { |
| std::string digest; |
| size_t total_size = 0; |
| |
| Hasher hasher; |
| for (const auto& vbmeta : vbmeta_images) { |
| hasher.update(vbmeta.data(), vbmeta.size()); |
| total_size += vbmeta.size(); |
| } |
| |
| // Converts digest bytes to a hex string. |
| digest = BytesToHex(hasher.finalize(), Hasher::DIGEST_SIZE); |
| return std::make_pair(digest, total_size); |
| } |
| |
| // class AvbVerifier |
| // ----------------- |
| // Reads the following values from kernel cmdline and provides the |
| // VerifyVbmetaImages() to verify AvbSlotVerifyData. |
| // - androidboot.vbmeta.hash_alg |
| // - androidboot.vbmeta.size |
| // - androidboot.vbmeta.digest |
| class AvbVerifier { |
| public: |
| // The factory method to return a unique_ptr<AvbVerifier> |
| static std::unique_ptr<AvbVerifier> Create(); |
| bool VerifyVbmetaImages(const std::vector<VBMetaData>& vbmeta_images); |
| |
| protected: |
| AvbVerifier() = default; |
| |
| private: |
| HashAlgorithm hash_alg_; |
| uint8_t digest_[SHA512_DIGEST_LENGTH]; |
| size_t vbmeta_size_; |
| }; |
| |
| std::unique_ptr<AvbVerifier> AvbVerifier::Create() { |
| std::unique_ptr<AvbVerifier> avb_verifier(new AvbVerifier()); |
| if (!avb_verifier) { |
| LERROR << "Failed to create unique_ptr<AvbVerifier>"; |
| return nullptr; |
| } |
| |
| std::string value; |
| if (!fs_mgr_get_boot_config("vbmeta.size", &value) || |
| !ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) { |
| LERROR << "Invalid hash size: " << value.c_str(); |
| return nullptr; |
| } |
| |
| // Reads hash algorithm. |
| size_t expected_digest_size = 0; |
| std::string hash_alg; |
| fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg); |
| if (hash_alg == "sha256") { |
| expected_digest_size = SHA256_DIGEST_LENGTH * 2; |
| avb_verifier->hash_alg_ = HashAlgorithm::kSHA256; |
| } else if (hash_alg == "sha512") { |
| expected_digest_size = SHA512_DIGEST_LENGTH * 2; |
| avb_verifier->hash_alg_ = HashAlgorithm::kSHA512; |
| } else { |
| LERROR << "Unknown hash algorithm: " << hash_alg.c_str(); |
| return nullptr; |
| } |
| |
| // Reads digest. |
| std::string digest; |
| fs_mgr_get_boot_config("vbmeta.digest", &digest); |
| if (digest.size() != expected_digest_size) { |
| LERROR << "Unexpected digest size: " << digest.size() |
| << " (expected: " << expected_digest_size << ")"; |
| return nullptr; |
| } |
| |
| if (!HexToBytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) { |
| LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str(); |
| return nullptr; |
| } |
| |
| return avb_verifier; |
| } |
| |
| bool AvbVerifier::VerifyVbmetaImages(const std::vector<VBMetaData>& vbmeta_images) { |
| if (vbmeta_images.empty()) { |
| LERROR << "No vbmeta images"; |
| return false; |
| } |
| |
| size_t total_size = 0; |
| bool digest_matched = false; |
| |
| if (hash_alg_ == HashAlgorithm::kSHA256) { |
| std::tie(total_size, digest_matched) = |
| VerifyVbmetaDigest<SHA256Hasher>(vbmeta_images, digest_); |
| } else if (hash_alg_ == HashAlgorithm::kSHA512) { |
| std::tie(total_size, digest_matched) = |
| VerifyVbmetaDigest<SHA512Hasher>(vbmeta_images, digest_); |
| } |
| |
| if (total_size != vbmeta_size_) { |
| LERROR << "total vbmeta size mismatch: " << total_size << " (expected: " << vbmeta_size_ |
| << ")"; |
| return false; |
| } |
| |
| if (!digest_matched) { |
| LERROR << "vbmeta digest mismatch"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // class AvbHandle |
| // --------------- |
| AvbHandle::AvbHandle() : status_(AvbHandleStatus::kUninitialized) { |
| slot_suffix_ = fs_mgr_get_slot_suffix(); |
| other_slot_suffix_ = fs_mgr_get_other_slot_suffix(); |
| } |
| |
| AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta( |
| const std::string& partition_name, const std::string& ab_suffix, |
| const std::string& ab_other_suffix, const std::string& expected_public_key_path, |
| const HashAlgorithm& hash_algorithm, bool allow_verification_error, |
| bool load_chained_vbmeta, bool rollback_protection, |
| std::function<std::string(const std::string&)> custom_device_path) { |
| AvbUniquePtr avb_handle(new AvbHandle()); |
| if (!avb_handle) { |
| LERROR << "Failed to allocate AvbHandle"; |
| return nullptr; |
| } |
| |
| avb_handle->slot_suffix_ = ab_suffix; |
| avb_handle->other_slot_suffix_ = ab_other_suffix; |
| |
| std::string expected_key_blob; |
| if (!expected_public_key_path.empty()) { |
| if (access(expected_public_key_path.c_str(), F_OK) != 0) { |
| LERROR << "Expected public key path doesn't exist: " << expected_public_key_path; |
| return nullptr; |
| } else if (!ReadFileToString(expected_public_key_path, &expected_key_blob)) { |
| LERROR << "Failed to load: " << expected_public_key_path; |
| return nullptr; |
| } |
| } |
| |
| auto android_by_name_symlink = [](const std::string& partition_name_with_ab) { |
| return "/dev/block/by-name/" + partition_name_with_ab; |
| }; |
| |
| auto device_path = custom_device_path ? custom_device_path : android_by_name_symlink; |
| |
| auto verify_result = LoadAndVerifyVbmetaByPartition( |
| partition_name, ab_suffix, ab_other_suffix, expected_key_blob, allow_verification_error, |
| load_chained_vbmeta, rollback_protection, device_path, false, |
| /* is_chained_vbmeta */ &avb_handle->vbmeta_images_); |
| switch (verify_result) { |
| case VBMetaVerifyResult::kSuccess: |
| avb_handle->status_ = AvbHandleStatus::kSuccess; |
| break; |
| case VBMetaVerifyResult::kErrorVerification: |
| avb_handle->status_ = AvbHandleStatus::kVerificationError; |
| break; |
| default: |
| LERROR << "LoadAndVerifyVbmetaByPartition failed, result: " << verify_result; |
| return nullptr; |
| } |
| |
| // Validity check here because we have to use vbmeta_images_[0] below. |
| if (avb_handle->vbmeta_images_.size() < 1) { |
| LERROR << "LoadAndVerifyVbmetaByPartition failed, no vbmeta loaded"; |
| return nullptr; |
| } |
| |
| // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version". |
| avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR); |
| |
| // Checks any disabled flag is set. |
| std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header = |
| avb_handle->vbmeta_images_[0].GetVBMetaHeader(); |
| bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header->flags & |
| AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED); |
| bool hashtree_disabled = |
| ((AvbVBMetaImageFlags)vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED); |
| if (verification_disabled) { |
| avb_handle->status_ = AvbHandleStatus::kVerificationDisabled; |
| } else if (hashtree_disabled) { |
| avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled; |
| } |
| |
| // Calculates the summary info for all vbmeta_images_; |
| std::string digest; |
| size_t total_size; |
| if (hash_algorithm == HashAlgorithm::kSHA256) { |
| std::tie(digest, total_size) = |
| CalculateVbmetaDigest<SHA256Hasher>(avb_handle->vbmeta_images_); |
| } else if (hash_algorithm == HashAlgorithm::kSHA512) { |
| std::tie(digest, total_size) = |
| CalculateVbmetaDigest<SHA512Hasher>(avb_handle->vbmeta_images_); |
| } else { |
| LERROR << "Invalid hash algorithm"; |
| return nullptr; |
| } |
| avb_handle->vbmeta_info_ = VBMetaInfo(digest, hash_algorithm, total_size); |
| |
| LINFO << "Returning avb_handle with status: " << avb_handle->status_; |
| return avb_handle; |
| } |
| |
| static bool IsAvbPermissive() { |
| if (IsDeviceUnlocked()) { |
| // Manually putting a file under metadata partition can enforce AVB verification. |
| if (!access(DSU_METADATA_PREFIX "avb_enforce", F_OK)) { |
| LINFO << "Enforcing AVB verification when the device is unlocked"; |
| return false; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry, |
| const std::vector<std::string>& preload_avb_key_blobs) { |
| // At least one of the following should be provided for public key matching. |
| if (preload_avb_key_blobs.empty() && fstab_entry.avb_keys.empty()) { |
| LERROR << "avb_keys=/path/to/key(s) is missing for " << fstab_entry.mount_point; |
| return nullptr; |
| } |
| |
| // Binds allow_verification_error and rollback_protection to device unlock state. |
| bool allow_verification_error = IsAvbPermissive(); |
| bool rollback_protection = !allow_verification_error; |
| |
| std::string public_key_data; |
| bool verification_disabled = false; |
| VBMetaVerifyResult verify_result = VBMetaVerifyResult::kError; |
| std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath( |
| fstab_entry.blk_device, "" /* partition_name, no need for a standalone path */, |
| "" /* expected_public_key_blob, */, allow_verification_error, rollback_protection, |
| false /* not is_chained_vbmeta */, &public_key_data, &verification_disabled, |
| &verify_result); |
| |
| if (!vbmeta) { |
| LERROR << "Failed to load vbmeta: " << fstab_entry.blk_device; |
| return nullptr; |
| } |
| |
| AvbUniquePtr avb_handle(new AvbHandle()); |
| if (!avb_handle) { |
| LERROR << "Failed to allocate AvbHandle"; |
| return nullptr; |
| } |
| avb_handle->vbmeta_images_.emplace_back(std::move(*vbmeta)); |
| |
| switch (verify_result) { |
| case VBMetaVerifyResult::kSuccess: |
| avb_handle->status_ = AvbHandleStatus::kSuccess; |
| break; |
| case VBMetaVerifyResult::kErrorVerification: |
| avb_handle->status_ = AvbHandleStatus::kVerificationError; |
| break; |
| default: |
| LERROR << "LoadAndVerifyVbmetaByPath failed, result: " << verify_result; |
| return nullptr; |
| } |
| |
| bool public_key_match = false; |
| // Performs key matching for preload_avb_key_blobs first, if it is present. |
| if (!public_key_data.empty() && !preload_avb_key_blobs.empty()) { |
| if (std::find(preload_avb_key_blobs.begin(), preload_avb_key_blobs.end(), |
| public_key_data) != preload_avb_key_blobs.end()) { |
| public_key_match = true; |
| } |
| } |
| // Performs key matching for fstab_entry.avb_keys if necessary. |
| // Note that it is intentional to match both preload_avb_key_blobs and fstab_entry.avb_keys. |
| // Some keys might only be availble before init chroots into /system, e.g., /avb/key1 |
| // in the first-stage ramdisk, while other keys might only be available after the chroot, |
| // e.g., /system/etc/avb/key2. |
| if (!public_key_data.empty() && !public_key_match) { |
| // fstab_entry.avb_keys might be either a directory containing multiple keys, |
| // or a string indicating multiple keys separated by ':'. |
| std::vector<std::string> allowed_avb_keys; |
| auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys); |
| if (list_avb_keys_in_dir.ok()) { |
| std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end()); |
| allowed_avb_keys = *list_avb_keys_in_dir; |
| } else { |
| allowed_avb_keys = Split(fstab_entry.avb_keys, ":"); |
| } |
| if (ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) { |
| public_key_match = true; |
| } |
| } |
| |
| if (!public_key_match) { |
| avb_handle->status_ = AvbHandleStatus::kVerificationError; |
| LWARNING << "Found unknown public key used to sign " << fstab_entry.mount_point; |
| if (!allow_verification_error) { |
| LERROR << "Unknown public key is not allowed"; |
| return nullptr; |
| } |
| } |
| |
| if (verification_disabled) { |
| LINFO << "AVB verification disabled on: " << fstab_entry.mount_point; |
| avb_handle->status_ = AvbHandleStatus::kVerificationDisabled; |
| } |
| |
| LINFO << "Returning avb_handle for '" << fstab_entry.mount_point |
| << "' with status: " << avb_handle->status_; |
| return avb_handle; |
| } |
| |
| AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const std::string& slot_suffix) { |
| // Loads inline vbmeta images, starting from /vbmeta. |
| auto suffix = slot_suffix; |
| if (suffix.empty()) { |
| suffix = fs_mgr_get_slot_suffix(); |
| } |
| auto other_suffix = android::fs_mgr::OtherSlotSuffix(suffix); |
| return LoadAndVerifyVbmeta("vbmeta", suffix, other_suffix, |
| {} /* expected_public_key, already checked by bootloader */, |
| HashAlgorithm::kSHA256, |
| IsAvbPermissive(), /* allow_verification_error */ |
| true, /* load_chained_vbmeta */ |
| false, /* rollback_protection, already checked by bootloader */ |
| nullptr /* custom_device_path */); |
| } |
| |
| // TODO(b/128807537): removes this function. |
| AvbUniquePtr AvbHandle::Open() { |
| bool allow_verification_error = IsAvbPermissive(); |
| |
| AvbUniquePtr avb_handle(new AvbHandle()); |
| if (!avb_handle) { |
| LERROR << "Failed to allocate AvbHandle"; |
| return nullptr; |
| } |
| |
| FsManagerAvbOps avb_ops; |
| AvbSlotVerifyFlags flags = allow_verification_error |
| ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR |
| : AVB_SLOT_VERIFY_FLAGS_NONE; |
| AvbSlotVerifyResult verify_result = |
| avb_ops.AvbSlotVerify(avb_handle->slot_suffix_, flags, &avb_handle->vbmeta_images_); |
| |
| // Only allow the following verify results: |
| // - AVB_SLOT_VERIFY_RESULT_OK. |
| // - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (UNLOCKED only). |
| // Might occur in either the top-level vbmeta or a chained vbmeta. |
| // - AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED (UNLOCKED only). |
| // Could only occur in a chained vbmeta. Because we have *no-op* operations in |
| // FsManagerAvbOps such that avb_ops->validate_vbmeta_public_key() used to validate |
| // the public key of the top-level vbmeta always pass in userspace here. |
| // |
| // The following verify result won't happen, because the *no-op* operation |
| // avb_ops->read_rollback_index() always returns the minimum value zero. So rollbacked |
| // vbmeta images, which should be caught in the bootloader stage, won't be detected here. |
| // - AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX |
| switch (verify_result) { |
| case AVB_SLOT_VERIFY_RESULT_OK: |
| avb_handle->status_ = AvbHandleStatus::kSuccess; |
| break; |
| case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: |
| case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: |
| if (!allow_verification_error) { |
| LERROR << "ERROR_VERIFICATION / PUBLIC_KEY_REJECTED isn't allowed "; |
| return nullptr; |
| } |
| avb_handle->status_ = AvbHandleStatus::kVerificationError; |
| break; |
| default: |
| LERROR << "avb_slot_verify failed, result: " << verify_result; |
| return nullptr; |
| } |
| |
| // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version". |
| avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR); |
| |
| // Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline. |
| std::unique_ptr<AvbVerifier> avb_verifier = AvbVerifier::Create(); |
| if (!avb_verifier || !avb_verifier->VerifyVbmetaImages(avb_handle->vbmeta_images_)) { |
| LERROR << "Failed to verify vbmeta digest"; |
| if (!allow_verification_error) { |
| LERROR << "vbmeta digest error isn't allowed "; |
| return nullptr; |
| } |
| } |
| |
| // Checks whether FLAGS_VERIFICATION_DISABLED is set: |
| // - Only the top-level vbmeta struct is read. |
| // - vbmeta struct in other partitions are NOT processed, including AVB HASH descriptor(s) |
| // and AVB HASHTREE descriptor(s). |
| AvbVBMetaImageHeader vbmeta_header; |
| avb_vbmeta_image_header_to_host_byte_order( |
| (AvbVBMetaImageHeader*)avb_handle->vbmeta_images_[0].data(), &vbmeta_header); |
| bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags & |
| AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED); |
| |
| // Checks whether FLAGS_HASHTREE_DISABLED is set. |
| // - vbmeta struct in all partitions are still processed, just disable |
| // dm-verity in the user space. |
| bool hashtree_disabled = |
| ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED); |
| |
| if (verification_disabled) { |
| avb_handle->status_ = AvbHandleStatus::kVerificationDisabled; |
| } else if (hashtree_disabled) { |
| avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled; |
| } |
| |
| LINFO << "Returning avb_handle with status: " << avb_handle->status_; |
| return avb_handle; |
| } |
| |
| AvbHashtreeResult AvbHandle::SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry, |
| bool wait_for_verity_dev) { |
| auto avb_handle = LoadAndVerifyVbmeta(*fstab_entry); |
| if (!avb_handle) { |
| return AvbHashtreeResult::kFail; |
| } |
| |
| return avb_handle->SetUpAvbHashtree(fstab_entry, wait_for_verity_dev); |
| } |
| |
| AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev) { |
| if (!fstab_entry || status_ == AvbHandleStatus::kUninitialized || vbmeta_images_.size() < 1) { |
| return AvbHashtreeResult::kFail; |
| } |
| |
| if (status_ == AvbHandleStatus::kHashtreeDisabled || |
| status_ == AvbHandleStatus::kVerificationDisabled) { |
| LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point; |
| return AvbHashtreeResult::kDisabled; |
| } |
| |
| if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images_, |
| slot_suffix_, other_slot_suffix_)) { |
| return AvbHashtreeResult::kFail; |
| } |
| |
| return AvbHashtreeResult::kSuccess; |
| } |
| |
| bool AvbHandle::TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait) { |
| if (!fstab_entry) { |
| return false; |
| } |
| |
| const std::string device_name(GetVerityDeviceName(*fstab_entry)); |
| |
| // TODO: remove duplicated code with UnmapDevice() |
| android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); |
| std::string path; |
| if (wait) { |
| dm.GetDmDevicePathByName(device_name, &path); |
| } |
| if (!dm.DeleteDevice(device_name)) { |
| return false; |
| } |
| if (!path.empty() && !WaitForFile(path, 1000ms, FileWaitMode::DoesNotExist)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) const { |
| if (vbmeta_images_.size() < 1) { |
| return ""; |
| } |
| std::string avb_partition_name = |
| DeriveAvbPartitionName(fstab_entry, slot_suffix_, other_slot_suffix_); |
| auto avb_prop_name = "com.android.build." + avb_partition_name + ".security_patch"; |
| return GetAvbPropertyDescriptor(avb_prop_name, vbmeta_images_); |
| } |
| |
| bool AvbHandle::IsDeviceUnlocked() { |
| return android::fs_mgr::IsDeviceUnlocked(); |
| } |
| |
| } // namespace fs_mgr |
| } // namespace android |