*
* 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-2023 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2023 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
#include <libdevmapper.h>
-#include <linux/fs.h>
#include <uuid/uuid.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* for major, minor */
#endif
-
#include "internal.h"
-#define DM_UUID_LEN 129
-#define DM_BY_ID_PREFIX "dm-uuid-"
-#define DM_BY_ID_PREFIX_LEN 8
-#define DM_UUID_PREFIX "CRYPT-"
-#define DM_UUID_PREFIX_LEN 6
#define DM_CRYPT_TARGET "crypt"
#define DM_VERITY_TARGET "verity"
#define DM_INTEGRITY_TARGET "integrity"
static bool _dm_crypt_checked = false;
static bool _dm_verity_checked = false;
static bool _dm_integrity_checked = false;
+static bool _dm_zero_checked = false;
static int _quiet_log = 0;
static uint32_t _dm_flags = 0;
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;
}
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;
+
+ if (_dm_satisfies_version(1, 9, 0, verity_maj, verity_min, verity_patch))
+ _dm_flags |= DM_VERITY_TASKLETS_SUPPORTED;
+
_dm_verity_checked = true;
}
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;
+
+ if (_dm_satisfies_version(1, 8, 0, integrity_maj, integrity_min, integrity_patch))
+ _dm_flags |= DM_INTEGRITY_RESET_RECALC_SUPPORTED;
+
_dm_integrity_checked = true;
}
+static void _dm_set_zero_compat(struct crypt_device *cd,
+ unsigned zero_maj,
+ unsigned zero_min,
+ unsigned zero_patch)
+{
+ if (_dm_zero_checked || zero_maj == 0)
+ return;
+
+ log_dbg(cd, "Detected dm-zero version %i.%i.%i.",
+ zero_maj, zero_min, zero_patch);
+
+ _dm_zero_checked = true;
+}
+
/* We use this for loading target module */
static void _dm_check_target(dm_target_type target_type)
{
return;
if (!(dmt = dm_task_create(DM_DEVICE_GET_TARGET_VERSION)))
- goto out;
+ return;
- if (!dm_task_set_name(dmt, target_name))
- goto out;
+ if (dm_task_set_name(dmt, target_name))
+ dm_task_run(dmt);
- if (!dm_task_run(dmt))
- goto out;
-out:
- if (dmt)
- dm_task_destroy(dmt);
+ dm_task_destroy(dmt);
#endif
}
unsigned dm_maj, dm_min, dm_patch;
int r = 0;
- if ((target_type == DM_CRYPT && _dm_crypt_checked) ||
+ if ((target_type == DM_CRYPT && _dm_crypt_checked) ||
(target_type == DM_VERITY && _dm_verity_checked) ||
(target_type == DM_INTEGRITY && _dm_integrity_checked) ||
- (target_type == DM_LINEAR) || (target_type == DM_ZERO) ||
- (_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked))
+ (target_type == DM_ZERO && _dm_zero_checked) ||
+ (target_type == DM_LINEAR) ||
+ (_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked && _dm_zero_checked))
return 1;
/* Shut up DM while checking */
_dm_check_target(target_type);
- /* FIXME: add support to DM so it forces crypt target module load here */
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
goto out;
_dm_set_integrity_compat(cd, (unsigned)target->version[0],
(unsigned)target->version[1],
(unsigned)target->version[2]);
+ } else if (!strcmp(DM_ZERO_TARGET, target->name)) {
+ _dm_set_zero_compat(cd, (unsigned)target->version[0],
+ (unsigned)target->version[1],
+ (unsigned)target->version[2]);
}
- target = (struct dm_versions *)((char *) target + target->next);
+ target = VOIDP_CAST(struct dm_versions *)((char *) target + target->next);
} while (last_target != target);
r = 1;
*flags = _dm_flags;
if (target == DM_UNKNOWN &&
- _dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked)
+ _dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked && _dm_zero_checked)
return 0;
- if ((target == DM_CRYPT && _dm_crypt_checked) ||
+ if ((target == DM_CRYPT && _dm_crypt_checked) ||
(target == DM_VERITY && _dm_verity_checked) ||
(target == DM_INTEGRITY && _dm_integrity_checked) ||
- (target == DM_LINEAR) || (target == DM_ZERO)) /* nothing to check */
+ (target == DM_ZERO && _dm_zero_checked) ||
+ (target == DM_LINEAR)) /* nothing to check */
return 0;
return -ENODEV;
}
}
-/*
- * libdevmapper is not context friendly, switch context on every DM call.
- * FIXME: this is not safe if called in parallel but neither is DM lib.
- */
+/* libdevmapper is not context friendly, switch context on every DM call. */
static int dm_init_context(struct crypt_device *cd, dm_target_type target)
{
_context = cd;
return dm_device_path(NULL, major(st.st_rdev), minor(st.st_rdev));
}
-static void hex_key(char *hexkey, size_t key_size, const char *key)
-{
- unsigned i;
-
- for(i = 0; i < key_size; i++)
- sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
-}
-
static size_t int_log10(uint64_t x)
{
uint64_t r = 0;
return r;
}
-#define CLEN 64 /* 2*MAX_CIPHER_LEN */
-#define CLENS "63" /* for sscanf length + '\0' */
-#define CAPIL 144 /* should be enough to fit whole capi string */
-#define CAPIS "143" /* for sscanf of crypto API string + 16 + \0 */
-
-static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
+static int cipher_dm2c(const char *org_c, const char *org_i, unsigned tag_size,
char *c_dm, int c_dm_size,
char *i_dm, int i_dm_size)
{
int c_size = 0, i_size = 0, i;
- char cipher[CLEN], mode[CLEN], iv[CLEN+1], tmp[CLEN];
- char capi[CAPIL];
+ char cipher[MAX_CAPI_ONE_LEN], mode[MAX_CAPI_ONE_LEN], iv[MAX_CAPI_ONE_LEN+1],
+ tmp[MAX_CAPI_ONE_LEN], capi[MAX_CAPI_LEN];
if (!c_dm || !c_dm_size || !i_dm || !i_dm_size)
return -EINVAL;
- i = sscanf(org_c, "%" CLENS "[^-]-%" CLENS "s", cipher, tmp);
+ i = sscanf(org_c, "%" MAX_CAPI_ONE_LEN_STR "[^-]-%" MAX_CAPI_ONE_LEN_STR "s", cipher, tmp);
if (i != 2)
return -EINVAL;
- i = sscanf(tmp, "%" CLENS "[^-]-%" CLENS "s", mode, iv);
+ i = sscanf(tmp, "%" MAX_CAPI_ONE_LEN_STR "[^-]-%" MAX_CAPI_ONE_LEN_STR "s", mode, iv);
if (i == 1) {
memset(iv, 0, sizeof(iv));
strncpy(iv, mode, sizeof(iv)-1);
return 0;
}
-static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char *i_dm)
+static char *_uf(char *buf, size_t buf_size, const char *s, unsigned u)
{
- char cipher[CLEN], mode[CLEN], iv[CLEN], auth[CLEN];
- char tmp[CAPIL], dmcrypt_tmp[CAPIL*2], capi[CAPIL+1];
- size_t len;
- int i;
-
- if (!c_dm)
- return -EINVAL;
-
- /* legacy mode */
- if (strncmp(c_dm, "capi:", 4)) {
- if (!(*org_c = strdup(c_dm)))
- return -ENOMEM;
- *org_i = NULL;
- return 0;
- }
-
- /* modes with capi: prefix */
- i = sscanf(c_dm, "capi:%" CAPIS "[^-]-%" CLENS "s", tmp, iv);
- if (i != 2)
- return -EINVAL;
-
- len = strlen(tmp);
- if (len < 2)
- return -EINVAL;
-
- if (tmp[len-1] == ')')
- tmp[len-1] = '\0';
-
- if (sscanf(tmp, "rfc4309(%" CAPIS "s", capi) == 1) {
- if (!(*org_i = strdup("aead")))
- return -ENOMEM;
- } else if (sscanf(tmp, "rfc7539(%" CAPIS "[^,],%" CLENS "s", capi, auth) == 2) {
- if (!(*org_i = strdup(auth)))
- return -ENOMEM;
- } else if (sscanf(tmp, "authenc(%" CLENS "[^,],%" CAPIS "s", auth, capi) == 2) {
- if (!(*org_i = strdup(auth)))
- return -ENOMEM;
- } else {
- if (i_dm) {
- if (!(*org_i = strdup(i_dm)))
- return -ENOMEM;
- } else
- *org_i = NULL;
- memset(capi, 0, sizeof(capi));
- strncpy(capi, tmp, sizeof(capi)-1);
- }
-
- i = sscanf(capi, "%" CLENS "[^(](%" CLENS "[^)])", mode, cipher);
- if (i == 2)
- snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv);
- else
- snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv);
-
- if (!(*org_c = strdup(dmcrypt_tmp))) {
- free(*org_i);
- *org_i = NULL;
- return -ENOMEM;
- }
-
- return 0;
+ 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)
return NULL;
- r = cipher_c2dm(tgt->u.crypt.cipher, tgt->u.crypt.integrity, tgt->u.crypt.tag_size,
+ r = cipher_dm2c(tgt->u.crypt.cipher, tgt->u.crypt.integrity, tgt->u.crypt.tag_size,
cipher_dm, sizeof(cipher_dm), integrity_dm, sizeof(integrity_dm));
if (r < 0)
return NULL;
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) {
- 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));
-
- if (!hexkey)
- return NULL;
-
if (null_cipher)
- strncpy(hexkey, "-", 2);
+ hexkey = crypt_bytes_to_hex(0, NULL);
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);
+ if (!hexkey)
+ goto out;
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);
+ hexkey = crypt_bytes_to_hex(tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key);
+
+ if (!hexkey)
+ goto out;
max_size = strlen(hexkey) + strlen(cipher_dm) +
strlen(device_block_path(tgt->data_device)) +
/* 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;
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 (flags & CRYPT_ACTIVATE_TASKLETS)
+ num_options++;
+
+ 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) {
+ 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 + 22 */
+ r = snprintf(features, sizeof(features), " %d%s%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
+ (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "",
+ (flags & CRYPT_ACTIVATE_TASKLETS) ? " try_verify_in_tasklet" : "");
+ 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);
+ hexroot = crypt_bytes_to_hex(tgt->u.verity.root_hash_size, tgt->u.verity.root_hash);
if (!hexroot)
goto out;
- hex_key(hexroot, tgt->u.verity.root_hash_size, tgt->u.verity.root_hash);
- hexsalt = crypt_safe_alloc(vp->salt_size ? vp->salt_size * 2 + 1 : 2);
+ hexsalt = crypt_bytes_to_hex(vp->salt_size, vp->salt);
if (!hexsalt)
goto out;
- if (vp->salt_size)
- hex_key(hexsalt, vp->salt_size, vp->salt);
- else
- strncpy(hexsalt, "-", 2);
max_size = strlen(hexroot) + strlen(hexsalt) +
strlen(device_block_path(tgt->data_device)) +
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;
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;
- }
- hex_key(hexkey, tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
+ hexkey = crypt_bytes_to_hex(tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
+ if (!hexkey)
+ goto out;
} 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;
- }
- hex_key(hexkey, tgt->u.integrity.journal_integrity_key->keylength,
+ hexkey = crypt_bytes_to_hex( tgt->u.integrity.journal_integrity_key->keylength,
tgt->u.integrity.journal_integrity_key->key);
+ if (!hexkey)
+ goto out;
} 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;
- }
- hex_key(hexkey, tgt->u.integrity.journal_crypt_key->keylength,
+ hexkey = crypt_bytes_to_hex(tgt->u.integrity.journal_crypt_key->keylength,
tgt->u.integrity.journal_crypt_key->key);
+ if (!hexkey)
+ goto out;
} 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++;
- snprintf(feature, sizeof(feature), "meta_device:%s ",
- device_block_path(tgt->u.integrity.meta_device));
- strncat(features, feature, sizeof(features) - strlen(features) - 1);
- }
+ 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_RECALCULATE_RESET)
+ num_options++;
+ if (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS)
+ num_options++;
+
+ r = snprintf(features, max_size, "%d%s%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_RECALCULATE_RESET ? " reset_recalculate" : "", /* MAX length 18 */
+ 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';
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)
+static char *get_dm_linear_params(const struct dm_target *tgt)
{
char *params;
int r;
return params;
}
-static char *get_dm_zero_params(const struct dm_target *tgt, uint32_t flags)
+static char *get_dm_zero_params(void)
{
char *params = crypt_safe_alloc(1);
if (!params)
return 0;
if (!dm_task_set_name(dmt, name))
- goto error;
+ goto out;
if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
- goto error;
+ goto out;
if (!dm_task_set_ro(dmt))
- goto error;
+ goto out;
if (!dm_task_no_open_count(dmt))
- goto error;
+ goto out;
if (!dm_task_run(dmt))
- goto error;
+ goto out;
if (_dm_resume_device(name, 0)) {
_dm_simple(DM_DEVICE_CLEAR, name, 0);
- goto error;
+ goto out;
}
r = 1;
-
-error:
+out:
dm_task_destroy(dmt);
return r;
}
{
char *ptr, uuid2[UUID_LEN] = {0};
uuid_t uu;
- unsigned i = 0;
+ int i = 0;
/* Remove '-' chars */
if (uuid) {
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;
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type)
{
- int r;
+ int r_udev, r;
char *c;
char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
/* cut of dm name */
*c = '\0';
+ /* Either udev or sysfs can report that device is active. */
r = lookup_by_disk_id(dev_uuid);
- if (r == -ENOENT) {
- log_dbg(cd, "Search by disk id not available. Using sysfs instead.");
- r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN, DM_UUID_LEN);
- }
+ if (r > 0)
+ return r;
- return r;
+ r_udev = r;
+ r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
+
+ return r == -ENOENT ? r_udev : r;
}
static int _add_dm_targets(struct dm_task *dmt, struct crypt_dm_active_device *dmd)
else if (tgt->type == DM_INTEGRITY)
tgt->params = get_dm_integrity_params(tgt, dmd->flags);
else if (tgt->type == DM_LINEAR)
- tgt->params = get_dm_linear_params(tgt, dmd->flags);
+ tgt->params = get_dm_linear_params(tgt);
else if (tgt->type == DM_ZERO)
- tgt->params = get_dm_zero_params(tgt, dmd->flags);
+ tgt->params = get_dm_zero_params();
else {
r = -ENOTSUP;
goto err;
}
static int _dm_create_device(struct crypt_device *cd, const char *name, const char *type,
- const char *uuid, struct crypt_dm_active_device *dmd)
+ struct crypt_dm_active_device *dmd)
{
struct dm_task *dmt = NULL;
struct dm_info dmi;
if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
goto out;
- if (!dm_task_run(dmt))
+ if (!dm_task_run(dmt)) {
+ r = dm_status_device(cd, name);;
+ if (r >= 0)
+ r = -EEXIST;
+ if (r != -EEXIST && r != -ENODEV)
+ r = -EINVAL;
goto out;
+ }
if (dm_task_get_info(dmt, &dmi))
r = 0;
static void _dm_target_erase(struct crypt_device *cd, struct dm_target *tgt)
{
+ if (tgt->direction == TARGET_EMPTY)
+ return;
+
if (tgt->direction == TARGET_QUERY)
_dm_target_free_query_path(cd, tgt);
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;
}
if (dm_init_context(cd, dmd->segment.type))
return -ENOTSUP;
- r = _dm_create_device(cd, name, type, dmd->uuid, dmd);
+ r = _dm_create_device(cd, name, type, dmd);
+ if (!r || r == -EEXIST)
+ goto out;
- if (r < 0 && dm_flags(cd, dmd->segment.type, &dmt_flags))
+ if (dm_flags(cd, dmd->segment.type, &dmt_flags))
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))
- r = _dm_create_device(cd, name, type, dmd->uuid, dmd);
+ if ((dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR || dmd->segment.type == DM_ZERO) &&
+ check_retry(cd, &dmd->flags, dmt_flags)) {
+ log_dbg(cd, "Retrying open without incompatible options.");
+ r = _dm_create_device(cd, name, type, dmd);
+ if (!r || r == -EEXIST)
+ goto out;
+ }
+
+ if (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."));
+ r = -EINVAL;
+ }
- 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)))
+ if (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."));
+ r = -EINVAL;
+ }
- if (r == -EINVAL && dmd->flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
- CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
- CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
- CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
- !(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED))
+ if (dmd->flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
+ CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
+ CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
+ CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
+ !(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED)) {
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
+ r = -EINVAL;
+ }
- if (r == -EINVAL && dmd->segment.type == DM_VERITY &&
- dmd->segment.u.verity.fec_device && !(dmt_flags & DM_VERITY_FEC_SUPPORTED))
+ if (dmd->flags & CRYPT_ACTIVATE_TASKLETS &&
+ !(dmt_flags & DM_VERITY_TASKLETS_SUPPORTED)) {
+ log_err(cd, _("Requested dm-verity tasklets option is not supported."));
+ r = -EINVAL;
+ }
+
+ if (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."));
+ r = -EINVAL;
+ }
+
+ if (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."));
+ r = -EINVAL;
+ }
- if (r == -EINVAL && dmd->segment.type == DM_CRYPT) {
- if (dmd->segment.u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED))
+ if (dmd->segment.type == DM_CRYPT) {
+ if (dmd->segment.u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED)) {
log_err(cd, _("Requested data integrity options are not supported."));
- if (dmd->segment.u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED))
+ r = -EINVAL;
+ }
+ if (dmd->segment.u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED)) {
log_err(cd, _("Requested sector_size option is not supported."));
+ r = -EINVAL;
+ }
+ }
+
+ if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
+ !(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED)) {
+ log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
+ r = -EINVAL;
}
- if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
- !(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED))
+ if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE_RESET) &&
+ !(dmt_flags & DM_INTEGRITY_RESET_RECALC_SUPPORTED)) {
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
+ r = -EINVAL;
+ }
- if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
- !(dmt_flags & DM_INTEGRITY_DISCARDS_SUPPORTED))
+ if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
+ !(dmt_flags & DM_INTEGRITY_DISCARDS_SUPPORTED)) {
log_err(cd, _("Discard/TRIM is not supported."));
+ r = -EINVAL;
+ }
- if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
- !(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED))
+ if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
+ !(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED)) {
log_err(cd, _("Requested dm-integrity bitmap mode is not supported."));
+ r = -EINVAL;
+ }
out:
+ /*
+ * 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.");
+
dm_exit_context();
return r;
}
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))
int r = -EINVAL;
if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
- goto out;
+ return r;
if (!dm_task_no_flush(dmt))
goto out;
goto out;
}
+ r = -EEXIST;
dm_get_next_target(dmt, NULL, &start, &length,
&target_type, ¶ms);
if (!r && status_line && !(*status_line = strdup(params)))
r = -ENOMEM;
- if (dmt)
- dm_task_destroy(dmt);
+ dm_task_destroy(dmt);
return r;
}
*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) {
/* cipher */
if (get_flags & DM_ACTIVE_CRYPT_CIPHER) {
- r = cipher_dm2c(CONST_CAST(char**)&cipher,
- CONST_CAST(char**)&integrity,
- rcipher, rintegrity);
+ r = crypt_capi_to_cipher(&cipher, &integrity, rcipher, rintegrity);
if (r < 0)
goto err;
}
*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"))
*act_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
+ else if (!strcasecmp(arg, "try_verify_in_tasklet"))
+ *act_flags |= CRYPT_ACTIVATE_TASKLETS;
else if (!strcasecmp(arg, "use_fec_from_device")) {
str = strsep(¶ms, " ");
str2 = crypt_lookup_dev(str);
str = strsep(¶ms, " ");
if (!str)
goto err;
- if (!root_hash_sig_key_desc)
+ if (vp && !root_hash_sig_key_desc) {
root_hash_sig_key_desc = strdup(str);
- i++;
- if (vp)
+ if (!root_hash_sig_key_desc) {
+ r = -ENOMEM;
+ goto err;
+ }
+ /* not stored in params, but cannot be used without vp */
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
+ }
+ i++;
} else /* unknown option */
goto err;
}
struct device *data_device = NULL, *meta_device = NULL;
char *integrity = NULL, *journal_crypt = NULL, *journal_integrity = NULL;
struct volume_key *vk = NULL;
+ struct volume_key *journal_integrity_key = NULL;
+ struct volume_key *journal_crypt_key = NULL;
tgt->type = DM_INTEGRITY;
tgt->direction = TARGET_QUERY;
goto err;
}
}
+
+ if (str) {
+ len = crypt_hex_to_bytes(str, &str2, 1);
+ if (len < 0) {
+ r = len;
+ goto err;
+ }
+
+ r = 0;
+ if (get_flags & DM_ACTIVE_JOURNAL_CRYPT_KEY) {
+ journal_crypt_key = crypt_alloc_volume_key(len, str2);
+ if (!journal_crypt_key)
+ r = -ENOMEM;
+ } else if (get_flags & DM_ACTIVE_JOURNAL_CRYPT_KEYSIZE) {
+ journal_crypt_key = crypt_alloc_volume_key(len, NULL);
+ if (!journal_crypt_key)
+ r = -ENOMEM;
+ }
+ crypt_safe_free(str2);
+ if (r < 0)
+ goto err;
+ }
} else if (!strncmp(arg, "journal_mac:", 12) && !journal_integrity) {
str = &arg[12];
arg = strsep(&str, ":");
goto err;
}
}
+
+ if (str) {
+ len = crypt_hex_to_bytes(str, &str2, 1);
+ if (len < 0) {
+ r = len;
+ goto err;
+ }
+
+ r = 0;
+ if (get_flags & DM_ACTIVE_JOURNAL_MAC_KEY) {
+ journal_integrity_key = crypt_alloc_volume_key(len, str2);
+ if (!journal_integrity_key)
+ r = -ENOMEM;
+ } else if (get_flags & DM_ACTIVE_JOURNAL_MAC_KEYSIZE) {
+ journal_integrity_key = crypt_alloc_volume_key(len, NULL);
+ if (!journal_integrity_key)
+ r = -ENOMEM;
+ }
+ crypt_safe_free(str2);
+ if (r < 0)
+ goto err;
+ }
} else if (!strcmp(arg, "recalculate")) {
*act_flags |= CRYPT_ACTIVATE_RECALCULATE;
+ } else if (!strcmp(arg, "reset_recalculate")) {
+ *act_flags |= CRYPT_ACTIVATE_RECALCULATE_RESET;
} 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 */
tgt->u.integrity.journal_integrity = journal_integrity;
if (vk)
tgt->u.integrity.vk = vk;
+ if (journal_integrity_key)
+ tgt->u.integrity.journal_integrity_key = journal_integrity_key;
+ if (journal_crypt_key)
+ tgt->u.integrity.journal_crypt_key = journal_crypt_key;
return 0;
err:
device_free(cd, data_device);
free(journal_crypt);
free(journal_integrity);
crypt_free_volume_key(vk);
+ crypt_free_volume_key(journal_integrity_key);
+ crypt_free_volume_key(journal_crypt_key);
return r;
}
return r;
}
-static int _dm_target_query_error(struct crypt_device *cd, struct dm_target *tgt)
+static int _dm_target_query_error(struct dm_target *tgt)
{
tgt->type = DM_ERROR;
tgt->direction = TARGET_QUERY;
return 0;
}
-static int _dm_target_query_zero(struct crypt_device *cd, struct dm_target *tgt)
+static int _dm_target_query_zero(struct dm_target *tgt)
{
tgt->type = DM_ZERO;
tgt->direction = TARGET_QUERY;
else if (!strcmp(target_type, DM_LINEAR_TARGET))
r = _dm_target_query_linear(cd, tgt, get_flags, params);
else if (!strcmp(target_type, DM_ERROR_TARGET))
- r = _dm_target_query_error(cd, tgt);
+ r = _dm_target_query_error(tgt);
else if (!strcmp(target_type, DM_ZERO_TARGET))
- r = _dm_target_query_zero(cd, tgt);
+ r = _dm_target_query_zero(tgt);
if (!r) {
tgt->offset = *start;
goto out;
}
- /* Never allow to return empty key */
+ /* Never allow one to return empty key */
if ((get_flags & DM_ACTIVE_CRYPT_KEY) && dmi.suspended) {
log_dbg(cd, "Cannot read volume key while suspended.");
r = -EINVAL;
r = (dmi.open_count > 0);
out:
- if (dmt)
- dm_task_destroy(dmt);
+ dm_task_destroy(dmt);
if (r < 0)
dm_targets_free(cd, dmd);
return r;
}
-static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_deps *deps, char **names, size_t names_offset, size_t names_length)
+static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_deps *deps,
+ char **names, size_t names_offset, size_t names_length)
{
#if HAVE_DECL_DM_DEVICE_GET_NAME
struct crypt_dm_active_device dmd;
#endif
}
-int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix, char **names, size_t names_length)
+int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix,
+ char **names, size_t names_length)
{
struct dm_task *dmt;
struct dm_info dmi;
{
uint32_t dmt_flags;
int msg_size;
- char *msg = NULL;
+ char *msg = NULL, *key = NULL;
int r = -ENOTSUP;
if (dm_init_context(cd, DM_CRYPT) || dm_flags(cd, DM_CRYPT, &dmt_flags))
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>
goto out;
}
- strcpy(msg, "key set ");
- 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);
+ if (vk->key_description) {
+ r = snprintf(msg, msg_size, "key set :%zu:logon:%s", vk->keylength, vk->key_description);
+ } else {
+ key = crypt_bytes_to_hex(vk->keylength, vk->key);
+ if (!key) {
+ r = -ENOMEM;
+ goto out;
+ }
+ r = snprintf(msg, msg_size, "key set %s", key);
+ }
+ if (r < 0 || r >= msg_size) {
+ r = -EINVAL;
+ goto out;
+ }
if (!_dm_message(name, msg) ||
_dm_resume_device(name, 0)) {
r = -EINVAL;
r = 0;
out:
crypt_safe_free(msg);
+ crypt_safe_free(key);
dm_exit_context();
return r;
}
+int dm_cancel_deferred_removal(const char *name)
+{
+ return _dm_message(name, "@cancel_deferred_remove") ? 0 : -ENOTSUP;
+}
+
const char *dm_get_dir(void)
{
return dm_dir();
uint64_t iv_offset, uint64_t data_offset, const char *integrity, uint32_t tag_size,
uint32_t sector_size)
{
- int r = -EINVAL;
-
- /* free on error */
char *dm_integrity = NULL;
if (tag_size) {
/* Space for IV metadata only */
dm_integrity = strdup(integrity ?: "none");
- if (!dm_integrity) {
- r = -ENOMEM;
- goto err;
- }
+ if (!dm_integrity)
+ return -ENOMEM;
}
tgt->data_device = data_device;
tgt->u.crypt.sector_size = sector_size;
return 0;
-err:
- free(dm_integrity);
-
- return r;
}
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;
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;
!(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;