Set context for DM log for all DM backend entries.

Try to handle error if run as non-root user better.
This commit is contained in:
Milan Broz
2012-08-14 16:53:02 +02:00
parent 97224b072a
commit 1d5788f779
8 changed files with 145 additions and 79 deletions

View File

@@ -2,6 +2,7 @@
* Allocate loop device late (only when real block device needed). * Allocate loop device late (only when real block device needed).
* Rework underlying device/file access functions. * Rework underlying device/file access functions.
* Create hash image if doesn't exist in veritysetup format. * Create hash image if doesn't exist in veritysetup format.
* Provide better error message if running as non-root user (device-mapper, loop).
2012-07-10 Milan Broz <gmazyland@gmail.com> 2012-07-10 Milan Broz <gmazyland@gmail.com>
* Version 1.5.0. * Version 1.5.0.

View File

@@ -38,10 +38,11 @@
/* Set if dm-crypt version was probed */ /* Set if dm-crypt version was probed */
static int _dm_crypt_checked = 0; static int _dm_crypt_checked = 0;
static int _quiet_log = 0;
static uint32_t _dm_crypt_flags = 0; static uint32_t _dm_crypt_flags = 0;
static int _dm_use_count = 0;
static struct crypt_device *_context = NULL; static struct crypt_device *_context = NULL;
static int _dm_use_count = 0;
/* Check if we have DM flag to instruct kernel to force wipe buffers */ /* Check if we have DM flag to instruct kernel to force wipe buffers */
#if !HAVE_DECL_DM_TASK_SECURE_DATA #if !HAVE_DECL_DM_TASK_SECURE_DATA
@@ -81,11 +82,14 @@ static void set_dm_error(int level,
va_start(va, f); va_start(va, f);
if (vasprintf(&msg, f, va) > 0) { if (vasprintf(&msg, f, va) > 0) {
if (level < 4) { if (level < 4 && !_quiet_log) {
log_err(_context, msg); log_err(_context, msg);
log_err(_context, "\n"); log_err(_context, "\n");
} else } else {
log_dbg(msg); /* We do not use DM visual stack backtrace here */
if (strncmp(msg, "<backtrace>", 11))
log_dbg(msg);
}
} }
free(msg); free(msg);
va_end(va); va_end(va);
@@ -142,23 +146,23 @@ static int _dm_check_versions(void)
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];
int r = 0;
if (_dm_crypt_checked) if (_dm_crypt_checked)
return 1; return 1;
/* Shut up DM while checking */
_quiet_log = 1;
/* FIXME: add support to DM so it forces crypt target module load here */ /* FIXME: add support to DM so it forces crypt target module load here */
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
return 0; goto out;
if (!dm_task_run(dmt)) { if (!dm_task_run(dmt))
dm_task_destroy(dmt); goto out;
return 0;
}
if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version))) { if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version)))
dm_task_destroy(dmt); goto out;
return 0;
}
target = dm_task_get_versions(dmt); target = dm_task_get_versions(dmt);
do { do {
@@ -177,52 +181,67 @@ static int _dm_check_versions(void)
target = (struct dm_versions *)((char *) target + target->next); target = (struct dm_versions *)((char *) target + target->next);
} while (last_target != target); } while (last_target != target);
dm_task_destroy(dmt); r = 1;
return 1; log_dbg("Device-mapper backend running with UDEV support %sabled.",
_dm_use_udev() ? "en" : "dis");
out:
if (dmt)
dm_task_destroy(dmt);
_quiet_log = 0;
return r;
} }
uint32_t dm_flags(void) uint32_t dm_flags(void)
{ {
if (!_dm_crypt_checked) _dm_check_versions();
_dm_check_versions();
return _dm_crypt_flags; return _dm_crypt_flags;
} }
int dm_init(struct crypt_device *context, int check_kernel) /* This doesn't run any kernel checks, just set up userspace libdevmapper */
void dm_backend_init(void)
{ {
if (!_dm_use_count++) { if (!_dm_use_count++) {
log_dbg("Initialising device-mapper backend%s, UDEV is %sabled.", log_dbg("Initialising device-mapper backend library.");
check_kernel ? "" : " (NO kernel check requested)",
_dm_use_udev() ? "en" : "dis");
if (check_kernel && !_dm_check_versions()) {
log_err(context, _("Cannot initialize device-mapper. Is dm_mod kernel module loaded?\n"));
return -1;
}
if (getuid() || geteuid())
log_dbg(("WARNING: Running as a non-root user. Functionality may be unavailable."));
dm_log_init(set_dm_error); dm_log_init(set_dm_error);
dm_log_init_verbose(10); dm_log_init_verbose(10);
} }
// FIXME: global context is not safe
if (context)
_context = context;
return 1; /* unsafe memory */
} }
void dm_exit(void) void dm_backend_exit(void)
{ {
if (_dm_use_count && (!--_dm_use_count)) { if (_dm_use_count && (!--_dm_use_count)) {
log_dbg("Releasing device-mapper backend."); log_dbg("Releasing device-mapper backend.");
dm_log_init_verbose(0); dm_log_init_verbose(0);
dm_log_init(NULL); dm_log_init(NULL);
dm_lib_release(); dm_lib_release();
_context = NULL;
} }
} }
/*
* 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.
*/
static int dm_init_context(struct crypt_device *cd)
{
_context = cd;
if (!_dm_check_versions()) {
if (getuid() || geteuid())
log_err(cd, _("Cannot initialize device-mapper, "
"running as non-root user.\n"));
else
log_err(cd, _("Cannot initialize device-mapper. "
"Is dm_mod kernel module loaded?\n"));
_context = NULL;
return -ENOTSUP;
}
return 0;
}
static void dm_exit_context(void)
{
_context = NULL;
}
/* Return path to DM device */ /* Return path to DM device */
char *dm_device_path(const char *prefix, int major, int minor) char *dm_device_path(const char *prefix, int major, int minor)
{ {
@@ -435,6 +454,9 @@ 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))
return -ENOTSUP;
do { do {
r = _dm_simple(DM_DEVICE_REMOVE, name, 1) ? 0 : -EINVAL; r = _dm_simple(DM_DEVICE_REMOVE, name, 1) ? 0 : -EINVAL;
if (--retries && r) { if (--retries && r) {
@@ -457,6 +479,7 @@ int dm_remove_device(struct crypt_device *cd, const char *name,
} while (r == -EINVAL && retries); } while (r == -EINVAL && retries);
dm_task_update_nodes(); dm_task_update_nodes();
dm_exit_context();
return r; return r;
} }
@@ -596,17 +619,25 @@ int dm_create_device(struct crypt_device *cd, const char *name,
int reload) int reload)
{ {
char *table_params = NULL; char *table_params = NULL;
int r = -EINVAL;
if (!type)
return -EINVAL;
if (dm_init_context(cd))
return -ENOTSUP;
if (dmd->target == DM_CRYPT) if (dmd->target == DM_CRYPT)
table_params = get_dm_crypt_params(dmd); table_params = get_dm_crypt_params(dmd);
else if (dmd->target == DM_VERITY) else if (dmd->target == DM_VERITY)
table_params = get_dm_verity_params(dmd->u.verity.vp, dmd); table_params = get_dm_verity_params(dmd->u.verity.vp, dmd);
if (!table_params || !type) if (table_params)
return -EINVAL; r = _dm_create_device(name, type, dmd->data_device,
dmd->flags, dmd->uuid, dmd->size,
return _dm_create_device(name, type, dmd->data_device, dmd->flags, table_params, reload);
dmd->uuid, dmd->size, table_params, reload); dm_exit_context();
return r;
} }
static int dm_status_dmi(const char *name, struct dm_info *dmi, static int dm_status_dmi(const char *name, struct dm_info *dmi,
@@ -664,7 +695,10 @@ int dm_status_device(struct crypt_device *cd, const char *name)
int r; int r;
struct dm_info dmi; struct dm_info dmi;
if (dm_init_context(cd))
return -ENOTSUP;
r = dm_status_dmi(name, &dmi, NULL, NULL); r = dm_status_dmi(name, &dmi, NULL, NULL);
dm_exit_context();
if (r < 0) if (r < 0)
return r; return r;
@@ -676,7 +710,10 @@ 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))
return -ENOTSUP;
r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL); r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL);
dm_exit_context();
if (r < 0) if (r < 0)
return r; return r;
@@ -704,7 +741,13 @@ static int _dm_status_verity_ok(const char *name)
int dm_status_verity_ok(struct crypt_device *cd, const char *name) int dm_status_verity_ok(struct crypt_device *cd, const char *name)
{ {
return _dm_status_verity_ok(name); int r;
if (dm_init_context(cd))
return -ENOTSUP;
r = _dm_status_verity_ok(name);
dm_exit_context();
return r;
} }
/* FIXME use hex wrapper, user val wrappers for line parsing */ /* FIXME use hex wrapper, user val wrappers for line parsing */
@@ -943,6 +986,8 @@ int dm_query_device(struct crypt_device *cd, const char *name,
void *next = NULL; void *next = NULL;
int r = -EINVAL; int r = -EINVAL;
if (dm_init_context(cd))
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)) if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
@@ -1004,6 +1049,7 @@ out:
if (dmt) if (dmt)
dm_task_destroy(dmt); dm_task_destroy(dmt);
dm_exit_context();
return r; return r;
} }
@@ -1036,49 +1082,62 @@ static int _dm_message(const char *name, const char *msg)
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)
{ {
if (!_dm_check_versions()) int r = -ENOTSUP;
if (dm_init_context(cd))
return -ENOTSUP; return -ENOTSUP;
if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED)) if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED))
return -ENOTSUP; goto out;
if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) {
return -EINVAL; r = -EINVAL;
goto out;
}
if (!_dm_message(name, "key wipe")) { if (!_dm_message(name, "key wipe")) {
_dm_simple(DM_DEVICE_RESUME, name, 1); _dm_simple(DM_DEVICE_RESUME, name, 1);
return -EINVAL; r = -EINVAL;
goto out;
} }
r = 0;
return 0; out:
dm_exit_context();
return r;
} }
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)
{ {
int msg_size = key_size * 2 + 10; // key set <key> int msg_size = key_size * 2 + 10; // key set <key>
char *msg; char *msg = NULL;
int r = 0; int r = -ENOTSUP;
if (!_dm_check_versions()) if (dm_init_context(cd))
return -ENOTSUP; return -ENOTSUP;
if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED)) if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED))
return -ENOTSUP; goto out;
msg = crypt_safe_alloc(msg_size); msg = crypt_safe_alloc(msg_size);
if (!msg) if (!msg) {
return -ENOMEM; r = -ENOMEM;
goto out;
}
memset(msg, 0, msg_size); memset(msg, 0, msg_size);
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) ||
!_dm_simple(DM_DEVICE_RESUME, name, 1)) !_dm_simple(DM_DEVICE_RESUME, name, 1)) {
r = -EINVAL; r = -EINVAL;
goto out;
}
r = 0;
out:
crypt_safe_free(msg); crypt_safe_free(msg);
dm_exit_context();
return r; return r;
} }

