From db96ccef4650eec3f4afb456d255076baacce896 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sat, 20 Jun 2009 09:24:33 +0000 Subject: [PATCH] Check device size when loading LUKS header. (And remove misleading error message later.) Because kernel and libdevmapper does not provide better error message then "invalid parameters" add some error hint if dm-crypt mapping failed. (Key size and kernel version check for XTS and LRW mode for now.) git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@52 36d66b0a-2a48-0410-832c-cd162a569da5 --- lib/libdevmapper.c | 15 +++++++-------- luks/keyencryption.c | 45 ++++++++++++++++++++++++++++++++++++-------- luks/keymanage.c | 16 +++++++++++++--- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 6c3daea2..3e740294 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -233,6 +233,7 @@ static int dm_create_device(int reload, struct crypt_options *options, struct dm_task *dmt_query = NULL; struct dm_info dmi; char *params = NULL; + char *error = NULL; int r = -EINVAL; params = get_params(options, key); @@ -268,17 +269,15 @@ static int dm_create_device(int reload, struct crypt_options *options, r = 0; out: if (r < 0 && !reload) { - char *error = (char *)get_error(); - if (error) - error = strdup(error); + if (get_error()) + error = strdup(get_error()); - if (!_dm_remove(options, 0)) - goto out_restore_error; + _dm_remove(options, 0); -out_restore_error: - set_error("%s", error); - if (error) + if (error) { + set_error(error); free(error); + } } out_no_removal: diff --git a/luks/keyencryption.c b/luks/keyencryption.c index 94af4a87..22c845a5 100644 --- a/luks/keyencryption.c +++ b/luks/keyencryption.c @@ -20,11 +20,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -85,10 +87,9 @@ static int setup_mapping(const char *cipher, const char *name, options->flags |= CRYPT_FLAG_READONLY; } - r = backend->create(0, options, key); + set_error(NULL); - if (r <= 0) - set_error(NULL); + r = backend->create(0, options, key); return r; } @@ -112,6 +113,35 @@ static void sigint_handler(int sig) kill(getpid(), SIGINT); } +static char *_error_hint(char *cipherName, char *cipherMode, size_t keyLength) +{ + char *hint = ""; +#ifdef __linux__ + char c, tmp[4] = {0}; + struct utsname uts; + int i = 0, kernel_minor; + + /* Nothing to suggest here */ + if (uname(&uts) || strncmp(uts.release, "2.6.", 4)) + return hint; + + /* Get kernel minor without suffixes */ + while (i < 3 && (c = uts.release[i + 4])) + tmp[i++] = isdigit(c) ? c : '\0'; + kernel_minor = atoi(tmp); + + if (!strncmp(cipherMode, "xts", 3) && (keyLength != 256 && keyLength != 512)) + hint = "Key size in XTS mode must be 256 or 512 bits."; + else if (!strncmp(cipherMode, "xts", 3) && kernel_minor < 24) + hint = "Block mode XTS is available since kernel 2.6.24."; + if (!strncmp(cipherMode, "lrw", 3) && (keyLength != 256 && keyLength != 512)) + hint = "Key size in LRW mode must be 256 or 512 bits."; + else if (!strncmp(cipherMode, "lrw", 3) && kernel_minor < 20) + hint = "Block mode LRW is available since kernel 2.6.20."; +#endif + return hint; +} + /* This function is not reentrant safe, as it installs a signal handler and global vars for cleaning */ static int LUKS_endec_template(char *src, size_t srcLength, @@ -145,11 +175,10 @@ static int LUKS_endec_template(char *src, size_t srcLength, r = setup_mapping(dmCipherSpec,name,device,hdr->payloadOffset,key,keyLength,sector,srcLength,backend,mode); if(r < 0) { - if(!get_error()) - set_error("Failed to setup dm-crypt key mapping.\nCheck kernel for support for the %s cipher spec and verify that %s contains at least %d sectors", - dmCipherSpec, - device, - sector + div_round_up(srcLength,SECTOR_SIZE)); + set_error("Failed to setup dm-crypt key mapping for device %s.\n" + "Check that kernel supports %s cipher (check syslog for more info).\n%s", + device, dmCipherSpec, + _error_hint(hdr->cipherName, hdr->cipherMode, keyLength * 8)); r = -EIO; goto out1; } diff --git a/luks/keymanage.c b/luks/keymanage.c index 193a97b6..2a098744 100644 --- a/luks/keymanage.c +++ b/luks/keymanage.c @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include #include @@ -79,11 +81,11 @@ struct luks_masterkey *LUKS_generate_masterkey(int keylength) int LUKS_read_phdr(const char *device, struct luks_phdr *hdr) { - int devfd = 0; + int devfd = 0, r = 0; unsigned int i; - int r = 0; + uint64_t size; char luksMagic[] = LUKS_MAGIC; - + devfd = open(device,O_RDONLY | O_DIRECT | O_SYNC); if(-1 == devfd) { set_error(_("Can't open device: %s\n"), device); @@ -114,7 +116,15 @@ int LUKS_read_phdr(const char *device, struct luks_phdr *hdr) } } +#ifdef BLKGETSIZE64 + if (ioctl(devfd, BLKGETSIZE64, &size) < 0 || + size < (uint64_t)hdr->payloadOffset) { + set_error(_("LUKS header detected but device %s is too small.\n"), device); + r = -EINVAL; + } +#endif close(devfd); + return r; }