diff options
Diffstat (limited to 'lib/libdevmapper.c')
-rw-r--r-- | lib/libdevmapper.c | 409 |
1 files changed, 264 insertions, 145 deletions
diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index a82163b..62e084f 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -3,8 +3,8 @@ * * Copyright (C) 2004 Jana Saout <jana@saout.de> * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org> - * Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved. - * Copyright (C) 2009-2020 Milan Broz + * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved. + * Copyright (C) 2009-2021 Milan Broz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,7 +33,7 @@ #ifdef HAVE_SYS_SYSMACROS_H # include <sys/sysmacros.h> /* for major, minor */ #endif - +#include <assert.h> #include "internal.h" #define DM_UUID_LEN 129 @@ -174,6 +174,9 @@ static void _dm_set_crypt_compat(struct crypt_device *cd, if (_dm_satisfies_version(1, 20, 0, crypt_maj, crypt_min, crypt_patch)) _dm_flags |= DM_BITLK_ELEPHANT_SUPPORTED; + if (_dm_satisfies_version(1, 22, 0, crypt_maj, crypt_min, crypt_patch)) + _dm_flags |= DM_CRYPT_NO_WORKQUEUE_SUPPORTED; + _dm_crypt_checked = true; } @@ -205,6 +208,9 @@ static void _dm_set_verity_compat(struct crypt_device *cd, if (_dm_satisfies_version(1, 5, 0, verity_maj, verity_min, verity_patch)) _dm_flags |= DM_VERITY_SIGNATURE_SUPPORTED; + if (_dm_satisfies_version(1, 7, 0, verity_maj, verity_min, verity_patch)) + _dm_flags |= DM_VERITY_PANIC_CORRUPTION_SUPPORTED; + _dm_verity_checked = true; } @@ -233,6 +239,9 @@ static void _dm_set_integrity_compat(struct crypt_device *cd, if (_dm_satisfies_version(1, 6, 0, integrity_maj, integrity_min, integrity_patch)) _dm_flags |= DM_INTEGRITY_DISCARDS_SUPPORTED; + if (_dm_satisfies_version(1, 7, 0, integrity_maj, integrity_min, integrity_patch)) + _dm_flags |= DM_INTEGRITY_FIX_HMAC_SUPPORTED; + _dm_integrity_checked = true; } @@ -581,9 +590,14 @@ static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char i = sscanf(capi, "%" CLENS "[^(](%" CLENS "[^)])", mode, cipher); if (i == 2) - snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv); + i = snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv); else - snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv); + i = snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv); + if (i < 0 || (size_t)i >= sizeof(dmcrypt_tmp)) { + free(*org_i); + *org_i = NULL; + return -EINVAL; + } if (!(*org_c = strdup(dmcrypt_tmp))) { free(*org_i); @@ -594,11 +608,18 @@ static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char return 0; } +static char *_uf(char *buf, size_t buf_size, const char *s, unsigned u) +{ + size_t r = snprintf(buf, buf_size, " %s:%u", s, u); + assert(r > 0 && r < buf_size); + return buf; +} + /* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt */ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags) { int r, max_size, null_cipher = 0, num_options = 0, keystr_len = 0; - char *params, *hexkey; + char *params = NULL, *hexkey = NULL; char sector_feature[32], features[512], integrity_dm[256], cipher_dm[256]; if (!tgt) @@ -615,47 +636,53 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags) num_options++; if (flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) num_options++; + if (flags & CRYPT_ACTIVATE_NO_READ_WORKQUEUE) + num_options++; + if (flags & CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE) + num_options++; if (flags & CRYPT_ACTIVATE_IV_LARGE_SECTORS) num_options++; if (tgt->u.crypt.integrity) num_options++; - - if (tgt->u.crypt.sector_size != SECTOR_SIZE) { + if (tgt->u.crypt.sector_size != SECTOR_SIZE) num_options++; - snprintf(sector_feature, sizeof(sector_feature), " sector_size:%u", tgt->u.crypt.sector_size); - } else - *sector_feature = '\0'; - if (num_options) { - snprintf(features, sizeof(features)-1, " %d%s%s%s%s%s%s", num_options, + if (num_options) { /* MAX length int32 + 15 + 15 + 23 + 18 + 19 + 17 + 13 + int32 + integrity_str */ + r = snprintf(features, sizeof(features), " %d%s%s%s%s%s%s%s%s", num_options, (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) ? " allow_discards" : "", (flags & CRYPT_ACTIVATE_SAME_CPU_CRYPT) ? " same_cpu_crypt" : "", (flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) ? " submit_from_crypt_cpus" : "", + (flags & CRYPT_ACTIVATE_NO_READ_WORKQUEUE) ? " no_read_workqueue" : "", + (flags & CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE) ? " no_write_workqueue" : "", (flags & CRYPT_ACTIVATE_IV_LARGE_SECTORS) ? " iv_large_sectors" : "", - sector_feature, integrity_dm); + (tgt->u.crypt.sector_size != SECTOR_SIZE) ? + _uf(sector_feature, sizeof(sector_feature), "sector_size", tgt->u.crypt.sector_size) : "", + integrity_dm); + if (r < 0 || (size_t)r >= sizeof(features)) + goto out; } else *features = '\0'; - if (!strncmp(cipher_dm, "cipher_null-", 12)) + if (crypt_is_cipher_null(cipher_dm)) null_cipher = 1; - if (flags & CRYPT_ACTIVATE_KEYRING_KEY) { + if (null_cipher) + hexkey = crypt_safe_alloc(2); + else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) { keystr_len = strlen(tgt->u.crypt.vk->key_description) + int_log10(tgt->u.crypt.vk->keylength) + 10; hexkey = crypt_safe_alloc(keystr_len); } else - hexkey = crypt_safe_alloc(null_cipher ? 2 : (tgt->u.crypt.vk->keylength * 2 + 1)); + hexkey = crypt_safe_alloc(tgt->u.crypt.vk->keylength * 2 + 1); if (!hexkey) - return NULL; + goto out; if (null_cipher) strncpy(hexkey, "-", 2); else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) { r = snprintf(hexkey, keystr_len, ":%zu:logon:%s", tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key_description); - if (r < 0 || r >= keystr_len) { - params = NULL; + if (r < 0 || r >= keystr_len) goto out; - } } else hex_key(hexkey, tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key); @@ -682,10 +709,10 @@ out: /* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity */ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags) { - int max_size, r, num_options = 0; + int max_size, max_fec_size, max_verify_size, r, num_options = 0; struct crypt_params_verity *vp; char *params = NULL, *hexroot = NULL, *hexsalt = NULL; - char features[256], fec_features[256], verity_verify_args[512+32]; + char features[256], *fec_features = NULL, *verity_verify_args = NULL; if (!tgt || !tgt->u.verity.vp) return NULL; @@ -693,42 +720,63 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags) vp = tgt->u.verity.vp; /* These flags are not compatible */ + if ((flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) && + (flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION)) + flags &= ~CRYPT_ACTIVATE_RESTART_ON_CORRUPTION; if ((flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) && - (flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION)) + (flags & (CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|CRYPT_ACTIVATE_PANIC_ON_CORRUPTION))) flags &= ~CRYPT_ACTIVATE_IGNORE_CORRUPTION; if (flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) num_options++; if (flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) num_options++; + if (flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) + num_options++; if (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) num_options++; if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) num_options++; - if (tgt->u.verity.fec_device) { + max_fec_size = (tgt->u.verity.fec_device ? strlen(device_block_path(tgt->u.verity.fec_device)) : 0) + 256; + fec_features = crypt_safe_alloc(max_fec_size); + if (!fec_features) + goto out; + + if (tgt->u.verity.fec_device) { /* MAX length 21 + path + 11 + int64 + 12 + int64 + 11 + int32 */ num_options += 8; - snprintf(fec_features, sizeof(fec_features)-1, + r = snprintf(fec_features, max_fec_size, " use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 " fec_roots %" PRIu32, device_block_path(tgt->u.verity.fec_device), tgt->u.verity.fec_offset, - vp->data_size + tgt->u.verity.hash_blocks, vp->fec_roots); + tgt->u.verity.fec_blocks, vp->fec_roots); + if (r < 0 || r >= max_fec_size) + goto out; } else *fec_features = '\0'; - if (tgt->u.verity.root_hash_sig_key_desc) { + max_verify_size = (tgt->u.verity.root_hash_sig_key_desc ? strlen(tgt->u.verity.root_hash_sig_key_desc) : 0) + 32; + verity_verify_args = crypt_safe_alloc(max_verify_size); + if (!verity_verify_args) + goto out; + if (tgt->u.verity.root_hash_sig_key_desc) { /* MAX length 24 + key_str */ num_options += 2; - snprintf(verity_verify_args, sizeof(verity_verify_args)-1, + r = snprintf(verity_verify_args, max_verify_size, " root_hash_sig_key_desc %s", tgt->u.verity.root_hash_sig_key_desc); + if (r < 0 || r >= max_verify_size) + goto out; } else *verity_verify_args = '\0'; - if (num_options) - snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options, + if (num_options) { /* MAX length int32 + 18 + 22 + 20 + 19 + 19 */ + r = snprintf(features, sizeof(features), " %d%s%s%s%s%s", num_options, (flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "", (flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "", + (flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) ? " panic_on_corruption" : "", (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "", (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : ""); - else + if (r < 0 || (size_t)r >= sizeof(features)) + goto out; + } else *features = '\0'; hexroot = crypt_safe_alloc(tgt->u.verity.root_hash_size * 2 + 1); @@ -762,12 +810,13 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags) vp->data_size, tgt->u.verity.hash_offset, vp->hash_name, hexroot, hexsalt, features, fec_features, verity_verify_args); - if (r < 0 || r >= max_size) { crypt_safe_free(params); params = NULL; } out: + crypt_safe_free(fec_features); + crypt_safe_free(verity_verify_args); crypt_safe_free(hexroot); crypt_safe_free(hexsalt); return params; @@ -775,149 +824,143 @@ out: static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags) { - int r, max_size, num_options = 0; - char *params, *hexkey, mode; - char features[512], feature[256]; + int r, max_size, max_integrity, max_journal_integrity, max_journal_crypt, num_options = 0; + char *params_out = NULL, *params, *hexkey, mode, feature[6][32]; + char *features, *integrity, *journal_integrity, *journal_crypt; if (!tgt) return NULL; + max_integrity = (tgt->u.integrity.integrity && tgt->u.integrity.vk ? tgt->u.integrity.vk->keylength * 2 : 0) + + (tgt->u.integrity.integrity ? strlen(tgt->u.integrity.integrity) : 0) + 32; + max_journal_integrity = (tgt->u.integrity.journal_integrity && tgt->u.integrity.journal_integrity_key ? + tgt->u.integrity.journal_integrity_key->keylength * 2 : 0) + + (tgt->u.integrity.journal_integrity ? strlen(tgt->u.integrity.journal_integrity) : 0) + 32; + max_journal_crypt = (tgt->u.integrity.journal_crypt && tgt->u.integrity.journal_crypt_key ? + tgt->u.integrity.journal_crypt_key->keylength * 2 : 0) + + (tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 32; max_size = strlen(device_block_path(tgt->data_device)) + - (tgt->u.integrity.meta_device ? strlen(device_block_path(tgt->u.integrity.meta_device)) : 0) + - (tgt->u.integrity.vk ? tgt->u.integrity.vk->keylength * 2 : 0) + - (tgt->u.integrity.journal_integrity_key ? tgt->u.integrity.journal_integrity_key->keylength * 2 : 0) + - (tgt->u.integrity.journal_crypt_key ? tgt->u.integrity.journal_crypt_key->keylength * 2 : 0) + - (tgt->u.integrity.integrity ? strlen(tgt->u.integrity.integrity) : 0) + - (tgt->u.integrity.journal_integrity ? strlen(tgt->u.integrity.journal_integrity) : 0) + - (tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 128; + (tgt->u.integrity.meta_device ? strlen(device_block_path(tgt->u.integrity.meta_device)) : 0) + + max_integrity + max_journal_integrity + max_journal_crypt + 512; params = crypt_safe_alloc(max_size); - if (!params) - return NULL; + features = crypt_safe_alloc(max_size); + integrity = crypt_safe_alloc(max_integrity); + journal_integrity = crypt_safe_alloc(max_journal_integrity); + journal_crypt = crypt_safe_alloc(max_journal_crypt); + if (!params || !features || !integrity || !journal_integrity || !journal_crypt) + goto out; - *features = '\0'; - if (tgt->u.integrity.journal_size) { - num_options++; - snprintf(feature, sizeof(feature), "journal_sectors:%u ", - (unsigned)(tgt->u.integrity.journal_size / SECTOR_SIZE)); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - if (tgt->u.integrity.journal_watermark) { - num_options++; - snprintf(feature, sizeof(feature), - /* bitmap overloaded values */ - (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit:%u " : "journal_watermark:%u ", - tgt->u.integrity.journal_watermark); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - if (tgt->u.integrity.journal_commit_time) { - num_options++; - snprintf(feature, sizeof(feature), - /* bitmap overloaded values */ - (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval:%u " : "commit_time:%u ", - tgt->u.integrity.journal_commit_time); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - if (tgt->u.integrity.interleave_sectors) { - num_options++; - snprintf(feature, sizeof(feature), "interleave_sectors:%u ", - tgt->u.integrity.interleave_sectors); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - if (tgt->u.integrity.sector_size) { - num_options++; - snprintf(feature, sizeof(feature), "block_size:%u ", - tgt->u.integrity.sector_size); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - if (tgt->u.integrity.buffer_sectors) { - num_options++; - snprintf(feature, sizeof(feature), "buffer_sectors:%u ", - tgt->u.integrity.buffer_sectors); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - if (tgt->u.integrity.integrity) { + if (tgt->u.integrity.integrity) { /* MAX length 16 + str_integrity + str_key */ num_options++; if (tgt->u.integrity.vk) { hexkey = crypt_safe_alloc(tgt->u.integrity.vk->keylength * 2 + 1); - if (!hexkey) { - crypt_safe_free(params); - return NULL; - } + if (!hexkey) + goto out; hex_key(hexkey, tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key); } else hexkey = NULL; - snprintf(feature, sizeof(feature), "internal_hash:%s%s%s ", + r = snprintf(integrity, max_integrity, " internal_hash:%s%s%s", tgt->u.integrity.integrity, hexkey ? ":" : "", hexkey ?: ""); - strncat(features, feature, sizeof(features) - strlen(features) - 1); crypt_safe_free(hexkey); + if (r < 0 || r >= max_integrity) + goto out; } - if (tgt->u.integrity.journal_integrity) { + if (tgt->u.integrity.journal_integrity) { /* MAX length 14 + str_journal_integrity + str_key */ num_options++; if (tgt->u.integrity.journal_integrity_key) { hexkey = crypt_safe_alloc(tgt->u.integrity.journal_integrity_key->keylength * 2 + 1); - if (!hexkey) { - crypt_safe_free(params); - return NULL; - } + if (!hexkey) + goto out; hex_key(hexkey, tgt->u.integrity.journal_integrity_key->keylength, tgt->u.integrity.journal_integrity_key->key); } else hexkey = NULL; - snprintf(feature, sizeof(feature), "journal_mac:%s%s%s ", + r = snprintf(journal_integrity, max_journal_integrity, " journal_mac:%s%s%s", tgt->u.integrity.journal_integrity, hexkey ? ":" : "", hexkey ?: ""); - strncat(features, feature, sizeof(features) - strlen(features) - 1); crypt_safe_free(hexkey); + if (r < 0 || r >= max_journal_integrity) + goto out; } - if (tgt->u.integrity.journal_crypt) { + if (tgt->u.integrity.journal_crypt) { /* MAX length 15 + str_journal_crypt + str_key */ num_options++; if (tgt->u.integrity.journal_crypt_key) { hexkey = crypt_safe_alloc(tgt->u.integrity.journal_crypt_key->keylength * 2 + 1); - if (!hexkey) { - crypt_safe_free(params); - return NULL; - } + if (!hexkey) + goto out; hex_key(hexkey, tgt->u.integrity.journal_crypt_key->keylength, tgt->u.integrity.journal_crypt_key->key); } else hexkey = NULL; - snprintf(feature, sizeof(feature), "journal_crypt:%s%s%s ", + r = snprintf(journal_crypt, max_journal_crypt, " journal_crypt:%s%s%s", tgt->u.integrity.journal_crypt, hexkey ? ":" : "", hexkey ?: ""); - strncat(features, feature, sizeof(features) - strlen(features) - 1); crypt_safe_free(hexkey); - } - if (tgt->u.integrity.fix_padding) { - num_options++; - snprintf(feature, sizeof(feature), "fix_padding "); - strncat(features, feature, sizeof(features) - strlen(features) - 1); + if (r < 0 || r >= max_journal_crypt) + goto out; } - if (flags & CRYPT_ACTIVATE_RECALCULATE) { + if (tgt->u.integrity.journal_size) num_options++; - snprintf(feature, sizeof(feature), "recalculate "); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - - if (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) { + if (tgt->u.integrity.journal_watermark) num_options++; - snprintf(feature, sizeof(feature), "allow_discards "); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } - - if (tgt->u.integrity.meta_device) { + if (tgt->u.integrity.journal_commit_time) + num_options++; + if (tgt->u.integrity.interleave_sectors) + num_options++; + if (tgt->u.integrity.sector_size) + num_options++; + if (tgt->u.integrity.buffer_sectors) + num_options++; + if (tgt->u.integrity.fix_padding) + num_options++; + if (tgt->u.integrity.fix_hmac) + num_options++; + if (tgt->u.integrity.legacy_recalc) + num_options++; + if (tgt->u.integrity.meta_device) + num_options++; + if (flags & CRYPT_ACTIVATE_RECALCULATE) + num_options++; + if (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) num_options++; - snprintf(feature, sizeof(feature), "meta_device:%s ", - device_block_path(tgt->u.integrity.meta_device)); - strncat(features, feature, sizeof(features) - strlen(features) - 1); - } + + r = snprintf(features, max_size, "%d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", num_options, + tgt->u.integrity.journal_size ? _uf(feature[0], sizeof(feature[0]), /* MAX length 17 + int32 */ + "journal_sectors", (unsigned)(tgt->u.integrity.journal_size / SECTOR_SIZE)) : "", + tgt->u.integrity.journal_watermark ? _uf(feature[1], sizeof(feature[1]), /* MAX length 19 + int32 */ + /* bitmap overloaded values */ + (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit" : "journal_watermark", + tgt->u.integrity.journal_watermark) : "", + tgt->u.integrity.journal_commit_time ? _uf(feature[2], sizeof(feature[2]), /* MAX length 23 + int32 */ + /* bitmap overloaded values */ + (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval" : "commit_time", + tgt->u.integrity.journal_commit_time) : "", + tgt->u.integrity.interleave_sectors ? _uf(feature[3], sizeof(feature[3]), /* MAX length 20 + int32 */ + "interleave_sectors", tgt->u.integrity.interleave_sectors) : "", + tgt->u.integrity.sector_size ? _uf(feature[4], sizeof(feature[4]), /* MAX length 12 + int32 */ + "block_size", tgt->u.integrity.sector_size) : "", + tgt->u.integrity.buffer_sectors ? _uf(feature[5], sizeof(feature[5]), /* MAX length 16 + int32 */ + "buffer_sectors", tgt->u.integrity.buffer_sectors) : "", + tgt->u.integrity.integrity ? integrity : "", + tgt->u.integrity.journal_integrity ? journal_integrity : "", + tgt->u.integrity.journal_crypt ? journal_crypt : "", + tgt->u.integrity.fix_padding ? " fix_padding" : "", /* MAX length 12 */ + tgt->u.integrity.fix_hmac ? " fix_hmac" : "", /* MAX length 9 */ + tgt->u.integrity.legacy_recalc ? " legacy_recalculate" : "", /* MAX length 19 */ + flags & CRYPT_ACTIVATE_RECALCULATE ? " recalculate" : "", /* MAX length 12 */ + flags & CRYPT_ACTIVATE_ALLOW_DISCARDS ? " allow_discards" : "", /* MAX length 15 */ + tgt->u.integrity.meta_device ? " meta_device:" : "", /* MAX length 13 + str_device */ + tgt->u.integrity.meta_device ? device_block_path(tgt->u.integrity.meta_device) : ""); + if (r < 0 || r >= max_size) + goto out; if (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) mode = 'B'; @@ -928,16 +971,22 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags else mode = 'J'; - r = snprintf(params, max_size, "%s %" PRIu64 " %d %c %d %s", + r = snprintf(params, max_size, "%s %" PRIu64 " %d %c %s", device_block_path(tgt->data_device), tgt->u.integrity.offset, - tgt->u.integrity.tag_size, mode, - num_options, *features ? features : ""); - if (r < 0 || r >= max_size) { + tgt->u.integrity.tag_size, mode, features); + if (r < 0 || r >= max_size) + goto out; + + params_out = params; +out: + crypt_safe_free(features); + crypt_safe_free(integrity); + crypt_safe_free(journal_integrity); + crypt_safe_free(journal_crypt); + if (!params_out) crypt_safe_free(params); - params = NULL; - } - return params; + return params_out; } static char *get_dm_linear_params(const struct dm_target *tgt, uint32_t flags) @@ -1172,7 +1221,7 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char { char *ptr, uuid2[UUID_LEN] = {0}; uuid_t uu; - unsigned i = 0; + int i = 0; /* Remove '-' chars */ if (uuid) { @@ -1192,9 +1241,11 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char type ?: "", type ? "-" : "", uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "", name); + if (i < 0) + return 0; log_dbg(cd, "DM-UUID is %s", buf); - if (i >= buflen) + if ((size_t)i >= buflen) log_err(cd, _("DM-UUID for device %s was truncated."), name); return 1; @@ -1305,6 +1356,12 @@ err: return r; } +static bool dm_device_exists(struct crypt_device *cd, const char *name) +{ + int r = dm_status_device(cd, name); + return (r >= 0 || r == -EEXIST); +} + static int _dm_create_device(struct crypt_device *cd, const char *name, const char *type, const char *uuid, struct crypt_dm_active_device *dmd) { @@ -1354,8 +1411,11 @@ static int _dm_create_device(struct crypt_device *cd, const char *name, const ch if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags)) goto out; - if (!dm_task_run(dmt)) + if (!dm_task_run(dmt)) { + if (dm_device_exists(cd, name)) + r = -EEXIST; goto out; + } if (dm_task_get_info(dmt, &dmi)) r = 0; @@ -1592,6 +1652,14 @@ static int check_retry(struct crypt_device *cd, uint32_t *dmd_flags, uint32_t dm ret = 1; } + /* Drop no workqueue options if not supported */ + if ((*dmd_flags & (CRYPT_ACTIVATE_NO_READ_WORKQUEUE | CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE)) && + !(dmt_flags & DM_CRYPT_NO_WORKQUEUE_SUPPORTED)) { + log_dbg(cd, "dm-crypt does not support performance options"); + *dmd_flags = *dmd_flags & ~(CRYPT_ACTIVATE_NO_READ_WORKQUEUE | CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE); + ret = 1; + } + return ret; } @@ -1614,14 +1682,29 @@ int dm_create_device(struct crypt_device *cd, const char *name, goto out; if (r && (dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR || dmd->segment.type == DM_ZERO) && - check_retry(cd, &dmd->flags, dmt_flags)) + check_retry(cd, &dmd->flags, dmt_flags)) { + log_dbg(cd, "Retrying open without incompatible options."); r = _dm_create_device(cd, name, type, dmd->uuid, dmd); + } + + /* + * Print warning if activating dm-crypt cipher_null device unless it's reencryption helper or + * keyslot encryption helper device (LUKS1 cipher_null devices). + */ + if (!r && !(dmd->flags & CRYPT_ACTIVATE_PRIVATE) && single_segment(dmd) && dmd->segment.type == DM_CRYPT && + crypt_is_cipher_null(dmd->segment.u.crypt.cipher)) + log_dbg(cd, "Activated dm-crypt device with cipher_null. Device is not encrypted."); if (r == -EINVAL && dmd->flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) && !(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) log_err(cd, _("Requested dm-crypt performance options are not supported.")); + if (r == -EINVAL && + dmd->flags & (CRYPT_ACTIVATE_NO_READ_WORKQUEUE | CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE) && + !(dmt_flags & DM_CRYPT_NO_WORKQUEUE_SUPPORTED)) + log_err(cd, _("Requested dm-crypt performance options are not supported.")); + if (r == -EINVAL && dmd->flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION| CRYPT_ACTIVATE_RESTART_ON_CORRUPTION| CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS| @@ -1629,6 +1712,10 @@ int dm_create_device(struct crypt_device *cd, const char *name, !(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED)) log_err(cd, _("Requested dm-verity data corruption handling options are not supported.")); + if (r == -EINVAL && dmd->flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION && + !(dmt_flags & DM_VERITY_PANIC_CORRUPTION_SUPPORTED)) + log_err(cd, _("Requested dm-verity data corruption handling options are not supported.")); + if (r == -EINVAL && dmd->segment.type == DM_VERITY && dmd->segment.u.verity.fec_device && !(dmt_flags & DM_VERITY_FEC_SUPPORTED)) log_err(cd, _("Requested dm-verity FEC options are not supported.")); @@ -1675,7 +1762,10 @@ int dm_reload_device(struct crypt_device *cd, const char *name, if (r == -EINVAL && (dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR)) { if ((dmd->flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS)) && - !dm_flags(cd, DM_CRYPT, &dmt_flags) && !(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) + !dm_flags(cd, DM_CRYPT, &dmt_flags) && !(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED | DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) + log_err(cd, _("Requested dm-crypt performance options are not supported.")); + if ((dmd->flags & (CRYPT_ACTIVATE_NO_READ_WORKQUEUE | CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE)) && + !dm_flags(cd, DM_CRYPT, &dmt_flags) && !(dmt_flags & DM_CRYPT_NO_WORKQUEUE_SUPPORTED)) log_err(cd, _("Requested dm-crypt performance options are not supported.")); if ((dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) && !dm_flags(cd, DM_CRYPT, &dmt_flags) && !(dmt_flags & DM_DISCARDS_SUPPORTED)) @@ -1720,6 +1810,7 @@ static int dm_status_dmi(const char *name, struct dm_info *dmi, goto out; } + r = -EEXIST; dm_get_next_target(dmt, NULL, &start, &length, &target_type, ¶ms); @@ -1918,6 +2009,10 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags, *act_flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT; else if (!strcasecmp(arg, "submit_from_crypt_cpus")) *act_flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS; + else if (!strcasecmp(arg, "no_read_workqueue")) + *act_flags |= CRYPT_ACTIVATE_NO_READ_WORKQUEUE; + else if (!strcasecmp(arg, "no_write_workqueue")) + *act_flags |= CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE; else if (!strcasecmp(arg, "iv_large_sectors")) *act_flags |= CRYPT_ACTIVATE_IV_LARGE_SECTORS; else if (sscanf(arg, "integrity:%u:", &val) == 1) { @@ -2168,6 +2263,8 @@ static int _dm_target_query_verity(struct crypt_device *cd, *act_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION; else if (!strcasecmp(arg, "restart_on_corruption")) *act_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION; + else if (!strcasecmp(arg, "panic_on_corruption")) + *act_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION; else if (!strcasecmp(arg, "ignore_zero_blocks")) *act_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS; else if (!strcasecmp(arg, "check_at_most_once")) @@ -2213,8 +2310,13 @@ static int _dm_target_query_verity(struct crypt_device *cd, str = strsep(¶ms, " "); if (!str) goto err; - if (!root_hash_sig_key_desc) + if (!root_hash_sig_key_desc) { root_hash_sig_key_desc = strdup(str); + if (!root_hash_sig_key_desc) { + r = -ENOMEM; + goto err; + } + } i++; if (vp) vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE; @@ -2418,6 +2520,10 @@ static int _dm_target_query_integrity(struct crypt_device *cd, *act_flags |= CRYPT_ACTIVATE_RECALCULATE; } else if (!strcmp(arg, "fix_padding")) { tgt->u.integrity.fix_padding = true; + } else if (!strcmp(arg, "fix_hmac")) { + tgt->u.integrity.fix_hmac = true; + } else if (!strcmp(arg, "legacy_recalculate")) { + tgt->u.integrity.legacy_recalc = true; } else if (!strcmp(arg, "allow_discards")) { *act_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; } else /* unknown option */ @@ -2857,7 +2963,9 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name, if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED)) goto out; - if (vk->key_description) + if (!vk->keylength) + msg_size = 11; // key set - + else if (vk->key_description) msg_size = strlen(vk->key_description) + int_log10(vk->keylength) + 18; else msg_size = vk->keylength * 2 + 10; // key set <key> @@ -2869,7 +2977,9 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name, } strcpy(msg, "key set "); - if (vk->key_description) + if (!vk->keylength) + snprintf(msg + 8, msg_size - 8, "-"); + else if (vk->key_description) snprintf(msg + 8, msg_size - 8, ":%zu:logon:%s", vk->keylength, vk->key_description); else hex_key(&msg[8], vk->keylength, vk->key); @@ -2944,8 +3054,8 @@ err: int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size, struct device *data_device, struct device *hash_device, struct device *fec_device, - const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc, - uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp) + const char *root_hash, uint32_t root_hash_size, const char* root_hash_sig_key_desc, + uint64_t hash_offset_block, uint64_t fec_blocks, struct crypt_params_verity *vp) { if (!data_device || !hash_device || !vp) return -EINVAL; @@ -2963,7 +3073,7 @@ int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t se tgt->u.verity.root_hash_sig_key_desc = root_hash_sig_key_desc; tgt->u.verity.hash_offset = hash_offset_block; tgt->u.verity.fec_offset = vp->fec_area_offset / vp->hash_block_size; - tgt->u.verity.hash_blocks = hash_blocks; + tgt->u.verity.fec_blocks = fec_blocks; tgt->u.verity.vp = vp; return 0; @@ -3004,6 +3114,15 @@ int dm_integrity_target_set(struct crypt_device *cd, !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING)) tgt->u.integrity.fix_padding = true; + if (!dm_flags(cd, DM_INTEGRITY, &dmi_flags) && + (dmi_flags & DM_INTEGRITY_FIX_HMAC_SUPPORTED) && + !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC)) + tgt->u.integrity.fix_hmac = true; + + /* This flag can be backported, just try to set it always */ + if (crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC) + tgt->u.integrity.legacy_recalc = true; + if (ip) { tgt->u.integrity.journal_size = ip->journal_size; tgt->u.integrity.journal_watermark = ip->journal_watermark; |