Rework detection of DM target flags.

Because there are already 3 targets used, the current detection
based only on dm-crypt is not sufficient.

Add new definition of dm_flags that allows separate target version detect.

Note: we do not want to load targets explicitly; instead, we repeats
detection after operation that could trigger target load.

If dm_flags() call fails, then the target is not yet loaded.
This commit is contained in:
Milan Broz
2017-06-01 09:15:05 +02:00
parent 82f7cae22c
commit 40a9178c7f
5 changed files with 169 additions and 108 deletions

View File

@@ -22,6 +22,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
@@ -41,10 +42,14 @@
#define DM_INTEGRITY_TARGET "integrity" #define DM_INTEGRITY_TARGET "integrity"
#define RETRY_COUNT 5 #define RETRY_COUNT 5
/* Set if dm-crypt version was probed */ /* Set if DM target versions were probed */
static int _dm_crypt_checked = 0; static bool _dm_ioctl_checked = false;
static bool _dm_crypt_checked = false;
static bool _dm_verity_checked = false;
static bool _dm_integrity_checked = false;
static int _quiet_log = 0; static int _quiet_log = 0;
static uint32_t _dm_crypt_flags = 0; static uint32_t _dm_flags = 0;
static struct crypt_device *_context = NULL; static struct crypt_device *_context = NULL;
static int _dm_use_count = 0; static int _dm_use_count = 0;
@@ -114,55 +119,62 @@ static int _dm_satisfies_version(unsigned target_maj, unsigned target_min,
return 0; return 0;
} }
static void _dm_set_crypt_compat(const char *dm_version, unsigned crypt_maj, static void _dm_set_crypt_compat(unsigned crypt_maj,
unsigned crypt_min, unsigned crypt_patch) unsigned crypt_min,
unsigned crypt_patch)
{ {
unsigned dm_maj, dm_min, dm_patch; if (_dm_crypt_checked || crypt_maj == 0)
return;
if (sscanf(dm_version, "%u.%u.%u", &dm_maj, &dm_min, &dm_patch) != 3) log_dbg("Detected dm-crypt version %i.%i.%i.",
dm_maj = dm_min = dm_patch = 0; crypt_maj, crypt_min, crypt_patch);
log_dbg("Detected dm-crypt version %i.%i.%i, dm-ioctl version %u.%u.%u.",
crypt_maj, crypt_min, crypt_patch, dm_maj, dm_min, dm_patch);
if (_dm_satisfies_version(1, 2, crypt_maj, crypt_min)) if (_dm_satisfies_version(1, 2, crypt_maj, crypt_min))
_dm_crypt_flags |= DM_KEY_WIPE_SUPPORTED; _dm_flags |= DM_KEY_WIPE_SUPPORTED;
else else
log_dbg("Suspend and resume disabled, no wipe key support."); log_dbg("Suspend and resume disabled, no wipe key support.");
if (_dm_satisfies_version(1, 10, crypt_maj, crypt_min)) if (_dm_satisfies_version(1, 10, crypt_maj, crypt_min))
_dm_crypt_flags |= DM_LMK_SUPPORTED; _dm_flags |= DM_LMK_SUPPORTED;
if (_dm_satisfies_version(4, 20, dm_maj, dm_min))
_dm_crypt_flags |= DM_SECURE_SUPPORTED;
/* not perfect, 2.6.33 supports with 1.7.0 */ /* not perfect, 2.6.33 supports with 1.7.0 */
if (_dm_satisfies_version(1, 8, crypt_maj, crypt_min)) if (_dm_satisfies_version(1, 8, crypt_maj, crypt_min))
_dm_crypt_flags |= DM_PLAIN64_SUPPORTED; _dm_flags |= DM_PLAIN64_SUPPORTED;
if (_dm_satisfies_version(1, 11, crypt_maj, crypt_min)) if (_dm_satisfies_version(1, 11, crypt_maj, crypt_min))
_dm_crypt_flags |= DM_DISCARDS_SUPPORTED; _dm_flags |= DM_DISCARDS_SUPPORTED;
if (_dm_satisfies_version(1, 13, crypt_maj, crypt_min)) if (_dm_satisfies_version(1, 13, crypt_maj, crypt_min))
_dm_crypt_flags |= DM_TCW_SUPPORTED; _dm_flags |= DM_TCW_SUPPORTED;
if (_dm_satisfies_version(1, 14, crypt_maj, crypt_min)) { if (_dm_satisfies_version(1, 14, crypt_maj, crypt_min)) {
_dm_crypt_flags |= DM_SAME_CPU_CRYPT_SUPPORTED; _dm_flags |= DM_SAME_CPU_CRYPT_SUPPORTED;
_dm_crypt_flags |= DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED; _dm_flags |= DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED;
} }
/* Repeat test if dm-crypt is not present */ if (_dm_satisfies_version(1, 15, crypt_maj, crypt_min))
if (crypt_maj > 0) _dm_flags |= DM_KERNEL_KEYRING_SUPPORTED;
_dm_crypt_checked = 1;
if (_dm_satisfies_version(1, 17, crypt_maj, crypt_min)) {
_dm_flags |= DM_SECTOR_SIZE_SUPPORTED;
_dm_flags |= DM_CAPI_STRING_SUPPORTED;
}
_dm_crypt_checked = true;
} }
static void _dm_set_verity_compat(const char *dm_version, unsigned verity_maj, static void _dm_set_verity_compat(unsigned verity_maj,
unsigned verity_min, unsigned verity_patch) unsigned verity_min,
unsigned verity_patch)
{ {
if (verity_maj > 0) if (_dm_verity_checked || verity_maj == 0)
_dm_crypt_flags |= DM_VERITY_SUPPORTED;
else
return; return;
log_dbg("Detected dm-verity version %i.%i.%i.",
verity_maj, verity_min, verity_patch);
_dm_flags |= DM_VERITY_SUPPORTED;
/* /*
* ignore_corruption, restart_on corruption is available since 1.2 (kernel 4.1) * ignore_corruption, restart_on corruption is available since 1.2 (kernel 4.1)
* ignore_zero_blocks since 1.3 (kernel 4.5) * ignore_zero_blocks since 1.3 (kernel 4.5)
@@ -170,34 +182,40 @@ static void _dm_set_verity_compat(const char *dm_version, unsigned verity_maj,
* FEC is added in 1.3 as well. * FEC is added in 1.3 as well.
*/ */
if (_dm_satisfies_version(1, 3, verity_maj, verity_min)) { if (_dm_satisfies_version(1, 3, verity_maj, verity_min)) {
_dm_crypt_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED; _dm_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED;
_dm_crypt_flags |= DM_VERITY_FEC_SUPPORTED; _dm_flags |= DM_VERITY_FEC_SUPPORTED;
} }
log_dbg("Detected dm-verity version %i.%i.%i.", _dm_verity_checked = true;
verity_maj, verity_min, verity_patch);
} }
static void _dm_set_integrity_compat(const char *dm_version, unsigned integrity_maj, static void _dm_set_integrity_compat(unsigned integrity_maj,
unsigned integrity_min, unsigned integrity_patch) unsigned integrity_min,
unsigned integrity_patch)
{ {
if (integrity_maj > 0) if (_dm_integrity_checked || integrity_maj == 0)
_dm_crypt_flags |= DM_INTEGRITY_SUPPORTED;
else
return; return;
log_dbg("Detected dm-integrity version %i.%i.%i.", log_dbg("Detected dm-integrity version %i.%i.%i.",
integrity_maj, integrity_min, integrity_patch); integrity_maj, integrity_min, integrity_patch);
_dm_flags |= DM_INTEGRITY_SUPPORTED;
_dm_integrity_checked = true;
} }
static int _dm_check_versions(void) static int _dm_check_versions(dm_target_type target_type)
{ {
struct dm_task *dmt; struct dm_task *dmt;
struct dm_versions *target, *last_target; struct dm_versions *target, *last_target;
char dm_version[16]; char dm_version[16];
unsigned dm_maj, dm_min, dm_patch;
int r = 0; int r = 0;
if (_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) ||
(_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked))
return 1; return 1;
/* Shut up DM while checking */ /* Shut up DM while checking */
@@ -213,31 +231,40 @@ static int _dm_check_versions(void)
if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version))) if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version)))
goto out; goto out;
if (!_dm_ioctl_checked) {
if (sscanf(dm_version, "%u.%u.%u", &dm_maj, &dm_min, &dm_patch) != 3)
goto out;
log_dbg("Detected dm-ioctl version %u.%u.%u.", dm_maj, dm_min, dm_patch);
if (_dm_satisfies_version(4, 20, dm_maj, dm_min))
_dm_flags |= DM_SECURE_SUPPORTED;
}
target = dm_task_get_versions(dmt); target = dm_task_get_versions(dmt);
do { do {
last_target = target; last_target = target;
if (!strcmp(DM_CRYPT_TARGET, target->name)) { if (!strcmp(DM_CRYPT_TARGET, target->name)) {
_dm_set_crypt_compat(dm_version, _dm_set_crypt_compat((unsigned)target->version[0],
(unsigned)target->version[0],
(unsigned)target->version[1], (unsigned)target->version[1],
(unsigned)target->version[2]); (unsigned)target->version[2]);
} else if (!strcmp(DM_VERITY_TARGET, target->name)) { } else if (!strcmp(DM_VERITY_TARGET, target->name)) {
_dm_set_verity_compat(dm_version, _dm_set_verity_compat((unsigned)target->version[0],
(unsigned)target->version[0], (unsigned)target->version[1],
(unsigned)target->version[1], (unsigned)target->version[2]);
(unsigned)target->version[2]);
} else if (!strcmp(DM_INTEGRITY_TARGET, target->name)) { } else if (!strcmp(DM_INTEGRITY_TARGET, target->name)) {
_dm_set_integrity_compat(dm_version, _dm_set_integrity_compat((unsigned)target->version[0],
(unsigned)target->version[0], (unsigned)target->version[1],
(unsigned)target->version[1], (unsigned)target->version[2]);
(unsigned)target->version[2]);
} }
target = (struct dm_versions *)((char *) target + target->next); target = (struct dm_versions *)((char *) target + target->next);
} while (last_target != target); } while (last_target != target);
r = 1; r = 1;
log_dbg("Device-mapper backend running with UDEV support %sabled.", if (!_dm_ioctl_checked)
_dm_use_udev() ? "en" : "dis"); log_dbg("Device-mapper backend running with UDEV support %sabled.",
_dm_use_udev() ? "en" : "dis");
_dm_ioctl_checked = true;
out: out:
if (dmt) if (dmt)
dm_task_destroy(dmt); dm_task_destroy(dmt);
@@ -246,10 +273,21 @@ out:
return r; return r;
} }
uint32_t dm_flags(void) int dm_flags(dm_target_type target, uint32_t *flags)
{ {
_dm_check_versions(); _dm_check_versions(target);
return _dm_crypt_flags; *flags = _dm_flags;
if (target == DM_UNKNOWN &&
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked)
return 0;
if ((target == DM_CRYPT && _dm_crypt_checked) ||
(target == DM_VERITY && _dm_verity_checked) ||
(target == DM_INTEGRITY && _dm_integrity_checked))
return 0;
return -ENODEV;
} }
/* This doesn't run any kernel checks, just set up userspace libdevmapper */ /* This doesn't run any kernel checks, just set up userspace libdevmapper */
@@ -276,10 +314,10 @@ void dm_backend_exit(void)
* libdevmapper is not context friendly, switch context on every DM call. * 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. * FIXME: this is not safe if called in parallel but neither is DM lib.
*/ */
static int dm_init_context(struct crypt_device *cd) static int dm_init_context(struct crypt_device *cd, dm_target_type target)
{ {
_context = cd; _context = cd;
if (!_dm_check_versions()) { if (!_dm_check_versions(target)) {
if (getuid() || geteuid()) if (getuid() || geteuid())
log_err(cd, _("Cannot initialize device-mapper, " log_err(cd, _("Cannot initialize device-mapper, "
"running as non-root user.\n")); "running as non-root user.\n"));
@@ -682,7 +720,7 @@ int dm_remove_device(struct crypt_device *cd, const char *name,
if (!name || (force && !size)) if (!name || (force && !size))
return -EINVAL; return -EINVAL;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP; return -ENOTSUP;
do { do {
@@ -754,16 +792,30 @@ static int dm_prepare_uuid(const char *name, const char *type, const char *uuid,
static int _dm_create_device(const char *name, const char *type, static int _dm_create_device(const char *name, const char *type,
struct device *device, uint32_t flags, struct device *device, uint32_t flags,
const char *uuid, uint64_t size, const char *uuid, uint64_t size,
const char *target, char *params, int reload) dm_target_type target, char *params, int reload)
{ {
struct dm_task *dmt = NULL; struct dm_task *dmt = NULL;
struct dm_info dmi; struct dm_info dmi;
char dev_uuid[DM_UUID_LEN] = {0}; char dev_uuid[DM_UUID_LEN] = {0};
const char *target_name;
int r = -EINVAL; int r = -EINVAL;
uint32_t read_ahead = 0; uint32_t read_ahead = 0;
uint32_t cookie = 0; uint32_t cookie = 0;
uint32_t dmt_flags;
uint16_t udev_flags = 0; uint16_t udev_flags = 0;
/* Only need DM_SECURE_SUPPORTED, no target specific fail matters */
dm_flags(target, &dmt_flags);
if (target == DM_CRYPT)
target_name = DM_CRYPT_TARGET;
else if (target == DM_VERITY)
target_name = DM_VERITY_TARGET;
else if (target == DM_INTEGRITY)
target_name = DM_INTEGRITY_TARGET;
else
return -EINVAL;
if (!params) if (!params)
return -EINVAL; return -EINVAL;
@@ -791,12 +843,12 @@ static int _dm_create_device(const char *name, const char *type,
goto out_no_removal; goto out_no_removal;
} }
if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt)) if ((dmt_flags & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
goto out_no_removal; goto out_no_removal;
if ((flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt)) if ((flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
goto out_no_removal; goto out_no_removal;
if (!dm_task_add_target(dmt, 0, size, target, params)) if (!dm_task_add_target(dmt, 0, size, target_name, params))
goto out_no_removal; goto out_no_removal;
#ifdef DM_READ_AHEAD_MINIMUM_FLAG #ifdef DM_READ_AHEAD_MINIMUM_FLAG
@@ -848,18 +900,18 @@ out_no_removal:
dm_task_update_nodes(); dm_task_update_nodes();
/* If code just loaded target module, update versions */ /* If code just loaded target module, update versions */
_dm_check_versions(); _dm_check_versions(target);
return r; return r;
} }
static int check_retry(uint32_t *dmd_flags) static int check_retry(uint32_t *dmd_flags, uint32_t dmt_flags)
{ {
int ret = 0; int ret = 0;
/* If discard not supported try to load without discard */ /* If discard not supported try to load without discard */
if ((*dmd_flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) && if ((*dmd_flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
!(dm_flags() & DM_DISCARDS_SUPPORTED)) { !(dmt_flags & DM_DISCARDS_SUPPORTED)) {
log_dbg("Discard/TRIM is not supported"); log_dbg("Discard/TRIM is not supported");
*dmd_flags = *dmd_flags & ~CRYPT_ACTIVATE_ALLOW_DISCARDS; *dmd_flags = *dmd_flags & ~CRYPT_ACTIVATE_ALLOW_DISCARDS;
ret = 1; ret = 1;
@@ -873,57 +925,55 @@ int dm_create_device(struct crypt_device *cd, const char *name,
struct crypt_dm_active_device *dmd, struct crypt_dm_active_device *dmd,
int reload) int reload)
{ {
char *table_params = NULL, *target; char *table_params = NULL;
uint32_t dmd_flags; uint32_t dmd_flags, dmt_flags;
int r; int r = -EINVAL;
if (!type) if (!type)
return -EINVAL; return -EINVAL;
if (dm_init_context(cd)) if (dm_init_context(cd, dmd->target))
return -ENOTSUP; return -ENOTSUP;
dmd_flags = dmd->flags; dmd_flags = dmd->flags;
if (dmd->target == DM_CRYPT) { if (dmd->target == DM_CRYPT)
table_params = get_dm_crypt_params(dmd, dmd_flags); table_params = get_dm_crypt_params(dmd, dmd_flags);
target = DM_CRYPT_TARGET; else if (dmd->target == DM_VERITY)
} else if (dmd->target == DM_VERITY) {
table_params = get_dm_verity_params(dmd->u.verity.vp, dmd, dmd_flags); table_params = get_dm_verity_params(dmd->u.verity.vp, dmd, dmd_flags);
target = DM_VERITY_TARGET; else if (dmd->target == DM_INTEGRITY)
} else if (dmd->target == DM_INTEGRITY) {
table_params = get_dm_integrity_params(dmd, dmd_flags); table_params = get_dm_integrity_params(dmd, dmd_flags);
target = DM_INTEGRITY_TARGET; else
} else { goto out;
dm_exit_context();
return -EINVAL;
}
r = _dm_create_device(name, type, dmd->data_device, dmd_flags, r = _dm_create_device(name, type, dmd->data_device, dmd_flags,
dmd->uuid, dmd->size, target, table_params, reload); dmd->uuid, dmd->size, dmd->target, table_params, reload);
if (!reload && r && dmd->target == DM_CRYPT && check_retry(&dmd_flags)) { if (r < 0 && dm_flags(dmd->target, &dmt_flags))
goto out;
if (!reload && r && dmd->target == DM_CRYPT && check_retry(&dmd_flags, dmt_flags)) {
crypt_safe_free(table_params); crypt_safe_free(table_params);
table_params = get_dm_crypt_params(dmd, dmd_flags); table_params = get_dm_crypt_params(dmd, dmd_flags);
r = _dm_create_device(name, type, dmd->data_device, dmd_flags, r = _dm_create_device(name, type, dmd->data_device, dmd_flags,
dmd->uuid, dmd->size, target, table_params, reload); dmd->uuid, dmd->size, dmd->target, table_params, reload);
} }
if (r == -EINVAL && if (r == -EINVAL &&
dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) && dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
!(dm_flags() & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) !(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
log_err(cd, _("Requested dm-crypt performance options are not supported.\n")); log_err(cd, _("Requested dm-crypt performance options are not supported.\n"));
if (r == -EINVAL && dmd_flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION| if (r == -EINVAL && dmd_flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION| CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) && CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) &&
!(dm_flags() & DM_VERITY_ON_CORRUPTION_SUPPORTED)) !(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED))
log_err(cd, _("Requested dm-verity data corruption handling options are not supported.\n")); log_err(cd, _("Requested dm-verity data corruption handling options are not supported.\n"));
if (r == -EINVAL && dmd->target == DM_VERITY && dmd->u.verity.fec_device && if (r == -EINVAL && dmd->target == DM_VERITY && dmd->u.verity.fec_device &&
!(dm_flags() & DM_VERITY_FEC_SUPPORTED)) !(dmt_flags & DM_VERITY_FEC_SUPPORTED))
log_err(cd, _("Requested dm-verity FEC options are not supported.\n")); log_err(cd, _("Requested dm-verity FEC options are not supported.\n"));
out:
crypt_safe_free(table_params); crypt_safe_free(table_params);
dm_exit_context(); dm_exit_context();
return r; return r;
@@ -993,7 +1043,7 @@ int dm_status_device(struct crypt_device *cd, const char *name)
if (strchr(name, '/') && stat(name, &st) < 0) if (strchr(name, '/') && stat(name, &st) < 0)
return -ENODEV; return -ENODEV;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP; return -ENOTSUP;
r = dm_status_dmi(name, &dmi, NULL, NULL); r = dm_status_dmi(name, &dmi, NULL, NULL);
dm_exit_context(); dm_exit_context();
@@ -1008,9 +1058,9 @@ int dm_status_suspended(struct crypt_device *cd, const char *name)
int r; int r;
struct dm_info dmi; struct dm_info dmi;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP; return -ENOTSUP;
r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL); r = dm_status_dmi(name, &dmi, NULL, NULL);
dm_exit_context(); dm_exit_context();
if (r < 0) if (r < 0)
return r; return r;
@@ -1041,7 +1091,7 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name)
{ {
int r; int r;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_VERITY))
return -ENOTSUP; return -ENOTSUP;
r = _dm_status_verity_ok(name); r = _dm_status_verity_ok(name);
dm_exit_context(); dm_exit_context();
@@ -1460,16 +1510,18 @@ int dm_query_device(struct crypt_device *cd, const char *name,
struct dm_task *dmt; struct dm_task *dmt;
struct dm_info dmi; struct dm_info dmi;
uint64_t start, length; uint64_t start, length;
uint32_t dmt_flags;
char *target_type, *params; char *target_type, *params;
const char *tmp_uuid; const char *tmp_uuid;
void *next = NULL; void *next = NULL;
int r = -EINVAL; int r = -EINVAL;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP; return -ENOTSUP;
if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
goto out; goto out;
if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt)) dm_flags(DM_UNKNOWN, &dmt_flags);
if ((dmt_flags & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
goto out; goto out;
if (!dm_task_set_name(dmt, name)) if (!dm_task_set_name(dmt, name))
goto out; goto out;
@@ -1534,7 +1586,7 @@ out:
return r; return r;
} }
static int _dm_message(const char *name, const char *msg) static int _dm_message(const char *name, const char *msg, uint32_t dmt_flags)
{ {
int r = 0; int r = 0;
struct dm_task *dmt; struct dm_task *dmt;
@@ -1542,7 +1594,7 @@ static int _dm_message(const char *name, const char *msg)
if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG))) if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
return 0; return 0;
if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt)) if ((dmt_flags & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
goto out; goto out;
if (name && !dm_task_set_name(dmt, name)) if (name && !dm_task_set_name(dmt, name))
@@ -1555,20 +1607,20 @@ static int _dm_message(const char *name, const char *msg)
goto out; goto out;
r = dm_task_run(dmt); r = dm_task_run(dmt);
out:
out:
dm_task_destroy(dmt); dm_task_destroy(dmt);
return r; return r;
} }
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name) int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
{ {
uint32_t dmt_flags;
int r = -ENOTSUP; int r = -ENOTSUP;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_CRYPT) || dm_flags(DM_CRYPT, &dmt_flags))
return -ENOTSUP; return -ENOTSUP;
if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED)) if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
goto out; goto out;
if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) { if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) {
@@ -1576,7 +1628,7 @@ int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
goto out; goto out;
} }
if (!_dm_message(name, "key wipe")) { if (!_dm_message(name, "key wipe", dmt_flags)) {
_dm_simple(DM_DEVICE_RESUME, name, 1); _dm_simple(DM_DEVICE_RESUME, name, 1);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
@@ -1590,14 +1642,15 @@ out:
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name, int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
size_t key_size, const char *key) size_t key_size, const char *key)
{ {
uint32_t dmt_flags;
int msg_size = key_size * 2 + 10; // key set <key> int msg_size = key_size * 2 + 10; // key set <key>
char *msg = NULL; char *msg = NULL;
int r = -ENOTSUP; int r = -ENOTSUP;
if (dm_init_context(cd)) if (dm_init_context(cd, DM_CRYPT) || dm_flags(DM_CRYPT, &dmt_flags))
return -ENOTSUP; return -ENOTSUP;
if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED)) if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
goto out; goto out;
msg = crypt_safe_alloc(msg_size); msg = crypt_safe_alloc(msg_size);
@@ -1609,7 +1662,7 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
strcpy(msg, "key set "); strcpy(msg, "key set ");
hex_key(&msg[8], key_size, key); hex_key(&msg[8], key_size, key);
if (!_dm_message(name, msg) || if (!_dm_message(name, msg, dmt_flags) ||
!_dm_simple(DM_DEVICE_RESUME, name, 1)) { !_dm_simple(DM_DEVICE_RESUME, name, 1)) {
r = -EINVAL; r = -EINVAL;
goto out; goto out;

View File

@@ -204,7 +204,7 @@ int LOOPAES_activate(struct crypt_device *cd,
uint32_t flags) uint32_t flags)
{ {
char *cipher = NULL; char *cipher = NULL;
uint32_t req_flags; uint32_t req_flags, dmc_flags;
int r; int r;
struct crypt_dm_active_device dmd = { struct crypt_dm_active_device dmd = {
.target = DM_CRYPT, .target = DM_CRYPT,
@@ -240,7 +240,8 @@ int LOOPAES_activate(struct crypt_device *cd,
r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0); r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0);
if (r < 0 && !(dm_flags() & req_flags)) { if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
(dmc_flags & req_flags) != req_flags) {
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n")); log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
r = -ENOTSUP; r = -ENOTSUP;
} }

View File

@@ -691,7 +691,7 @@ int TCRYPT_activate(struct crypt_device *cd,
struct device *device = NULL, *part_device = NULL; struct device *device = NULL, *part_device = NULL;
unsigned int i; unsigned int i;
int r; int r;
uint32_t req_flags; uint32_t req_flags, dmc_flags;
struct tcrypt_algs *algs; struct tcrypt_algs *algs;
enum devcheck device_check; enum devcheck device_check;
struct crypt_dm_active_device dmd = { struct crypt_dm_active_device dmd = {
@@ -817,7 +817,8 @@ int TCRYPT_activate(struct crypt_device *cd,
break; break;
} }
if (r < 0 && !(dm_flags() & req_flags)) { if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
(dmc_flags & req_flags) != req_flags) {
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping.\n")); log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping.\n"));
r = -ENOTSUP; r = -ENOTSUP;
} }

View File

@@ -44,9 +44,14 @@ struct device;
#define DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED (1 << 8) /* submit_from_crypt_cpus */ #define DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED (1 << 8) /* submit_from_crypt_cpus */
#define DM_VERITY_ON_CORRUPTION_SUPPORTED (1 << 9) /* ignore/restart_on_corruption, ignore_zero_block */ #define DM_VERITY_ON_CORRUPTION_SUPPORTED (1 << 9) /* ignore/restart_on_corruption, ignore_zero_block */
#define DM_VERITY_FEC_SUPPORTED (1 << 10) /* Forward Error Correction (FEC) */ #define DM_VERITY_FEC_SUPPORTED (1 << 10) /* Forward Error Correction (FEC) */
#define DM_KERNEL_KEYRING_SUPPORTED (1 << 11) /* dm-crypt allows loading kernel keyring keys */
#define DM_INTEGRITY_SUPPORTED (1 << 12) /* dm-integrity target supported */ #define DM_INTEGRITY_SUPPORTED (1 << 12) /* dm-integrity target supported */
#define DM_SECTOR_SIZE_SUPPORTED (1 << 13) /* support for sector size setting in dm-crypt/dm-integrity */
#define DM_CAPI_STRING_SUPPORTED (1 << 14) /* support for cryptoapi format cipher definition */
uint32_t dm_flags(void); typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_UNKNOWN } dm_target_type;
int dm_flags(dm_target_type target, uint32_t *flags);
#define DM_ACTIVE_DEVICE (1 << 0) #define DM_ACTIVE_DEVICE (1 << 0)
#define DM_ACTIVE_UUID (1 << 1) #define DM_ACTIVE_UUID (1 << 1)
@@ -60,7 +65,7 @@ uint32_t dm_flags(void);
#define DM_ACTIVE_VERITY_PARAMS (1 << 7) #define DM_ACTIVE_VERITY_PARAMS (1 << 7)
struct crypt_dm_active_device { struct crypt_dm_active_device {
enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY } target; dm_target_type target;
uint64_t size; /* active device size */ uint64_t size; /* active device size */
uint32_t flags; /* activation flags */ uint32_t flags; /* activation flags */
const char *uuid; const char *uuid;

View File

@@ -241,6 +241,7 @@ int VERITY_activate(struct crypt_device *cd,
uint32_t activation_flags) uint32_t activation_flags)
{ {
struct crypt_dm_active_device dmd; struct crypt_dm_active_device dmd;
uint32_t dmv_flags;
int r; int r;
log_dbg("Trying to activate VERITY device %s using hash %s.", log_dbg("Trying to activate VERITY device %s using hash %s.",
@@ -289,7 +290,7 @@ int VERITY_activate(struct crypt_device *cd,
} }
r = dm_create_device(cd, name, CRYPT_VERITY, &dmd, 0); r = dm_create_device(cd, name, CRYPT_VERITY, &dmd, 0);
if (r < 0 && !(dm_flags() & DM_VERITY_SUPPORTED)) { if (r < 0 && !dm_flags(DM_VERITY, &dmv_flags) && !(dmv_flags & DM_VERITY_SUPPORTED)) {
log_err(cd, _("Kernel doesn't support dm-verity mapping.\n")); log_err(cd, _("Kernel doesn't support dm-verity mapping.\n"));
return -ENOTSUP; return -ENOTSUP;
} }