From 1dcd5a3de5bbb23581a6d3970975cbd927facf57 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Fri, 30 Apr 2010 12:03:41 +0000 Subject: [PATCH] Detect old dm-crypt module and disable LUKS suspend/resume. Fix apitest to work on older systems. git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@205 36d66b0a-2a48-0410-832c-cd162a569da5 --- ChangeLog | 5 +++++ lib/libdevmapper.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++--- lib/setup.c | 8 +++++-- tests/apitest.c | 37 ++++++++++++++++++++++++++++++--- 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index f61ee59..5ccd91b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-04-30 Milan Broz + * Try to use pkgconfig for device mapper library. + * Detect old dm-crypt module and disable LUKS suspend/resume. + * Fix apitest to work on older systems. + 2010-04-12 Milan Broz * Fix package config to use proper package version. * Avoid class C++ keyword in library header. diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index e697f71..6040727 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -18,6 +18,8 @@ #define DM_CRYPT_TARGET "crypt" #define RETRY_COUNT 5 +static int _dm_crypt_wipe_key_supported = 0; + static int _dm_use_count = 0; static struct crypt_device *_context = NULL; @@ -61,16 +63,63 @@ static void set_dm_error(int level, const char *file, int line, static int _dm_simple(int task, const char *name, int udev_wait); +static void _dm_set_crypt_compat(struct crypt_device *context, + int maj, int min, int patch) +{ + log_dbg("Detected dm-crypt target of version %i.%i.%i.", maj, min, patch); + + if (maj >= 1 && min >=2) + _dm_crypt_wipe_key_supported = 1; + else + log_dbg("Suspend and resume disabled, no wipe key support."); +} + +static int _dm_check_versions(struct crypt_device *context) +{ + int r = 0; + struct dm_task *dmt; + struct dm_versions *target, *last_target; + + if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) + goto fail_versions; + + if (!dm_task_run(dmt)) { + dm_task_destroy(dmt); + goto fail_versions; + } + + target = dm_task_get_versions(dmt); + do { + last_target = target; + if (!strcmp(DM_CRYPT_TARGET, target->name)) { + r = 1; + _dm_set_crypt_compat(context, + (int)target->version[0], + (int)target->version[1], + (int)target->version[2]); + } + target = (void *) target + target->next; + } while (last_target != target); + + if (!r) + log_err(context, _("Cannot find compatible device-mapper kernel modules.\n")); + + dm_task_destroy(dmt); + return r; + +fail_versions: + log_err(context, _("Cannot initialize device-mapper. Is dm_mod kernel module loaded?\n")); + return 0; +} + int dm_init(struct crypt_device *context, int check_kernel) { 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_simple(DM_DEVICE_LIST_VERSIONS, NULL, 0)) { - log_err(context, _("Cannot initialize device-mapper. Is dm_mod kernel module loaded?\n")); + if (check_kernel && !_dm_check_versions(context)) return -1; - } if (getuid() || geteuid()) log_dbg(("WARNING: Running as a non-root user. Functionality may be unavailable.")); dm_log_init(set_dm_error); @@ -665,6 +714,9 @@ static int _dm_message(const char *name, const char *msg) int dm_suspend_and_wipe_key(const char *name) { + if (!_dm_crypt_wipe_key_supported) + return -ENOTSUP; + if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) return -EINVAL; @@ -684,6 +736,9 @@ int dm_resume_and_reinstate_key(const char *name, char *msg; int r = 0; + if (!_dm_crypt_wipe_key_supported) + return -ENOTSUP; + msg = safe_alloc(msg_size); if (!msg) return -ENOMEM; diff --git a/lib/setup.c b/lib/setup.c index 061636b..fd264f3 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -1304,7 +1304,9 @@ int crypt_suspend(struct crypt_device *cd, } r = dm_suspend_and_wipe_key(name); - if (r) + if (r == -ENOTSUP) + log_err(cd, "Suspend is not supported for device %s.\n", name); + else if (r) log_err(cd, "Error during suspending device %s.\n", name); out: if (!cd) @@ -1348,7 +1350,9 @@ int crypt_resume_by_passphrase(struct crypt_device *cd, if (r >= 0) { keyslot = r; r = dm_resume_and_reinstate_key(name, mk->keyLength, mk->key); - if (r) + if (r == -ENOTSUP) + log_err(cd, "Resume is not supported for device %s.\n", name); + else if (r) log_err(cd, "Error during resuming device %s.\n", name); } else r = keyslot; diff --git a/tests/apitest.c b/tests/apitest.c index 9e5e517..14f6aed 100644 --- a/tests/apitest.c +++ b/tests/apitest.c @@ -58,6 +58,8 @@ static int _verbose = 1; static char global_log[4096]; static int global_lines = 0; +static int gcrypt_compatible = 0; + // Helpers static int _prepare_keyfile(const char *name, const char *passphrase) { @@ -585,13 +587,19 @@ static void UseLuksDevice(void) static void SuspendDevice(void) { + int suspend_status; struct crypt_device *cd; OK_(crypt_init(&cd, DEVICE_1)); OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); - OK_(crypt_suspend(cd, CDEVICE_1)); + suspend_status = crypt_suspend(cd, CDEVICE_1); + if (suspend_status == -ENOTSUP) { + printf("WARNING: Suspend/Resume not supported, skipping test.\n"); + goto out; + } + OK_(suspend_status); FAIL_(crypt_suspend(cd, CDEVICE_1), "already suspended"); FAIL_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1)-1), "wrong key"); @@ -604,7 +612,7 @@ static void SuspendDevice(void) OK_(crypt_resume_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0)); FAIL_(crypt_resume_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0), "not suspended"); _remove_keyfiles(); - +out: OK_(crypt_deactivate(cd, CDEVICE_1)); crypt_free(cd); } @@ -688,11 +696,34 @@ static void NonFIPSAlg(void) char *cipher = "aes"; char *cipher_mode = "cbc-essiv:sha256"; + if (!gcrypt_compatible) { + printf("WARNING: old libgcrypt, skipping test.\n"); + return; + } OK_(crypt_init(&cd, DEVICE_2)); OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms)); crypt_free(cd); } + +static void _gcrypt_compatible() +{ + int maj, min, patch; + FILE *f; + + if (!(f = popen("libgcrypt-config --version", "r"))) + return; + + if (fscanf(f, "%d.%d.%d", &maj, &min, &patch) == 2 && + maj >= 1 && min >= 4) + gcrypt_compatible = 1; + if (_debug) + printf("libgcrypt version %d.%d.%d detected.\n", maj, min, patch); + + (void)fclose(f); + return; +} + int main (int argc, char *argv[]) { int i; @@ -711,6 +742,7 @@ int main (int argc, char *argv[]) _cleanup(); _setup(); + _gcrypt_compatible(); crypt_set_debug_level(_debug ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE); @@ -729,7 +761,6 @@ int main (int argc, char *argv[]) RUN_(UseLuksDevice, "Use pre-formated LUKS device"); RUN_(SuspendDevice, "Suspend/Resume test"); - _cleanup(); return 0; } -- 2.7.4