From 6879cc1e2ee91f47fa05a01dfbce9dfef7504501 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Thu, 11 May 2017 22:05:23 +0800 Subject: [PATCH] fs_mgr: support different dm-verity error modes AVB is going to support different modes to handle dm-verity errors. See the following CL for more details: - https://android-review.googlesource.com/#/c/392873/ The verity mode is controlled by bootloader through androidboot.veritymode in kernel command line. fs_mgr should read the value from there and specify the corresponding flag when loading dm-verity table into kernel. Also removes some unused #include libraries. Bug: 38157502 Test: Manually tested different dm verity modes: - "restart_on_corruption" (androidboot.veritymode=enforcing) - "ignore_corruption" (androidboot.veritymode=logging) - None, default mode is EIO in kernel (androidboot.veritymode=eio) Change-Id: I80e1e817a148b54fb67ba58112d376dc2cf37c98 --- fs_mgr/fs_mgr_avb.cpp | 170 +++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 75 deletions(-) diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp index 2b3220127..661800374 100644 --- a/fs_mgr/fs_mgr_avb.cpp +++ b/fs_mgr/fs_mgr_avb.cpp @@ -16,15 +16,14 @@ #include "fs_mgr_avb.h" -#include #include -#include #include -#include #include -#include +#include #include -#include + +#include +#include #include #include @@ -33,11 +32,7 @@ #include #include #include -#include #include -#include -#include -#include #include "fs_mgr.h" #include "fs_mgr_priv.h" @@ -45,48 +40,6 @@ #include "fs_mgr_priv_dm_ioctl.h" #include "fs_mgr_priv_sha.h" -/* The format of dm-verity construction parameters: - * - * - */ -#define VERITY_TABLE_FORMAT \ - "%u %s %s %u %u " \ - "%" PRIu64 " %" PRIu64 " %s %s %s " - -#define VERITY_TABLE_PARAMS(hashtree_desc, blk_device, digest, salt) \ - hashtree_desc.dm_verity_version, blk_device, blk_device, hashtree_desc.data_block_size, \ - hashtree_desc.hash_block_size, \ - hashtree_desc.image_size / hashtree_desc.data_block_size, /* num_data_blocks. */ \ - hashtree_desc.tree_offset / hashtree_desc.hash_block_size, /* hash_start_block. */ \ - (char*)hashtree_desc.hash_algorithm, digest, salt - -#define VERITY_TABLE_OPT_RESTART "restart_on_corruption" -#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks" - -/* The default format of dm-verity optional parameters: - * <#opt_params> ignore_zero_blocks restart_on_corruption - */ -#define VERITY_TABLE_OPT_DEFAULT_FORMAT "2 %s %s" -#define VERITY_TABLE_OPT_DEFAULT_PARAMS VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART - -/* The FEC (forward error correction) format of dm-verity optional parameters: - * <#opt_params> use_fec_from_device - * fec_roots fec_blocks fec_start - * ignore_zero_blocks restart_on_corruption - */ -#define VERITY_TABLE_OPT_FEC_FORMAT \ - "10 use_fec_from_device %s fec_roots %u fec_blocks %" PRIu64 " fec_start %" PRIu64 " %s %s" - -/* Note that fec_blocks is the size that FEC covers, *not* the - * size of the FEC data. Since we use FEC for everything up until - * the FEC data, it's the same as the offset (fec_start). - */ -#define VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device) \ - blk_device, hashtree_desc.fec_num_roots, \ - hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_blocks */ \ - hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_start */ \ - VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART - static inline bool nibble_value(const char& c, uint8_t* value) { FS_MGR_CHECK(value != nullptr); @@ -280,10 +233,81 @@ bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_da return true; } -static bool hashtree_load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name, - int fd, const std::string& blk_device, - const AvbHashtreeDescriptor& hashtree_desc, - const std::string& salt, const std::string& root_digest) { +// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel. +// See the following link for more details: +// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity +static std::string construct_verity_table(const AvbHashtreeDescriptor& hashtree_desc, + const std::string& salt, const std::string& root_digest, + const std::string& blk_device) { + // Loads androidboot.veritymode from kernel cmdline. + std::string verity_mode; + if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) { + verity_mode = "enforcing"; // Defaults to enforcing when it's absent. + } + + // Converts veritymode to the format used in kernel. + std::string dm_verity_mode; + if (verity_mode == "enforcing") { + dm_verity_mode = "restart_on_corruption"; + } else if (verity_mode == "logging") { + dm_verity_mode = "ignore_corruption"; + } else if (verity_mode != "eio") { // Default dm_verity_mode is eio. + LERROR << "Unknown androidboot.veritymode: " << verity_mode; + return ""; + } + + // dm-verity construction parameters: + // + // + // + // + // [<#opt_params> ] + std::ostringstream verity_table; + verity_table << hashtree_desc.dm_verity_version << " " << blk_device << " " << blk_device << " " + << hashtree_desc.data_block_size << " " << hashtree_desc.hash_block_size << " " + << hashtree_desc.image_size / hashtree_desc.data_block_size << " " + << hashtree_desc.tree_offset / hashtree_desc.hash_block_size << " " + << hashtree_desc.hash_algorithm << " " << root_digest << " " << salt; + + // Continued from the above optional parameters: + // [<#opt_params> ] + int optional_argc = 0; + std::ostringstream optional_args; + + // dm-verity optional parameters for FEC (forward error correction): + // use_fec_from_device + // fec_roots + // fec_blocks + // fec_start + if (hashtree_desc.fec_size > 0) { + // Note that fec_blocks is the size that FEC covers, *NOT* the + // size of the FEC data. Since we use FEC for everything up until + // the FEC data, it's the same as the offset (fec_start). + optional_argc += 8; + // clang-format off + optional_args << "use_fec_from_device " << blk_device + << " fec_roots " << hashtree_desc.fec_num_roots + << " fec_blocks " << hashtree_desc.fec_offset / hashtree_desc.data_block_size + << " fec_start " << hashtree_desc.fec_offset / hashtree_desc.data_block_size + << " "; + // clang-format on + } + + if (!dm_verity_mode.empty()) { + optional_argc += 1; + optional_args << dm_verity_mode << " "; + } + + // Always use ignore_zero_blocks. + optional_argc += 1; + optional_args << "ignore_zero_blocks"; + + verity_table << " " << optional_argc << " " << optional_args.str(); + return verity_table.str(); +} + +static bool load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name, int fd, + uint64_t image_size, const std::string& verity_table) { fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG); // The buffer consists of [dm_ioctl][dm_target_spec][verity_params]. @@ -294,35 +318,25 @@ static bool hashtree_load_verity_table(struct dm_ioctl* io, const std::string& d io->target_count = 1; dm_target->status = 0; dm_target->sector_start = 0; - dm_target->length = hashtree_desc.image_size / 512; + dm_target->length = image_size / 512; strcpy(dm_target->target_type, "verity"); // Builds the verity params. char* verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); size_t bufsize = DM_BUF_SIZE - (verity_params - buffer); - int res = 0; - if (hashtree_desc.fec_size > 0) { - res = snprintf(verity_params, bufsize, VERITY_TABLE_FORMAT VERITY_TABLE_OPT_FEC_FORMAT, - VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(), root_digest.c_str(), - salt.c_str()), - VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device.c_str())); - } else { - res = snprintf(verity_params, bufsize, VERITY_TABLE_FORMAT VERITY_TABLE_OPT_DEFAULT_FORMAT, - VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(), root_digest.c_str(), - salt.c_str()), - VERITY_TABLE_OPT_DEFAULT_PARAMS); - } + LINFO << "Loading verity table: '" << verity_table << "'"; - if (res < 0 || (size_t)res >= bufsize) { - LERROR << "Error building verity table; insufficient buffer size?"; + // Copies verity_table to verity_params (including the terminating null byte). + if (verity_table.size() > bufsize - 1) { + LERROR << "Verity table size too large: " << verity_table.size() + << " (max allowable size: " << bufsize - 1 << ")"; return false; } - - LINFO << "Loading verity table: '" << verity_params << "'"; + memcpy(verity_params, verity_table.c_str(), verity_table.size() + 1); // Sets ext target boundary. - verity_params += strlen(verity_params) + 1; + verity_params += verity_table.size() + 1; verity_params = (char*)(((unsigned long)verity_params + 7) & ~7); dm_target->next = verity_params - buffer; @@ -362,9 +376,15 @@ static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry, return false; } + std::string verity_table = + construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device); + if (verity_table.empty()) { + LERROR << "Failed to construct verity table."; + return false; + } + // Loads the verity mapping table. - if (!hashtree_load_verity_table(io, mount_point, fd, std::string(fstab_entry->blk_device), - hashtree_desc, salt, root_digest)) { + if (!load_verity_table(io, mount_point, fd, hashtree_desc.image_size, verity_table)) { LERROR << "Couldn't load verity table!"; return false; }