Enhance check of device size before writing LUKS header.
authorMilan Broz <gmazyland@gmail.com>
Fri, 26 Aug 2011 19:46:17 +0000 (19:46 +0000)
committerMilan Broz <gmazyland@gmail.com>
Fri, 26 Aug 2011 19:46:17 +0000 (19:46 +0000)
(Thanks to okozina@redhat.com)

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@607 36d66b0a-2a48-0410-832c-cd162a569da5

ChangeLog
lib/luks1/keymanage.c
tests/api-test.c

index 5a7099d..a3eaec1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
        * Add more paranoid checks for LUKS header and keyslot attributes.
        * Fix crypt_load to properly check device size.
        * Use new /dev/loop-control (kernel 3.1) if possible.
+       * Enhance check of device size before writing LUKS header.
 
 2011-07-25  Milan Broz  <mbroz@redhat.com>
        * Remove hash/hmac restart from crypto backend and make it part of hash/hmac final.
index 6e43340..96a325e 100644 (file)
@@ -45,6 +45,41 @@ static inline int round_up_modulo(int x, int m) {
        return div_round_up(x, m) * m;
 }
 
+/* Get size of struct luks_phrd with all keyslots material space */
+static uint64_t LUKS_device_sectors(size_t keyLen, unsigned int stripes)
+{
+       uint64_t keyslot_sectors, sector;
+       int i;
+
+       keyslot_sectors = div_round_up(keyLen * stripes, SECTOR_SIZE);
+       sector = round_up_modulo(LUKS_PHDR_SIZE, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
+
+       for (i = 0; i < LUKS_NUMKEYS; i++) {
+               sector = round_up_modulo(sector, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
+               sector += keyslot_sectors;
+       }
+
+       return sector;
+}
+
+static int LUKS_check_device_size(const char *device,
+                                 uint64_t min_sectors,
+                                 size_t keyLength)
+{
+       uint64_t dev_size, req_sectors;
+
+       req_sectors = LUKS_device_sectors(keyLength, LUKS_STRIPES);
+       if (min_sectors > req_sectors)
+               req_sectors = min_sectors;
+
+       if(device_size(device, &dev_size)) {
+               log_dbg("Cannot get device size for device %s.", device);
+               return -EIO;
+       }
+
+       return (req_sectors > (dev_size >> SECTOR_SHIFT));
+}
+
 /* Check keyslot to prevent access outside of header and keyslot area */
 static int LUKS_check_keyslot_size(const struct luks_phdr *phdr, unsigned int keyIndex)
 {
@@ -391,6 +426,11 @@ int LUKS_write_phdr(const char *device,
        log_dbg("Updating LUKS header of size %d on device %s",
                sizeof(struct luks_phdr), device);
 
+       if (LUKS_check_device_size(device, hdr->payloadOffset, hdr->keyBytes)) {
+               log_err(ctx, _("Device %s is too small.\n"), device);
+               return -EINVAL;
+       }
+
        devfd = open(device,O_RDWR | O_DIRECT | O_SYNC);
        if(-1 == devfd) {
                log_err(ctx, _("Cannot open device %s.\n"), device);
index 9d17d00..d7dc795 100644 (file)
@@ -923,16 +923,16 @@ static void AddDeviceLuks(void)
        OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, r_header_size - 1));
 
        // format
-//     OK_(crypt_init(&cd, DMDIR H_DEVICE_WRONG));
-//     params.data_alignment = 0;
-//     FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params), "Not enough space for keyslots material");
-//     crypt_free(cd);
+       OK_(crypt_init(&cd, DMDIR H_DEVICE_WRONG));
+       params.data_alignment = 0;
+       FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params), "Not enough space for keyslots material");
+       crypt_free(cd);
 
        // test payload_offset = 0 for encrypted device with external header device
-//     OK_(crypt_init(&cd, DMDIR H_DEVICE));
-//     OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params));
-//     EQ_(crypt_get_data_offset(cd), 0);
-//     crypt_free(cd);
+       OK_(crypt_init(&cd, DMDIR H_DEVICE));
+       OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params));
+       EQ_(crypt_get_data_offset(cd), 0);
+       crypt_free(cd);
 
        params.data_alignment = 0;
        params.data_device = NULL;
@@ -953,9 +953,9 @@ static void AddDeviceLuks(void)
        OK_(create_dmdevice_over_loop(L_DEVICE_WRONG, r_payload_offset - 1));
 
        // 1 sector less than required
-//     OK_(crypt_init(&cd, DMDIR L_DEVICE_WRONG));
-//     FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params), "Device too small");
-//     crypt_free(cd);
+       OK_(crypt_init(&cd, DMDIR L_DEVICE_WRONG));
+       FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params), "Device too small");
+       crypt_free(cd);
 
        // 0 sectors for encrypted area
        OK_(crypt_init(&cd, DMDIR L_DEVICE_0S));