Check device size when loading LUKS header.
authorMilan Broz <gmazyland@gmail.com>
Sat, 20 Jun 2009 09:24:33 +0000 (09:24 +0000)
committerMilan Broz <gmazyland@gmail.com>
Sat, 20 Jun 2009 09:24:33 +0000 (09:24 +0000)
(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
luks/keyencryption.c
luks/keymanage.c

index 6c3daea..3e74029 100644 (file)
@@ -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:
index 94af4a8..22c845a 100644 (file)
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <ctype.h>
 #include <inttypes.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/utsname.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
@@ -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;
        }
index 193a97b..2a09874 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <unistd.h>
@@ -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;
 }