X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Flibdevmapper.c;h=f7113925e8eff25998aa069a2326d2ff00279bef;hb=f45d4d0755239da85e553dcfe24e6c9b82ac7818;hp=149d2979517d68efd496f49816bdbd02e2b04c53;hpb=05b695d5165f280bcdffbac9a312a3fee1202436;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 149d297..f711392 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -38,10 +38,11 @@ /* Set if dm-crypt version was probed */ static int _dm_crypt_checked = 0; +static int _quiet_log = 0; static uint32_t _dm_crypt_flags = 0; -static int _dm_use_count = 0; 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 */ #if !HAVE_DECL_DM_TASK_SECURE_DATA @@ -81,11 +82,14 @@ static void set_dm_error(int level, va_start(va, f); if (vasprintf(&msg, f, va) > 0) { - if (level < 4) { + if (level < 4 && !_quiet_log) { log_err(_context, msg); log_err(_context, "\n"); - } else - log_dbg(msg); + } else { + /* We do not use DM visual stack backtrace here */ + if (strncmp(msg, "", 11)) + log_dbg(msg); + } } free(msg); va_end(va); @@ -142,23 +146,23 @@ static int _dm_check_versions(void) struct dm_task *dmt; struct dm_versions *target, *last_target; char dm_version[16]; + int r = 0; if (_dm_crypt_checked) return 1; + /* Shut up DM while checking */ + _quiet_log = 1; + /* FIXME: add support to DM so it forces crypt target module load here */ if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) - return 0; + goto out; - if (!dm_task_run(dmt)) { - dm_task_destroy(dmt); - return 0; - } + if (!dm_task_run(dmt)) + goto out; - if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version))) { - dm_task_destroy(dmt); - return 0; - } + if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version))) + goto out; target = dm_task_get_versions(dmt); do { @@ -177,50 +181,65 @@ static int _dm_check_versions(void) target = (struct dm_versions *)((char *) target + target->next); } while (last_target != target); - dm_task_destroy(dmt); - return 1; + r = 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) { - if (!_dm_crypt_checked) - _dm_check_versions(); - + _dm_check_versions(); 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++) { - log_dbg("Initialising device-mapper backend%s, UDEV is %sabled.", - 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.")); + log_dbg("Initialising device-mapper backend library."); dm_log_init(set_dm_error); 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)) { log_dbg("Releasing device-mapper backend."); dm_log_init_verbose(0); dm_log_init(NULL); dm_lib_release(); + } +} + +/* + * 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 */ @@ -256,21 +275,6 @@ static void hex_key(char *hexkey, size_t key_size, const char *key) sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]); } -static size_t hex_to_bytes(const char *hex, char *result) -{ - char buf[3] = "xx\0", *endp; - size_t i, len; - - len = strlen(hex) / 2; - for (i = 0; i < len; i++) { - memcpy(buf, &hex[i * 2], 2); - result[i] = strtoul(buf, &endp, 16); - if (endp != &buf[2]) - return -EINVAL; - } - return i; -} - /* http://code.google.com/p/cryptsetup/wiki/DMCrypt */ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd) { @@ -302,14 +306,16 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd) hex_key(hexkey, dmd->u.crypt.vk->keylength, dmd->u.crypt.vk->key); max_size = strlen(hexkey) + strlen(dmd->u.crypt.cipher) + - strlen(dmd->data_device) + strlen(features) + 64; + strlen(device_block_path(dmd->data_device)) + + strlen(features) + 64; params = crypt_safe_alloc(max_size); if (!params) goto out; r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s", dmd->u.crypt.cipher, hexkey, dmd->u.crypt.iv_offset, - dmd->data_device, dmd->u.crypt.offset, features); + device_block_path(dmd->data_device), dmd->u.crypt.offset, + features); if (r < 0 || r >= max_size) { crypt_safe_free(params); params = NULL; @@ -343,8 +349,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp, strncpy(hexsalt, "-", 2); max_size = strlen(hexroot) + strlen(hexsalt) + - strlen(dmd->data_device) + - strlen(dmd->u.verity.hash_device) + + strlen(device_block_path(dmd->data_device)) + + strlen(device_block_path(dmd->u.verity.hash_device)) + strlen(vp->hash_name) + 128; params = crypt_safe_alloc(max_size); @@ -353,8 +359,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp, r = snprintf(params, max_size, "%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s", - vp->hash_type, dmd->data_device, - dmd->u.verity.hash_device, + vp->hash_type, device_block_path(dmd->data_device), + device_block_path(dmd->u.verity.hash_device), vp->data_block_size, vp->hash_block_size, vp->data_size, dmd->u.verity.hash_offset, vp->hash_name, hexroot, hexsalt); @@ -438,7 +444,8 @@ error: return r; } -int dm_remove_device(const char *name, int force, uint64_t size) +int dm_remove_device(struct crypt_device *cd, const char *name, + int force, uint64_t size) { int r = -EINVAL; int retries = force ? RETRY_COUNT : 1; @@ -447,13 +454,14 @@ int dm_remove_device(const char *name, int force, uint64_t size) if (!name || (force && !size)) return -EINVAL; + if (dm_init_context(cd)) + return -ENOTSUP; + do { r = _dm_simple(DM_DEVICE_REMOVE, name, 1) ? 0 : -EINVAL; if (--retries && r) { log_dbg("WARNING: other process locked internal device %s, %s.", name, retries ? "retrying remove" : "giving up"); - if (force && (crypt_get_debug_level() == CRYPT_LOG_DEBUG)) - debug_processes_using_device(name); sleep(1); if (force && !error_target) { /* If force flag is set, replace device with error, read-only target. @@ -471,6 +479,7 @@ int dm_remove_device(const char *name, int force, uint64_t size) } while (r == -EINVAL && retries); dm_task_update_nodes(); + dm_exit_context(); return r; } @@ -508,7 +517,7 @@ static void dm_prepare_uuid(const char *name, const char *type, const char *uuid } static int _dm_create_device(const char *name, const char *type, - const char *device, uint32_t flags, + struct device *device, uint32_t flags, const char *uuid, uint64_t size, char *params, int reload) { @@ -589,7 +598,7 @@ out: } if (r < 0 && !reload) - dm_remove_device(name, 0, 0); + _dm_simple(DM_DEVICE_REMOVE, name, 1); out_no_removal: if (cookie && _dm_use_udev()) @@ -604,23 +613,31 @@ out_no_removal: return r; } -int dm_create_device(const char *name, +int dm_create_device(struct crypt_device *cd, const char *name, const char *type, struct crypt_dm_active_device *dmd, int reload) { char *table_params = NULL; + int r = -EINVAL; + + if (!type) + return -EINVAL; + + if (dm_init_context(cd)) + return -ENOTSUP; if (dmd->target == DM_CRYPT) table_params = get_dm_crypt_params(dmd); else if (dmd->target == DM_VERITY) table_params = get_dm_verity_params(dmd->u.verity.vp, dmd); - if (!table_params || !type) - return -EINVAL; - - return _dm_create_device(name, type, dmd->data_device, dmd->flags, - dmd->uuid, dmd->size, table_params, reload); + if (table_params) + r = _dm_create_device(name, type, dmd->data_device, + dmd->flags, dmd->uuid, dmd->size, + table_params, reload); + dm_exit_context(); + return r; } static int dm_status_dmi(const char *name, struct dm_info *dmi, @@ -673,31 +690,37 @@ out: return r; } -int dm_status_device(const char *name) +int dm_status_device(struct crypt_device *cd, const char *name) { int r; struct dm_info dmi; + if (dm_init_context(cd)) + return -ENOTSUP; r = dm_status_dmi(name, &dmi, NULL, NULL); + dm_exit_context(); if (r < 0) return r; return (dmi.open_count > 0); } -int dm_status_suspended(const char *name) +int dm_status_suspended(struct crypt_device *cd, const char *name) { int r; struct dm_info dmi; + if (dm_init_context(cd)) + return -ENOTSUP; r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL); + dm_exit_context(); if (r < 0) return r; return dmi.suspended ? 1 : 0; } -int dm_status_verity_ok(const char *name) +static int _dm_status_verity_ok(const char *name) { int r; struct dm_info dmi; @@ -716,6 +739,17 @@ int dm_status_verity_ok(const char *name) return r; } +int dm_status_verity_ok(struct crypt_device *cd, const char *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 */ static int _dm_query_crypt(uint32_t get_flags, struct dm_info *dmi, @@ -725,6 +759,7 @@ static int _dm_query_crypt(uint32_t get_flags, uint64_t val64; char *rcipher, *key_, *rdevice, *endp, buffer[3], *arg; unsigned int i; + int r; memset(dmd, 0, sizeof(*dmd)); dmd->target = DM_CRYPT; @@ -747,8 +782,13 @@ static int _dm_query_crypt(uint32_t get_flags, /* device */ rdevice = strsep(¶ms, " "); - if (get_flags & DM_ACTIVE_DEVICE) - dmd->data_device = crypt_lookup_dev(rdevice); + if (get_flags & DM_ACTIVE_DEVICE) { + arg = crypt_lookup_dev(rdevice); + r = device_alloc(&dmd->data_device, arg); + free(arg); + if (r < 0 && r != -ENOTBLK) + return r; + } /*offset */ if (!params) @@ -820,8 +860,9 @@ static int _dm_query_verity(uint32_t get_flags, struct crypt_params_verity *vp = NULL; uint32_t val32; uint64_t val64; - size_t len; + ssize_t len; char *str, *str2; + int r; if (get_flags & DM_ACTIVE_VERITY_PARAMS) vp = dmd->u.verity.vp; @@ -843,15 +884,25 @@ static int _dm_query_verity(uint32_t get_flags, str = strsep(¶ms, " "); if (!params) return -EINVAL; - if (get_flags & DM_ACTIVE_DEVICE) - dmd->data_device = crypt_lookup_dev(str); + if (get_flags & DM_ACTIVE_DEVICE) { + str2 = crypt_lookup_dev(str); + r = device_alloc(&dmd->data_device, str2); + free(str2); + if (r < 0 && r != -ENOTBLK) + return r; + } /* hash device */ str = strsep(¶ms, " "); if (!params) return -EINVAL; - if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE) - dmd->u.verity.hash_device = crypt_lookup_dev(str); + if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE) { + str2 = crypt_lookup_dev(str); + r = device_alloc(&dmd->u.verity.hash_device, str2); + free(str2); + if (r < 0 && r != -ENOTBLK) + return r; + } /* data block size*/ val32 = strtoul(params, ¶ms, 10); @@ -895,35 +946,37 @@ static int _dm_query_verity(uint32_t get_flags, str = strsep(¶ms, " "); if (!params) return -EINVAL; - len = strlen(str) / 2; + len = crypt_hex_to_bytes(str, &str2, 0); + if (len < 0) + return len; dmd->u.verity.root_hash_size = len; - if (get_flags & DM_ACTIVE_VERITY_ROOT_HASH) { - if (!(str2 = malloc(len))) - return -ENOMEM; - if (hex_to_bytes(str, str2) != len) - return -EINVAL; + if (get_flags & DM_ACTIVE_VERITY_ROOT_HASH) dmd->u.verity.root_hash = str2; - } + else + free(str2); /* salt */ str = strsep(¶ms, " "); if (params) return -EINVAL; if (vp) { - len = strlen(str) / 2; - vp->salt_size = len; - if (!(str2 = malloc(len))) - return -ENOMEM; - if (hex_to_bytes(str, str2) != len) - return -EINVAL; - vp->salt = str2; + if (!strcmp(str, "-")) { + vp->salt_size = 0; + vp->salt = NULL; + } else { + len = crypt_hex_to_bytes(str, &str2, 0); + if (len < 0) + return len; + vp->salt_size = len; + vp->salt = str2; + } } return 0; } -int dm_query_device(const char *name, uint32_t get_flags, - struct crypt_dm_active_device *dmd) +int dm_query_device(struct crypt_device *cd, const char *name, + uint32_t get_flags, struct crypt_dm_active_device *dmd) { struct dm_task *dmt; struct dm_info dmi; @@ -933,6 +986,8 @@ int dm_query_device(const char *name, uint32_t get_flags, void *next = NULL; int r = -EINVAL; + if (dm_init_context(cd)) + return -ENOTSUP; if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) goto out; if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt)) @@ -964,7 +1019,7 @@ int dm_query_device(const char *name, uint32_t get_flags, r = _dm_query_verity(get_flags, &dmi, params, dmd); if (r < 0) goto out; - r = dm_status_verity_ok(name); + r = _dm_status_verity_ok(name); if (r < 0) goto out; if (r == 0) @@ -994,6 +1049,7 @@ out: if (dmt) dm_task_destroy(dmt); + dm_exit_context(); return r; } @@ -1024,52 +1080,63 @@ static int _dm_message(const char *name, const char *msg) return r; } -int dm_suspend_and_wipe_key(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; if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED)) - return -ENOTSUP; + goto out; - if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) - return -EINVAL; + if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) { + r = -EINVAL; + goto out; + } if (!_dm_message(name, "key wipe")) { _dm_simple(DM_DEVICE_RESUME, name, 1); - return -EINVAL; + r = -EINVAL; + goto out; } - - return 0; + r = 0; +out: + dm_exit_context(); + return r; } -int dm_resume_and_reinstate_key(const char *name, - size_t key_size, - const char *key) +int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name, + size_t key_size, const char *key) { int msg_size = key_size * 2 + 10; // key set - char *msg; - int r = 0; + char *msg = NULL; + int r = -ENOTSUP; - if (!_dm_check_versions()) + if (dm_init_context(cd)) return -ENOTSUP; if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED)) - return -ENOTSUP; + goto out; msg = crypt_safe_alloc(msg_size); - if (!msg) - return -ENOMEM; + if (!msg) { + r = -ENOMEM; + goto out; + } - memset(msg, 0, msg_size); strcpy(msg, "key set "); hex_key(&msg[8], key_size, key); if (!_dm_message(name, msg) || - !_dm_simple(DM_DEVICE_RESUME, name, 1)) + !_dm_simple(DM_DEVICE_RESUME, name, 1)) { r = -EINVAL; - + goto out; + } + r = 0; +out: crypt_safe_free(msg); + dm_exit_context(); return r; } @@ -1087,27 +1154,3 @@ int dm_is_dm_kernel_name(const char *name) { return strncmp(name, "dm-", 3) ? 0 : 1; } - -int dm_check_segment(const char *name, uint64_t offset, uint64_t size) -{ - struct crypt_dm_active_device dmd; - int r; - - log_dbg("Checking segments for device %s.", name); - - r = dm_query_device(name, 0, &dmd); - if (r < 0) - return r; - - if (offset >= (dmd.u.crypt.offset + dmd.size) || - (offset + size) <= dmd.u.crypt.offset) - r = 0; - else - r = -EBUSY; - - log_dbg("seg: %" PRIu64 " - %" PRIu64 ", new %" PRIu64 " - %" PRIu64 "%s", - dmd.u.crypt.offset, dmd.u.crypt.offset + dmd.size, offset, offset + size, - r ? " (overlapping)" : " (ok)"); - - return r; -}