Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30fef71b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "libfs_avb: support enable verity for a standalone partition"

parents 8a5943b3 defe1cb5
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -1090,6 +1090,13 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
                // Skips mounting the device.
                continue;
            }
        } else if (!current_entry.avb_key.empty()) {
            if (AvbHandle::SetUpStandaloneAvbHashtree(&current_entry) == AvbHashtreeResult::kFail) {
                LERROR << "Failed to set up AVB on standalone partition: "
                       << current_entry.mount_point << ", skipping!";
                // Skips mounting the device.
                continue;
            }
        } else if ((current_entry.fs_mgr_flags.verify)) {
            int rc = fs_mgr_setup_verity(&current_entry, true);
            if (__android_log_is_debuggable() &&
@@ -1326,6 +1333,13 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name,
                // Skips mounting the device.
                continue;
            }
        } else if (!fstab_entry.avb_key.empty()) {
            if (AvbHandle::SetUpStandaloneAvbHashtree(&fstab_entry) == AvbHashtreeResult::kFail) {
                LERROR << "Failed to set up AVB on standalone partition: "
                       << fstab_entry.mount_point << ", skipping!";
                // Skips mounting the device.
                continue;
            }
        } else if (fstab_entry.fs_mgr_flags.verify) {
            int rc = fs_mgr_setup_verity(&fstab_entry, true);
            if (__android_log_is_debuggable() &&
+2 −0
Original line number Diff line number Diff line
@@ -338,6 +338,8 @@ static void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
        } else if (StartsWith(flag, "zram_backing_dev_path=")) {
            entry->fs_mgr_flags.zram_backing_dev_path = true;
            entry->zram_backing_dev_path = arg;
        } else if (StartsWith(flag, "avb_key=")) {
            entry->avb_key = arg;
        } else {
            LWARNING << "Warning: unknown flag: " << flag;
        }
+1 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ struct FstabEntry {
    std::string zram_loopback_path;
    uint64_t zram_loopback_size = 512 * 1024 * 1024;  // 512MB by default;
    std::string zram_backing_dev_path;
    std::string avb_key;

    // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
    // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
+138 −49
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include "util.h"

using android::base::Basename;
using android::base::StartsWith;
using android::base::unique_fd;

@@ -61,7 +62,7 @@ std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) {
// class VBMetaData
// ----------------
std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) {
    auto vbmeta_header(std::make_unique<AvbVBMetaImageHeader>());
    auto vbmeta_header = std::make_unique<AvbVBMetaImageHeader>();

    if (!vbmeta_header) return nullptr;

@@ -136,7 +137,7 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor&
    }
    table.set_readonly(true);

    const std::string mount_point(basename(fstab_entry->mount_point.c_str()));
    const std::string mount_point(Basename(fstab_entry->mount_point));
    android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
    if (!dm.CreateDevice(mount_point, table)) {
        LERROR << "Couldn't create verity device!";
@@ -163,12 +164,12 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor&
    return true;
}

bool GetHashtreeDescriptor(const std::string& partition_name,
                           const std::vector<VBMetaData>& vbmeta_images,
                           AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
                           std::string* out_digest) {
std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
    const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
    std::string* out_salt, std::string* out_digest) {
    bool found = false;
    const uint8_t* desc_partition_name;
    auto hashtree_desc = std::make_unique<AvbHashtreeDescriptor>();

    for (const auto& vbmeta : vbmeta_images) {
        size_t num_descriptors;
@@ -189,15 +190,15 @@ bool GetHashtreeDescriptor(const std::string& partition_name,
                desc_partition_name =
                        (const uint8_t*)descriptors[n] + sizeof(AvbHashtreeDescriptor);
                if (!avb_hashtree_descriptor_validate_and_byteswap(
                            (AvbHashtreeDescriptor*)descriptors[n], out_hashtree_desc)) {
                        (AvbHashtreeDescriptor*)descriptors[n], hashtree_desc.get())) {
                    continue;
                }
                if (out_hashtree_desc->partition_name_len != partition_name.length()) {
                if (hashtree_desc->partition_name_len != partition_name.length()) {
                    continue;
                }
                // Notes that desc_partition_name is not NUL-terminated.
                std::string hashtree_partition_name((const char*)desc_partition_name,
                                                    out_hashtree_desc->partition_name_len);
                                                    hashtree_desc->partition_name_len);
                if (hashtree_partition_name == partition_name) {
                    found = true;
                }
@@ -209,16 +210,43 @@ bool GetHashtreeDescriptor(const std::string& partition_name,

    if (!found) {
        LERROR << "Partition descriptor not found: " << partition_name.c_str();
        return false;
        return nullptr;
    }

    const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len;
    *out_salt = BytesToHex(desc_salt, out_hashtree_desc->salt_len);
    const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len;
    *out_salt = BytesToHex(desc_salt, hashtree_desc->salt_len);

    const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len;
    *out_digest = BytesToHex(desc_digest, out_hashtree_desc->root_digest_len);
    const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len;
    *out_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);

    return true;
    return hashtree_desc;
}

bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev,
                                   const std::vector<VBMetaData>& vbmeta_images,
                                   const std::string& ab_suffix,
                                   const std::string& ab_other_suffix) {
    // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
    // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
    std::string partition_name = DeriveAvbPartitionName(*fstab_entry, ab_suffix, ab_other_suffix);

    if (partition_name.empty()) {
        LERROR << "partition name is empty, cannot lookup AVB descriptors";
        return false;
    }

    std::string salt;
    std::string root_digest;
    std::unique_ptr<AvbHashtreeDescriptor> hashtree_descriptor =
        GetHashtreeDescriptor(partition_name, vbmeta_images, &salt, &root_digest);
    if (!hashtree_descriptor) {
        return false;
    }

    // Converts HASHTREE descriptor to verity table to load into kernel.
    // When success, the new device path will be returned, e.g., /dev/block/dm-2.
    return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, salt, root_digest,
                                 wait_for_verity_dev);
}

