From 4ae302af7d0f72559ffb8dd521f290b02fed3072 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 21 Sep 2015 15:12:29 +0100 Subject: [PATCH] fs_mgr: trigger dm-verity error handling for invalid signatures Currently, the device doesn't mount verified partitions if the verity table signature is invalid, which usually means it fails to boot. This change instead sets up dm-verity with an invalid root hash and triggers device-specific error handling to recover from the corruption. Bug: 24256506 Change-Id: I6d693306fa0e7459c5500b028e433df61ecea6fb (cherry picked from commit 47caa5c386b436ba13de9f2ef356380f39afaf3f) --- fs_mgr/fs_mgr_verity.c | 54 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c index 60f53982f..a9e3358b2 100644 --- a/fs_mgr/fs_mgr_verity.c +++ b/fs_mgr/fs_mgr_verity.c @@ -47,6 +47,8 @@ #define VERITY_METADATA_SIZE 32768 #define VERITY_TABLE_RSA_KEY "/verity_key" +#define VERITY_TABLE_HASH_IDX 8 +#define VERITY_TABLE_SALT_IDX 9 #define METADATA_MAGIC 0x01564c54 #define METADATA_TAG_MAX_LENGTH 63 @@ -141,6 +143,33 @@ static int verify_table(char *signature, char *table, int table_length) return retval; } +static int invalidate_table(char *table, int table_length) +{ + int n = 0; + int idx = 0; + int cleared = 0; + + while (n < table_length) { + if (table[n++] == ' ') { + ++idx; + } + + if (idx != VERITY_TABLE_HASH_IDX && idx != VERITY_TABLE_SALT_IDX) { + continue; + } + + while (n < table_length && table[n] != ' ') { + table[n++] = '0'; + } + + if (++cleared == 2) { + return 0; + } + } + + return -1; +} + static int squashfs_get_target_device_size(char *blk_device, uint64_t *device_size) { struct squashfs_info sq_info; @@ -957,6 +986,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { char *verity_blk_name = 0; char *verity_table = 0; char *verity_table_signature = 0; + int verity_table_length = 0; uint64_t device_size = 0; _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE]; @@ -983,6 +1013,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { } retval = FS_MGR_SETUP_VERITY_FAIL; + verity_table_length = strlen(verity_table); // get the device mapper fd if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { @@ -1002,13 +1033,6 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { goto out; } - // verify the signature on the table - if (verify_table(verity_table_signature, - verity_table, - strlen(verity_table)) < 0) { - goto out; - } - if (load_verity_state(fstab, &mode) < 0) { /* if accessing or updating the state failed, switch to the default * safe mode. This makes sure the device won't end up in an endless @@ -1017,6 +1041,22 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { mode = VERITY_MODE_EIO; } + // verify the signature on the table + if (verify_table(verity_table_signature, + verity_table, + verity_table_length) < 0) { + if (mode == VERITY_MODE_LOGGING) { + // the user has been warned, allow mounting without dm-verity + retval = FS_MGR_SETUP_VERITY_SUCCESS; + goto out; + } + + // invalidate root hash and salt to trigger device-specific recovery + if (invalidate_table(verity_table, verity_table_length) < 0) { + goto out; + } + } + INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, mode); // load the verity mapping table