From d5e48fcb00e3ea81cf802074422dc3e44a50f1fa Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Fri, 26 Aug 2011 19:46:17 +0000 Subject: [PATCH] Enhance check of device size before writing LUKS header. (Thanks to okozina@redhat.com) git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@607 36d66b0a-2a48-0410-832c-cd162a569da5 --- ChangeLog | 1 + lib/luks1/keymanage.c | 40 ++++++++++++++++++++++++++++++++++++++++ tests/api-test.c | 22 +++++++++++----------- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5a7099d..a3eaec1 100644 --- 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 * Remove hash/hmac restart from crypto backend and make it part of hash/hmac final. diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index 6e43340..96a325e 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -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); diff --git a/tests/api-test.c b/tests/api-test.c index 9d17d00..d7dc795 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -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, ¶ms), "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, ¶ms), "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, ¶ms)); -// 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, ¶ms)); + 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, ¶ms), "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, ¶ms), "Device too small"); + crypt_free(cd); // 0 sectors for encrypted area OK_(crypt_init(&cd, DMDIR L_DEVICE_0S)); -- 2.7.4