// Converts a AVB partition_name (without A/B suffix) to a device partition name.
@@ -244,6 +272,38 @@ std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
    return sanitized_partition_name + append_suffix;
}

// Converts fstab_entry.blk_device (with ab_suffix) to a AVB partition name.
// e.g., "/dev/block/by-name/system_a", slot_select       => "system",
//       "/dev/block/by-name/system_b", slot_select_other => "system_other".
//
// Or for a logical partition (with ab_suffix):
// e.g., "system_a", slot_select       => "system",
//       "system_b", slot_select_other => "system_other".
std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix,
                                   const std::string& ab_other_suffix) {
    std::string partition_name;
    if (fstab_entry.fs_mgr_flags.logical) {
        partition_name = fstab_entry.logical_partition_name;
    } else {
        partition_name = Basename(fstab_entry.blk_device);
    }

    if (fstab_entry.fs_mgr_flags.slot_select) {
        auto found = partition_name.rfind(ab_suffix);
        if (found != std::string::npos) {
            partition_name.erase(found);  // converts system_a => system
        }
    } else if (fstab_entry.fs_mgr_flags.slot_select_other) {
        auto found = partition_name.rfind(ab_other_suffix);
        if (found != std::string::npos) {
            partition_name.erase(found);  // converts system_b => system
        }
        partition_name += "_other";  // converts system => system_other
    }

    return partition_name;
}

off64_t GetTotalSize(int fd) {
    off64_t saved_current = lseek64(fd, 0, SEEK_CUR);
    if (saved_current == -1) {
@@ -268,19 +328,19 @@ off64_t GetTotalSize(int fd) {

std::unique_ptr<AvbFooter> GetAvbFooter(int fd) {
    std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf;
    auto footer(std::make_unique<AvbFooter>());
    auto footer = std::make_unique<AvbFooter>();

    off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE;

    ssize_t num_read =
            TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset));
    if (num_read < 0 || num_read != AVB_FOOTER_SIZE) {
        PERROR << "Failed to read AVB footer";
        PERROR << "Failed to read AVB footer at offset: " << footer_offset;
        return nullptr;
    }

    if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) {
        PERROR << "AVB footer verification failed.";
        PERROR << "AVB footer verification failed at offset " << footer_offset;
        return nullptr;
    }

@@ -432,24 +492,22 @@ std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fat
    return chain_partitions;
}

VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
        const std::string& partition_name, const std::string& ab_suffix,
        const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
        bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
        std::function<std::string(const std::string&)> device_path_constructor,
        bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) {
// Loads the vbmeta from a given path.
std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
    const std::string& image_path, const std::string& partition_name,
    const std::string& expected_public_key_blob, bool allow_verification_error,
    bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled,
    VBMetaVerifyResult* out_verify_result) {
    // Ensures the device path (might be a symlink created by init) is ready to access.
    auto device_path = device_path_constructor(
            AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));
    if (!WaitForFile(device_path, 1s)) {
        PERROR << "No such partition: " << device_path;
        return VBMetaVerifyResult::kError;
    if (!WaitForFile(image_path, 1s)) {
        PERROR << "No such path: " << image_path;
        return nullptr;
    }

    unique_fd fd(TEMP_FAILURE_RETRY(open(device_path.c_str(), O_RDONLY | O_CLOEXEC)));
    unique_fd fd(TEMP_FAILURE_RETRY(open(image_path.c_str(), O_RDONLY | O_CLOEXEC)));
    if (fd < 0) {
        PERROR << "Failed to open: " << device_path;
        return VBMetaVerifyResult::kError;
        PERROR << "Failed to open: " << image_path;
        return nullptr;
    }

    VBMetaVerifyResult verify_result;
@@ -457,49 +515,80 @@ VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
            VerifyVBMetaData(fd, partition_name, expected_public_key_blob, &verify_result);
    if (!vbmeta) {
        LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result;
        return VBMetaVerifyResult::kError;
        return nullptr;
    }
    vbmeta->set_vbmeta_path(image_path);

    if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) {
        LERROR << partition_name << ": allow verification error is not allowed";
        return VBMetaVerifyResult::kError;
        return nullptr;
    }

    std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
            vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
    if (!vbmeta_header) {
        LERROR << partition_name << ": Failed to get vbmeta header";
        return VBMetaVerifyResult::kError;
        return nullptr;
    }

    if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) {
        return VBMetaVerifyResult::kError;
        return nullptr;
    }

    // vbmeta flags can only be set by the top-level vbmeta image.
    if (is_chained_vbmeta && vbmeta_header->flags != 0) {
        LERROR << partition_name << ": chained vbmeta image has non-zero flags";
        return VBMetaVerifyResult::kError;
    }

    if (out_vbmeta_images) {
        out_vbmeta_images->emplace_back(std::move(*vbmeta));
        return nullptr;
    }

    // If verification has been disabled by setting a bit in the image, we're done.
    // Checks if verification has been disabled by setting a bit in the image.
    if (out_verification_disabled) {
        if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
            LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name;
        return verify_result;
            *out_verification_disabled = true;
        } else {
            *out_verification_disabled = false;
        }
    }

    if (out_verify_result) {
        *out_verify_result = verify_result;
    }

    return vbmeta;
}

