From ce2218ed6505de0dc84698fbf1e30a7a4ad35eee Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Fri, 8 Jun 2012 16:38:26 +0200 Subject: [PATCH] Support init_by_name for verity. --- lib/libdevmapper.c | 173 +++++++++++++++++++++++++++++++----- lib/loopaes/loopaes.c | 6 +- lib/luks1/keyencryption.c | 4 +- lib/luks1/keymanage.c | 6 +- lib/setup.c | 221 ++++++++++++++++++++++++++++++---------------- lib/utils_dm.h | 20 +++-- lib/verity/verity.c | 7 +- src/cryptsetup.c | 2 + src/veritysetup.c | 26 +++++- 9 files changed, 344 insertions(+), 121 deletions(-) diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index f2e66a4..e7d4a07 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -256,12 +256,31 @@ static void hex_key(char *hexkey, size_t key_size, const char *key) sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]); } +static int hex_to_bytes(const char *hex, char *result) +{ + char buf[3] = "xx\0", *endp; + int i, len; + + len = strlen(hex) / 2; + for (i = 0; i < len; i++) { + memcpy(buf, &hex[i * 2], 2); + result[i] = strtoul(buf, &endp, 16); + if (endp != &buf[2]) + return -EINVAL; + } + return i; +} + +/* http://code.google.com/p/cryptsetup/wiki/DMCrypt */ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd) { int r, max_size, null_cipher = 0; char *params, *hexkey; const char *features = ""; + if (!dmd) + return NULL; + if (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) { if (dm_flags() & DM_DISCARDS_SUPPORTED) { features = " 1 allow_discards"; @@ -283,14 +302,14 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd) hex_key(hexkey, dmd->u.crypt.vk->keylength, dmd->u.crypt.vk->key); max_size = strlen(hexkey) + strlen(dmd->u.crypt.cipher) + - strlen(dmd->u.crypt.device) + strlen(features) + 64; + strlen(dmd->data_device) + strlen(features) + 64; params = crypt_safe_alloc(max_size); if (!params) goto out; r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s", dmd->u.crypt.cipher, hexkey, dmd->u.crypt.iv_offset, - dmd->u.crypt.device, dmd->u.crypt.offset, features); + dmd->data_device, dmd->u.crypt.offset, features); if (r < 0 || r >= max_size) { crypt_safe_free(params); params = NULL; @@ -299,12 +318,17 @@ out: crypt_safe_free(hexkey); return params; } + +/* http://code.google.com/p/cryptsetup/wiki/DMVerity */ static char *get_dm_verity_params(struct crypt_params_verity *vp, struct crypt_dm_active_device *dmd) { int max_size, r; char *params = NULL, *hexroot = NULL, *hexsalt = NULL; + if (!vp || !dmd) + return NULL; + hexroot = crypt_safe_alloc(dmd->u.verity.root_hash_size * 2 + 1); if (!hexroot) goto out; @@ -316,7 +340,7 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp, hex_key(hexsalt, vp->salt_size, vp->salt); max_size = strlen(hexroot) + strlen(hexsalt) + - strlen(dmd->u.verity.data_device) + + strlen(dmd->data_device) + strlen(dmd->u.verity.hash_device) + strlen(vp->hash_name) + 128; @@ -326,7 +350,7 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp, r = snprintf(params, max_size, "%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s", - vp->version, dmd->u.verity.data_device, + vp->version, dmd->data_device, dmd->u.verity.hash_device, vp->data_block_size, vp->hash_block_size, vp->data_size, dmd->u.verity.hash_offset, @@ -581,7 +605,6 @@ out_no_removal: int dm_create_device(const char *name, const char *type, struct crypt_dm_active_device *dmd, - void *params, int reload) { char *table_params = NULL; @@ -589,12 +612,12 @@ int dm_create_device(const char *name, if (dmd->target == DM_CRYPT) table_params = get_dm_crypt_params(dmd); else if (dmd->target == DM_VERITY) - table_params = get_dm_verity_params(params, dmd); + table_params = get_dm_verity_params(dmd->u.verity.vp, dmd); if (!table_params) return -EINVAL; - return _dm_create_device(name, type, dmd->u.crypt.device, dmd->flags, + return _dm_create_device(name, type, dmd->data_device, dmd->flags, dmd->uuid, dmd->size, table_params, reload); } @@ -626,11 +649,18 @@ static int dm_status_dmi(const char *name, struct dm_info *dmi, next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); - if (!target_type || strcmp(target_type, target) != 0 || - start != 0 || next) - r = -EINVAL; - else - r = 0; + + if (!target_type || start != 0 || next) + goto out; + + if (target && strcmp(target_type, target)) + goto out; + + /* for target == NULL check all supported */ + if (!target && (strcmp(target_type, DM_CRYPT_TARGET) && + strcmp(target_type, DM_VERITY_TARGET))) + goto out; + r = 0; out: if (!r && status_line && !(*status_line = strdup(params))) r = -ENOMEM; @@ -646,7 +676,7 @@ int dm_status_device(const char *name) int r; struct dm_info dmi; - r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL); + r = dm_status_dmi(name, &dmi, NULL, NULL); if (r < 0) return r; @@ -684,6 +714,7 @@ int dm_status_verity_ok(const char *name) return r; } +/* FIXME use hex wrapper, user val wrappers for line parsing */ static int _dm_query_crypt(uint32_t get_flags, struct dm_info *dmi, char *params, @@ -693,11 +724,12 @@ static int _dm_query_crypt(uint32_t get_flags, char *rcipher, *key_, *rdevice, *endp, buffer[3], *arg; unsigned int i; + memset(dmd, 0, sizeof(*dmd)); dmd->target = DM_CRYPT; rcipher = strsep(¶ms, " "); /* cipher */ - if (get_flags & DM_ACTIVE_CIPHER) + if (get_flags & DM_ACTIVE_CRYPT_CIPHER) dmd->u.crypt.cipher = strdup(rcipher); /* skip */ @@ -714,7 +746,7 @@ static int _dm_query_crypt(uint32_t get_flags, /* device */ rdevice = strsep(¶ms, " "); if (get_flags & DM_ACTIVE_DEVICE) - dmd->u.crypt.device = crypt_lookup_dev(rdevice); + dmd->data_device = crypt_lookup_dev(rdevice); /*offset */ if (!params) @@ -750,17 +782,17 @@ static int _dm_query_crypt(uint32_t get_flags, } /* Never allow to return empty key */ - if ((get_flags & DM_ACTIVE_KEY) && dmi->suspended) { + if ((get_flags & DM_ACTIVE_CRYPT_KEY) && dmi->suspended) { log_dbg("Cannot read volume key while suspended."); return -EINVAL; } - if (get_flags & DM_ACTIVE_KEYSIZE) { + if (get_flags & DM_ACTIVE_CRYPT_KEYSIZE) { dmd->u.crypt.vk = crypt_alloc_volume_key(strlen(key_) / 2, NULL); if (!dmd->u.crypt.vk) return -ENOMEM; - if (get_flags & DM_ACTIVE_KEY) { + if (get_flags & DM_ACTIVE_CRYPT_KEY) { buffer[2] = '\0'; for(i = 0; i < dmd->u.crypt.vk->keylength; i++) { memcpy(buffer, &key_[i * 2], 2); @@ -783,8 +815,109 @@ static int _dm_query_verity(uint32_t get_flags, char *params, struct crypt_dm_active_device *dmd) { + struct crypt_params_verity *vp = NULL; + uint32_t val32; + uint64_t val64; + size_t len; + char *str, *str2; + + if (get_flags & DM_ACTIVE_VERITY_PARAMS) + vp = dmd->u.verity.vp; + + memset(dmd, 0, sizeof(*dmd)); + dmd->target = DM_VERITY; - return -EINVAL; + dmd->u.verity.vp = vp; + + /* version */ + val32 = strtoul(params, ¶ms, 10); + if (*params != ' ') + return -EINVAL; + if (vp) + vp->version = val32; + params++; + + /* data device */ + str = strsep(¶ms, " "); + if (!params) + return -EINVAL; + if (get_flags & DM_ACTIVE_DEVICE) + dmd->data_device = crypt_lookup_dev(str); + + /* hash device */ + str = strsep(¶ms, " "); + if (!params) + return -EINVAL; + if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE) + dmd->u.verity.hash_device = crypt_lookup_dev(str); + + /* data block size*/ + val32 = strtoul(params, ¶ms, 10); + if (*params != ' ') + return -EINVAL; + if (vp) + vp->data_block_size = val32; + params++; + + /* hash block size */ + val32 = strtoul(params, ¶ms, 10); + if (*params != ' ') + return -EINVAL; + if (vp) + vp->hash_block_size = val32; + params++; + + /* data blocks */ + val64 = strtoull(params, ¶ms, 10); + if (*params != ' ') + return -EINVAL; + if (vp) + vp->data_size = val64; + params++; + + /* hash start */ + val64 = strtoull(params, ¶ms, 10); + if (*params != ' ') + return -EINVAL; + dmd->u.verity.hash_offset = val64; + params++; + + /* hash algorithm */ + str = strsep(¶ms, " "); + if (!params) + return -EINVAL; + if (vp) + vp->hash_name = strdup(str); + + /* root digest */ + str = strsep(¶ms, " "); + if (!params) + return -EINVAL; + len = strlen(str) / 2; + dmd->u.verity.root_hash_size = len; + if (get_flags & DM_ACTIVE_VERITY_ROOT_HASH) { + if (!(str2 = malloc(len))) + return -ENOMEM; + if (hex_to_bytes(str, str2) != len) + return -EINVAL; + dmd->u.verity.root_hash = str2; + } + + /* salt */ + str = strsep(¶ms, " "); + if (params) + return -EINVAL; + if (vp) { + len = strlen(str) / 2; + vp->salt_size = len; + if (!(str2 = malloc(len))) + return -ENOMEM; + if (hex_to_bytes(str, str2) != len) + return -EINVAL; + vp->salt = str2; + } + + return 0; } int dm_query_device(const char *name, uint32_t get_flags, @@ -798,8 +931,6 @@ int dm_query_device(const char *name, uint32_t get_flags, void *next = NULL; int r = -EINVAL; - memset(dmd, 0, sizeof(*dmd)); - if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) goto out; if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt)) diff --git a/lib/loopaes/loopaes.c b/lib/loopaes/loopaes.c index 7a5f67b..35345eb 100644 --- a/lib/loopaes/loopaes.c +++ b/lib/loopaes/loopaes.c @@ -196,8 +196,8 @@ int LOOPAES_activate(struct crypt_device *cd, .uuid = crypt_get_uuid(cd), .size = 0, .flags = flags, + .data_device = crypt_get_device_name(cd), .u.crypt = { - .device = crypt_get_device_name(cd), .cipher = NULL, .vk = vk, .offset = crypt_get_data_offset(cd), @@ -206,7 +206,7 @@ int LOOPAES_activate(struct crypt_device *cd, }; - r = device_check_and_adjust(cd, dmd.u.crypt.device, DEV_EXCL, + r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL, &dmd.size, &dmd.u.crypt.offset, &flags); if (r) return r; @@ -225,7 +225,7 @@ int LOOPAES_activate(struct crypt_device *cd, log_dbg("Trying to activate loop-AES device %s using cipher %s.", name, dmd.u.crypt.cipher); - r = dm_create_device(name, CRYPT_LOOPAES, &dmd, NULL, 0); + r = dm_create_device(name, CRYPT_LOOPAES, &dmd, 0); if (!r && !(dm_flags() & req_flags)) { log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n")); diff --git a/lib/luks1/keyencryption.c b/lib/luks1/keyencryption.c index a2e0d31..c634b68 100644 --- a/lib/luks1/keyencryption.c +++ b/lib/luks1/keyencryption.c @@ -62,8 +62,8 @@ static int setup_mapping(const char *cipher, const char *name, .uuid = NULL, .size = 0, .flags = 0, + .data_device = device, .u.crypt = { - .device = device, .cipher = cipher, .vk = vk, .offset = sector, @@ -86,7 +86,7 @@ static int setup_mapping(const char *cipher, const char *name, dmd.size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE; cleaner_size = dmd.size; - return dm_create_device(name, "TEMP", &dmd, NULL, 0); + return dm_create_device(name, "TEMP", &dmd, 0); } static void sigint_handler(int sig __attribute__((unused))) diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index 95a4d27..50db7aa 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -1037,8 +1037,8 @@ int LUKS1_activate(struct crypt_device *cd, .uuid = crypt_get_uuid(cd), .flags = flags, .size = 0, + .data_device = crypt_get_device_name(cd), .u.crypt = { - .device = crypt_get_device_name(cd), .cipher = NULL, .vk = vk, .offset = crypt_get_data_offset(cd), @@ -1051,7 +1051,7 @@ int LUKS1_activate(struct crypt_device *cd, else device_check = DEV_EXCL; - r = device_check_and_adjust(cd, dmd.u.crypt.device, device_check, + r = device_check_and_adjust(cd, dmd.data_device, device_check, &dmd.size, &dmd.u.crypt.offset, &dmd.flags); if (r) @@ -1062,7 +1062,7 @@ int LUKS1_activate(struct crypt_device *cd, return -ENOMEM; dmd.u.crypt.cipher = dm_cipher; - r = dm_create_device(name, CRYPT_LUKS1, &dmd, NULL, 0); + r = dm_create_device(name, CRYPT_LUKS1, &dmd, 0); free(dm_cipher); return r; diff --git a/lib/setup.c b/lib/setup.c index 0d930ef..21053fd 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -305,8 +305,8 @@ int PLAIN_activate(struct crypt_device *cd, .uuid = crypt_get_uuid(cd), .size = size, .flags = flags, + .data_device = crypt_get_device_name(cd), .u.crypt = { - .device = crypt_get_device_name(cd), .cipher = NULL, .vk = vk, .offset = crypt_get_data_offset(cd), @@ -319,7 +319,7 @@ int PLAIN_activate(struct crypt_device *cd, else device_check = DEV_EXCL; - r = device_check_and_adjust(cd, dmd.u.crypt.device, device_check, + r = device_check_and_adjust(cd, dmd.data_device, device_check, &dmd.size, &dmd.u.crypt.offset, &dmd.flags); if (r) return r; @@ -335,7 +335,7 @@ int PLAIN_activate(struct crypt_device *cd, log_dbg("Trying to activate PLAIN device %s using cipher %s.", name, dmd.u.crypt.cipher); - r = dm_create_device(name, CRYPT_PLAIN, &dmd, NULL, 0); + r = dm_create_device(name, CRYPT_PLAIN, &dmd, 0); // FIXME if (!cd->plain_uuid && dm_query_device(name, DM_ACTIVE_UUID, &dmd) >= 0) @@ -677,15 +677,121 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit return r; } +static int _init_by_name_crypt(struct crypt_device *cd, const char *name) +{ + struct crypt_dm_active_device dmd = {}; + char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; + int key_nums, r; + + r = dm_query_device(name, DM_ACTIVE_DEVICE | + DM_ACTIVE_UUID | + DM_ACTIVE_CRYPT_CIPHER | + DM_ACTIVE_CRYPT_KEYSIZE, &dmd); + if (r < 0) + goto out; + + if (isPLAIN(cd->type)) { + cd->plain_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL; + cd->plain_hdr.hash = NULL; /* no way to get this */ + cd->plain_hdr.offset = dmd.u.crypt.offset; + cd->plain_hdr.skip = dmd.u.crypt.iv_offset; + cd->plain_key_size = dmd.u.crypt.vk->keylength; + + r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, NULL, cipher_mode); + if (!r) { + cd->plain_cipher = strdup(cipher); + cd->plain_cipher_mode = strdup(cipher_mode); + } + } else if (isLOOPAES(cd->type)) { + cd->loopaes_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL; + cd->loopaes_hdr.offset = dmd.u.crypt.offset; + + r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, + &key_nums, cipher_mode); + if (!r) { + cd->loopaes_cipher = strdup(cipher); + cd->loopaes_cipher_mode = strdup(cipher_mode); + /* version 3 uses last key for IV */ + if (dmd.u.crypt.vk->keylength % key_nums) + key_nums++; + cd->loopaes_key_size = dmd.u.crypt.vk->keylength / key_nums; + } + } else if (isLUKS(cd->type)) { + if (mdata_device(cd)) { + r = _crypt_load_luks1(cd, 0, 0); + if (r < 0) { + log_dbg("LUKS device header does not match active device."); + free(cd->type); + cd->type = NULL; + r = 0; + goto out; + } + /* check whether UUIDs match each other */ + r = crypt_uuid_cmp(dmd.uuid, cd->hdr.uuid); + if (r < 0) { + log_dbg("LUKS device header uuid: %s mismatches DM returned uuid %s", + cd->hdr.uuid, dmd.uuid); + free(cd->type); + cd->type = NULL; + r = 0; + goto out; + } + } + } +out: + crypt_free_volume_key(dmd.u.crypt.vk); + free(CONST_CAST(void*)dmd.u.crypt.cipher); + free(CONST_CAST(void*)dmd.data_device); + free(CONST_CAST(void*)dmd.uuid); + return r; +} + +static int _init_by_name_verity(struct crypt_device *cd, const char *name) +{ + struct crypt_params_verity params = {}; + struct crypt_dm_active_device dmd = { + .target = DM_VERITY, + .u.verity.vp = ¶ms, + }; + int r; + + r = dm_query_device(name, DM_ACTIVE_DEVICE | + DM_ACTIVE_UUID | + DM_ACTIVE_VERITY_HASH_DEVICE | + DM_ACTIVE_VERITY_PARAMS, &dmd); + if (r < 0) + goto out; + + if (isVERITY(cd->type)) { + cd->verity_flags = CRYPT_VERITY_NO_HEADER; //FIXME + //cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL; + cd->verity_hdr.data_size = params.data_size; + cd->verity_root_hash_size = dmd.u.verity.root_hash_size; + cd->verity_root_hash = NULL; + cd->verity_hdr.hash_name = params.hash_name; + cd->verity_hdr.data_device = NULL; + cd->verity_hdr.data_block_size = params.data_block_size; + cd->verity_hdr.hash_block_size = params.hash_block_size; + cd->verity_hdr.hash_area_offset = params.hash_area_offset; + cd->verity_hdr.version = params.version; + cd->verity_hdr.flags = params.flags; + cd->verity_hdr.salt_size = params.salt_size; + cd->verity_hdr.salt = params.salt; + } +out: + free(CONST_CAST(void*)dmd.u.verity.hash_device); + free(CONST_CAST(void*)dmd.data_device); + free(CONST_CAST(void*)dmd.uuid); + return r; +} + int crypt_init_by_name_and_header(struct crypt_device **cd, const char *name, const char *header_device) { crypt_status_info ci; struct crypt_dm_active_device dmd; - char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; - int key_nums, r; - + int r; log_dbg("Allocating crypt device context by device %s.", name); @@ -698,8 +804,7 @@ int crypt_init_by_name_and_header(struct crypt_device **cd, return -ENODEV; } - r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_CIPHER | - DM_ACTIVE_UUID | DM_ACTIVE_KEYSIZE, &dmd); + r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &dmd); if (r < 0) goto out; @@ -708,17 +813,17 @@ int crypt_init_by_name_and_header(struct crypt_device **cd, if (header_device) { r = crypt_init(cd, header_device); } else { - r = crypt_init(cd, dmd.u.crypt.device); + r = crypt_init(cd, dmd.data_device); /* Underlying device disappeared but mapping still active */ - if (!dmd.u.crypt.device || r == -ENOTBLK) + if (!dmd.data_device || r == -ENOTBLK) log_verbose(NULL, _("Underlying device for crypt device %s disappeared.\n"), name); /* Underlying device is not readable but crypt mapping exists */ if (r == -ENOTBLK) { - free(CONST_CAST(void*)dmd.u.crypt.device); - dmd.u.crypt.device = NULL; + free(CONST_CAST(void*)dmd.data_device); + dmd.data_device = NULL; r = crypt_init(cd, NULL); } } @@ -733,83 +838,38 @@ int crypt_init_by_name_and_header(struct crypt_device **cd, (*cd)->type = strdup(CRYPT_LOOPAES); else if (!strncmp(CRYPT_LUKS1, dmd.uuid, sizeof(CRYPT_LUKS1)-1)) (*cd)->type = strdup(CRYPT_LUKS1); + else if (!strncmp(CRYPT_VERITY, dmd.uuid, sizeof(CRYPT_VERITY)-1)) + (*cd)->type = strdup(CRYPT_VERITY); else log_dbg("Unknown UUID set, some parameters are not set."); } else log_dbg("Active device has no UUID set, some parameters are not set."); if (header_device) { - r = crypt_set_data_device(*cd, dmd.u.crypt.device); + r = crypt_set_data_device(*cd, dmd.data_device); if (r < 0) goto out; } /* Try to initialise basic parameters from active device */ - if (!(*cd)->backing_file && dmd.u.crypt.device && - crypt_loop_device(dmd.u.crypt.device) && - !((*cd)->backing_file = crypt_loop_backing_file(dmd.u.crypt.device))) { + if (!(*cd)->backing_file && dmd.data_device && + crypt_loop_device(dmd.data_device) && + !((*cd)->backing_file = crypt_loop_backing_file(dmd.data_device))) { r = -ENOMEM; goto out; } - if (isPLAIN((*cd)->type)) { - (*cd)->plain_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL; - (*cd)->plain_hdr.hash = NULL; /* no way to get this */ - (*cd)->plain_hdr.offset = dmd.u.crypt.offset; - (*cd)->plain_hdr.skip = dmd.u.crypt.iv_offset; - (*cd)->plain_key_size = dmd.u.crypt.vk->keylength; - - r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, NULL, cipher_mode); - if (!r) { - (*cd)->plain_cipher = strdup(cipher); - (*cd)->plain_cipher_mode = strdup(cipher_mode); - } - } else if (isLOOPAES((*cd)->type)) { - (*cd)->loopaes_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL; - (*cd)->loopaes_hdr.offset = dmd.u.crypt.offset; - - r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, - &key_nums, cipher_mode); - if (!r) { - (*cd)->loopaes_cipher = strdup(cipher); - (*cd)->loopaes_cipher_mode = strdup(cipher_mode); - /* version 3 uses last key for IV */ - if (dmd.u.crypt.vk->keylength % key_nums) - key_nums++; - (*cd)->loopaes_key_size = dmd.u.crypt.vk->keylength / key_nums; - } - } else if (isLUKS((*cd)->type)) { - if (mdata_device(*cd)) { - r = _crypt_load_luks1(*cd, 0, 0); - if (r < 0) { - log_dbg("LUKS device header does not match active device."); - free((*cd)->type); - (*cd)->type = NULL; - r = 0; - goto out; - } - /* checks whether UUIDs match each other */ - r = crypt_uuid_cmp(dmd.uuid, (*cd)->hdr.uuid); - if (r < 0) { - log_dbg("LUKS device header uuid: %s mismatches DM returned uuid %s", - (*cd)->hdr.uuid, dmd.uuid); - free((*cd)->type); - (*cd)->type = NULL; - r = 0; - goto out; - } - } - } - + if (dmd.target == DM_CRYPT) + r = _init_by_name_crypt(*cd, name); + else if (dmd.target == DM_VERITY) + r = _init_by_name_verity(*cd, name); out: if (r < 0) { crypt_free(*cd); *cd = NULL; } - crypt_free_volume_key(dmd.u.crypt.vk); - free(CONST_CAST(void*)dmd.u.crypt.device); - free(CONST_CAST(void*)dmd.u.crypt.cipher); + free(CONST_CAST(void*)dmd.data_device); free(CONST_CAST(void*)dmd.uuid); return r; } @@ -1171,20 +1231,20 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) log_dbg("Resizing device %s to %" PRIu64 " sectors.", name, new_size); - r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_CIPHER | - DM_ACTIVE_UUID | DM_ACTIVE_KEYSIZE | - DM_ACTIVE_KEY, &dmd); + r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER | + DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE | + DM_ACTIVE_CRYPT_KEY, &dmd); if (r < 0) { log_err(NULL, _("Device %s is not active.\n"), name); - goto out; + return -EINVAL; } - if (!dmd.uuid) { + if (!dmd.uuid || dmd.target != DM_CRYPT) { r = -EINVAL; goto out; } - r = device_check_and_adjust(cd, dmd.u.crypt.device, DEV_OK, &new_size, + r = device_check_and_adjust(cd, dmd.data_device, DEV_OK, &new_size, &dmd.u.crypt.offset, &dmd.flags); if (r) goto out; @@ -1195,12 +1255,14 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) r = 0; } else { dmd.size = new_size; - r = dm_create_device(name, cd->type, &dmd, NULL, 1); + r = dm_create_device(name, cd->type, &dmd, 1); } out: - crypt_free_volume_key(dmd.u.crypt.vk); - free(CONST_CAST(void*)dmd.u.crypt.cipher); - free(CONST_CAST(void*)dmd.u.crypt.device); + if (dmd.target == DM_CRYPT) { + crypt_free_volume_key(dmd.u.crypt.vk); + free(CONST_CAST(void*)dmd.u.crypt.cipher); + } + free(CONST_CAST(void*)dmd.data_device); free(CONST_CAST(void*)dmd.uuid); return r; @@ -2342,6 +2404,9 @@ int crypt_get_active_device(struct crypt_device *cd __attribute__((unused)), if (r < 0) return r; + if (dmd.target != DM_CRYPT) + return -ENOTSUP; + cad->offset = dmd.u.crypt.offset; cad->iv_offset = dmd.u.crypt.iv_offset; cad->size = dmd.size; diff --git a/lib/utils_dm.h b/lib/utils_dm.h index 7a8c8cc..5a0756e 100644 --- a/lib/utils_dm.h +++ b/lib/utils_dm.h @@ -39,19 +39,24 @@ struct crypt_params_verity; uint32_t dm_flags(void); #define DM_ACTIVE_DEVICE (1 << 0) -#define DM_ACTIVE_CIPHER (1 << 1) -#define DM_ACTIVE_UUID (1 << 2) -#define DM_ACTIVE_KEYSIZE (1 << 3) -#define DM_ACTIVE_KEY (1 << 4) +#define DM_ACTIVE_UUID (1 << 1) + +#define DM_ACTIVE_CRYPT_CIPHER (1 << 2) +#define DM_ACTIVE_CRYPT_KEYSIZE (1 << 3) +#define DM_ACTIVE_CRYPT_KEY (1 << 4) + +#define DM_ACTIVE_VERITY_ROOT_HASH (1 << 5) +#define DM_ACTIVE_VERITY_HASH_DEVICE (1 << 6) +#define DM_ACTIVE_VERITY_PARAMS (1 << 7) struct crypt_dm_active_device { enum { DM_CRYPT = 0, DM_VERITY } target; uint64_t size; /* active device size */ uint32_t flags; /* activation flags */ const char *uuid; + const char *data_device; union { struct { - const char *device; const char *cipher; /* Active key for device */ @@ -62,13 +67,13 @@ struct crypt_dm_active_device { uint64_t iv_offset; /* IV initilisation sector */ } crypt; struct { - const char *data_device; const char *hash_device; const char *root_hash; - size_t root_hash_size; + uint32_t root_hash_size; uint64_t hash_offset; /* hash offset (not header) */ + struct crypt_params_verity *vp; } verity; } u; }; @@ -85,7 +90,6 @@ int dm_query_device(const char *name, uint32_t get_flags, int dm_create_device(const char *name, const char *type, struct crypt_dm_active_device *dmd, - void *params, int reload); int dm_suspend_and_wipe_key(const char *name); int dm_resume_and_reinstate_key(const char *name, diff --git a/lib/verity/verity.c b/lib/verity/verity.c index 81d6349..b53edba 100644 --- a/lib/verity/verity.c +++ b/lib/verity/verity.c @@ -190,7 +190,7 @@ int VERITY_activate(struct crypt_device *cd, return 0; dmd.target = DM_VERITY; - dmd.u.verity.data_device = crypt_get_device_name(cd); + dmd.data_device = crypt_get_device_name(cd); dmd.u.verity.hash_device = hash_device; dmd.u.verity.root_hash = root_hash; dmd.u.verity.root_hash_size = root_hash_size; @@ -198,13 +198,14 @@ int VERITY_activate(struct crypt_device *cd, dmd.flags = CRYPT_ACTIVATE_READONLY; dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512; dmd.uuid = NULL; + dmd.u.verity.vp = verity_hdr; - r = device_check_and_adjust(cd, dmd.u.verity.data_device, DEV_EXCL, + r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL, &dmd.size, &offset, &dmd.flags); if (r) return r; - r = dm_create_device(name, CRYPT_VERITY, &dmd, verity_hdr, 0); + r = dm_create_device(name, CRYPT_VERITY, &dmd, 0); if (!r && !(dm_flags() & DM_VERITY_SUPPORTED)) { log_err(cd, _("Kernel doesn't support dm-verity mapping.\n")); return -ENOTSUP; diff --git a/src/cryptsetup.c b/src/cryptsetup.c index dde6aec..8b3228b 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -489,6 +489,8 @@ static int action_status(int arg __attribute__((unused))) } out: crypt_free(cd); + if (r == -ENOTSUP) + r = 0; return r; } diff --git a/src/veritysetup.c b/src/veritysetup.c index e6a08e4..87b2ab6 100644 --- a/src/veritysetup.c +++ b/src/veritysetup.c @@ -18,11 +18,11 @@ */ /* TODO: - * - init_by_name() * - support device without superblock * - audit alloc errors / error path * - change command names (cryptsetup style) * - extend superblock (UUID) + * - add api tests */ #include @@ -40,6 +40,7 @@ #define MODE_CREATE 1 #define MODE_ACTIVATE 2 #define MODE_DUMP 3 +#define MODE_STATUS 4 static int mode = -1; static int use_superblock = 1; /* FIXME: no superblock not supported */ @@ -145,6 +146,18 @@ static int action_dump(void) return r; } +static int action_status(void) +{ + struct crypt_device *cd = NULL; + int r; + + r = crypt_init_by_name_and_header(&cd, dm_device, NULL); + if (!r) + r = crypt_dump(cd); + crypt_free(cd); + return r; +} + static int action_activate(int verify) { struct crypt_device *cd = NULL; @@ -292,6 +305,7 @@ int main(int argc, const char **argv) { "verify", 'v', POPT_ARG_VAL, &mode, MODE_VERIFY, "Verify integrity", NULL }, { "activate", 'a', POPT_ARG_VAL, &mode, MODE_ACTIVATE, "Activate the device", NULL }, { "dump", 'd', POPT_ARG_VAL, &mode, MODE_DUMP, "Dump the device", NULL }, + { "status", 's', POPT_ARG_VAL, &mode, MODE_STATUS, "Status active device", NULL }, { "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, "Do not create/use superblock" }, { "format", 0, POPT_ARG_INT, &version, 0, "Format version (1 - normal format, 0 - original Chromium OS format)", "number" }, { "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, "Block size on the data device", "bytes" }, @@ -335,7 +349,7 @@ int main(int argc, const char **argv) usage(popt_context, EXIT_FAILURE, _("Unknown action."), poptGetInvocationName(popt_context)); - if (mode == MODE_ACTIVATE) { + if (mode == MODE_ACTIVATE || mode == MODE_STATUS) { dm_device = poptGetArg(popt_context); if (!dm_device || !*dm_device) usage(popt_context, EXIT_FAILURE, @@ -343,6 +357,9 @@ int main(int argc, const char **argv) poptGetInvocationName(popt_context)); } + if (mode == MODE_STATUS) + goto run; //FIXME + data_device = poptGetArg(popt_context); if (!data_device) usage(popt_context, EXIT_FAILURE, _("Missing data device name."), @@ -383,7 +400,7 @@ int main(int argc, const char **argv) salt_string = ""; salt_size = strlen(salt_string) / 2; } - +run: if (opt_debug) { opt_verbose = 1; crypt_set_debug_level(-1); @@ -403,6 +420,9 @@ int main(int argc, const char **argv) case MODE_DUMP: r = action_dump(); break; + case MODE_STATUS: + r = action_status(); + break; } poptFreeContext(popt_context); -- 2.7.4