View File

@@ -143,7 +143,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
r = setup_mapping(dmCipherSpec, name, bsize, vk, sector, srcLength, mode, ctx); r = setup_mapping(dmCipherSpec, name, bsize, vk, sector, srcLength, mode, ctx);
if(r < 0) { if(r < 0) {
if (r != -EACCES) if (r != -EACCES && r != -ENOTSUP)
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n" log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
"Check that kernel supports %s cipher (check syslog for more info).\n%s"), "Check that kernel supports %s cipher (check syslog for more info).\n%s"),
device_path(crypt_metadata_device(ctx)), dmCipherSpec, device_path(crypt_metadata_device(ctx)), dmCipherSpec,

View File

@@ -530,10 +530,7 @@ int crypt_init(struct crypt_device **cd, const char *device)
if (r < 0) if (r < 0)
goto bad; goto bad;
if (dm_init(h, 1) < 0) { dm_backend_init();
r = -ENOSYS;
goto bad;
}
h->iteration_time = 1000; h->iteration_time = 1000;
h->password_verify = 0; h->password_verify = 0;
@@ -940,6 +937,11 @@ static int _crypt_format_luks1(struct crypt_device *cd,
&required_alignment, &required_alignment,
&alignment_offset, DEFAULT_DISK_ALIGNMENT); &alignment_offset, DEFAULT_DISK_ALIGNMENT);
/* Check early if we cannot allocate block device for key slot access */
r = device_block_adjust(cd, cd->device, DEV_OK, 0, NULL, NULL);
if(r < 0)
return r;
r = LUKS_generate_phdr(&cd->hdr, cd->volume_key, cipher, cipher_mode, r = LUKS_generate_phdr(&cd->hdr, cd->volume_key, cipher, cipher_mode,
(params && params->hash) ? params->hash : "sha1", (params && params->hash) ? params->hash : "sha1",
uuid, LUKS_STRIPES, uuid, LUKS_STRIPES,
@@ -1334,7 +1336,7 @@ void crypt_free(struct crypt_device *cd)
if (cd) { if (cd) {
log_dbg("Releasing crypt device %s context.", mdata_device_path(cd)); log_dbg("Releasing crypt device %s context.", mdata_device_path(cd));
dm_exit(); dm_backend_exit();
crypt_free_volume_key(cd->volume_key); crypt_free_volume_key(cd->volume_key);
device_free(cd->device); device_free(cd->device);
@@ -1382,8 +1384,8 @@ int crypt_suspend(struct crypt_device *cd,
return -EINVAL; return -EINVAL;
} }
if (!cd && dm_init(NULL, 1) < 0) if (!cd)
return -ENOSYS; dm_backend_init();
r = dm_status_suspended(cd, name); r = dm_status_suspended(cd, name);
if (r < 0) if (r < 0)
@@ -1402,7 +1404,7 @@ int crypt_suspend(struct crypt_device *cd,
log_err(cd, "Error during suspending device %s.\n", name); log_err(cd, "Error during suspending device %s.\n", name);
out: out:
if (!cd) if (!cd)
dm_exit(); dm_backend_exit();
return r; return r;
} }
@@ -2019,8 +2021,8 @@ int crypt_deactivate(struct crypt_device *cd, const char *name)
log_dbg("Deactivating volume %s.", name); log_dbg("Deactivating volume %s.", name);
if (!cd && dm_init(NULL, 1) < 0) if (!cd)
return -ENOSYS; dm_backend_init();
switch (crypt_status(cd, name)) { switch (crypt_status(cd, name)) {
case CRYPT_ACTIVE: case CRYPT_ACTIVE:
@@ -2037,7 +2039,7 @@ int crypt_deactivate(struct crypt_device *cd, const char *name)
} }
if (!cd) if (!cd)
dm_exit(); dm_backend_exit();
return r; return r;
} }
@@ -2167,13 +2169,13 @@ crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
{ {
int r; int r;
if (!cd && dm_init(NULL, 1) < 0) if (!cd)
return CRYPT_INVALID; dm_backend_init();
r = dm_status_device(cd, name); r = dm_status_device(cd, name);
if (!cd) if (!cd)
dm_exit(); dm_backend_exit();
if (r < 0 && r != -ENODEV) if (r < 0 && r != -ENODEV)
return CRYPT_INVALID; return CRYPT_INVALID;

View File

@@ -229,7 +229,7 @@ int crypt_memlock_inc(struct crypt_device *ctx)
if (!_memlock_count++) { if (!_memlock_count++) {
log_dbg("Locking memory."); log_dbg("Locking memory.");
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n")); log_dbg("Cannot lock memory with mlockall.");
_memlock_count--; _memlock_count--;
return 0; return 0;
} }

View File

@@ -326,11 +326,15 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
if (device->init_done) if (device->init_done)
return 0; return 0;
log_dbg("Allocating free loop device."); log_dbg("Allocating a free loop device.");
loop_device = crypt_loop_get_device(); loop_device = crypt_loop_get_device();
if (!loop_device) { if (!loop_device) {
log_err(cd, _("Cannot find a free loopback device.\n")); if (getuid() || geteuid())
return -EINVAL; log_err(cd, _("Cannot use a loopback device, "
"running as non-root user.\n"));
else
log_err(cd, _("Cannot find a free loopback device.\n"));
return -ENOTSUP;
} }
/* Keep the loop open, dettached on last close. */ /* Keep the loop open, dettached on last close. */

View File

@@ -79,8 +79,8 @@ struct crypt_dm_active_device {
} u; } u;
}; };
int dm_init(struct crypt_device *context, int check_kernel); void dm_backend_init(void);
void dm_exit(void); void dm_backend_exit(void);
int dm_remove_device(struct crypt_device *cd, const char *name, int dm_remove_device(struct crypt_device *cd, const char *name,
int force, uint64_t size); int force, uint64_t size);

View File

@@ -582,7 +582,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
} }
} }
if (r < 0) if (r == -EPERM)
log_err(_("No key available with this passphrase.\n")); log_err(_("No key available with this passphrase.\n"));
out: out:
crypt_safe_free(password); crypt_safe_free(password);