VBMetaVerifyResult LoadAndVerifyVbmetaByPartition(
    const std::string& partition_name, const std::string& ab_suffix,
    const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
    bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
    std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta,
    std::vector<VBMetaData>* out_vbmeta_images) {
    auto image_path = device_path_constructor(
        AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));

    bool verification_disabled = false;
    VBMetaVerifyResult verify_result;
    auto vbmeta = LoadAndVerifyVbmetaByPath(
        image_path, partition_name, expected_public_key_blob, allow_verification_error,
        rollback_protection, is_chained_vbmeta, &verification_disabled, &verify_result);

    if (!vbmeta) {
        return VBMetaVerifyResult::kError;
    }
    if (out_vbmeta_images) {
        out_vbmeta_images->emplace_back(std::move(*vbmeta));
    }

    if (load_chained_vbmeta) {
    // Only loads chained vbmeta if AVB verification is NOT disabled.
    if (!verification_disabled && load_chained_vbmeta) {
        bool fatal_error = false;
        auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error);
        if (fatal_error) {
            return VBMetaVerifyResult::kError;
        }
        for (auto& chain : chain_partitions) {
            auto sub_ret = LoadAndVerifyVbmetaImpl(
            auto sub_ret = LoadAndVerifyVbmetaByPartition(
                chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob,
                allow_verification_error, load_chained_vbmeta, rollback_protection,
                device_path_constructor, true, /* is_chained_vbmeta */
+29 −11
Original line number Diff line number Diff line
@@ -46,10 +46,9 @@ struct ChainInfo {
};

// AvbHashtreeDescriptor to dm-verity table setup.
bool GetHashtreeDescriptor(const std::string& partition_name,
                           const std::vector<VBMetaData>& vbmeta_images,
                           AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
                           std::string* out_digest);
std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
    const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
    std::string* out_salt, std::string* out_digest);

bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
                          const std::string& root_digest, const std::string& blk_device,
@@ -59,11 +58,20 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor&
                           const std::string& salt, const std::string& root_digest,
                           bool wait_for_verity_dev);

// Maps AVB partition name to a device partition name.
// Searches a Avb hashtree descriptor in vbmeta_images for fstab_entry, to enable dm-verity.
bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev,
                                   const std::vector<VBMetaData>& vbmeta_images,
                                   const std::string& ab_suffix, const std::string& ab_other_suffix);

// Converts AVB partition name to a device partition name.
std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
                                         const std::string& ab_suffix,
                                         const std::string& ab_other_suffix);

// Converts by-name symlink to AVB partition name.
std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix,
                                   const std::string& ab_other_suffix);

// AvbFooter and AvbMetaImage maninpulations.
off64_t GetTotalSize(int fd);

@@ -84,12 +92,22 @@ bool RollbackDetected(const std::string& partition_name, uint64_t rollback_index
// Extracts chain partition info.
std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error);

VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
// Loads the single vbmeta from a given path.
std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
    const std::string& image_path, const std::string& partition_name,
    const std::string& expected_public_key_blob, bool allow_verification_error,
    bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled,
    VBMetaVerifyResult* out_verify_result);

// Loads the top-level vbmeta and all its chained vbmeta images.
// The actual device path is constructed at runtime by:
// partition_name, ab_suffix, ab_other_suffix, and device_path_constructor.
VBMetaVerifyResult LoadAndVerifyVbmetaByPartition(
    const std::string& partition_name, const std::string& ab_suffix,
    const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
    bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
        std::function<std::string(const std::string&)> device_path_constructor,
        bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images);
    std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta,
    std::vector<VBMetaData>* out_vbmeta_images);

}  // namespace fs_mgr
}  // namespace android
Loading