From 231a2e932d07d43f90b34b4a36ef462dd597bdaa Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 18 Apr 2011 10:52:15 +0000 Subject: [PATCH] Fix possible leaks in blockwise read/write code. Fix lseek_write blockwise function (not used in that mode anyway). git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@511 36d66b0a-2a48-0410-832c-cd162a569da5 --- lib/internal.h | 4 +-- lib/luks1/keyencryption.c | 5 ++- lib/luks1/keymanage.c | 20 ++++++----- lib/utils.c | 86 +++++++++++++++++++++++++++++------------------ 4 files changed, 70 insertions(+), 45 deletions(-) diff --git a/lib/internal.h b/lib/internal.h index 6ffae93..821c383 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -92,9 +92,9 @@ int dm_resume_and_reinstate_key(const char *name, const char *key); int sector_size_for_device(const char *device); -ssize_t write_blockwise(int fd, const void *buf, size_t count); +ssize_t write_blockwise(int fd, void *buf, size_t count); ssize_t read_blockwise(int fd, void *_buf, size_t count); -ssize_t write_lseek_blockwise(int fd, const char *buf, size_t count, off_t offset); +ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset); int device_ready(struct crypt_device *cd, const char *device, int mode); int get_device_infos(const char *device, int open_exclusive, diff --git a/lib/luks1/keyencryption.c b/lib/luks1/keyencryption.c index 127f4b8..c37724a 100644 --- a/lib/luks1/keyencryption.c +++ b/lib/luks1/keyencryption.c @@ -193,9 +193,8 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength, unsigned int sector, struct crypt_device *ctx) { - return LUKS_endec_template(src,srcLength,hdr,key,keyLength, device, sector, - (ssize_t (*)(int, void *, size_t)) write_blockwise, - O_RDWR, ctx); + return LUKS_endec_template(src,srcLength,hdr,key,keyLength, device, + sector, write_blockwise, O_RDWR, ctx); } int LUKS_decrypt_from_storage(char *dst, size_t dstLength, diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index b854cf4..6c07492 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -764,29 +764,33 @@ static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn) static int wipe(const char *device, unsigned int from, unsigned int to) { - int devfd; + int devfd, r = 0; char *buffer; - unsigned int i; - unsigned int bufLen = (to - from) * SECTOR_SIZE; - int r = 0; + unsigned int i, bufLen; + ssize_t written; devfd = open(device, O_RDWR | O_DIRECT | O_SYNC); if(devfd == -1) return -EINVAL; - buffer = (char *) malloc(bufLen); + bufLen = (to - from) * SECTOR_SIZE; + buffer = malloc(bufLen); if(!buffer) { close(devfd); return -ENOMEM; } for(i = 0; i < 39; ++i) { - if (i < 5) crypt_random_get(NULL, buffer, bufLen, CRYPT_RND_NORMAL); + if (i < 5) crypt_random_get(NULL, buffer, bufLen, + CRYPT_RND_NORMAL); else if(i >= 5 && i < 32) wipeSpecial(buffer, bufLen, i - 5); - else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, bufLen, CRYPT_RND_NORMAL); + else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, bufLen, + CRYPT_RND_NORMAL); else if(i >= 38 && i < 39) memset(buffer, 0xFF, bufLen); - if(write_lseek_blockwise(devfd, buffer, bufLen, from * SECTOR_SIZE) < 0) { + written = write_lseek_blockwise(devfd, buffer, bufLen, + from * SECTOR_SIZE); + if (written < 0 || written != bufLen) { r = -EIO; break; } diff --git a/lib/utils.c b/lib/utils.c index 84519ac..af17f8f 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -128,7 +128,7 @@ int sector_size_for_device(const char *device) return r; } -ssize_t write_blockwise(int fd, const void *orig_buf, size_t count) +ssize_t write_blockwise(int fd, void *orig_buf, size_t count) { void *hangover_buf, *hangover_buf_base = NULL; void *buf, *buf_base = NULL; @@ -148,7 +148,7 @@ ssize_t write_blockwise(int fd, const void *orig_buf, size_t count) goto out; memcpy(buf, orig_buf, count); } else - buf = (void *)orig_buf; + buf = orig_buf; r = write(fd, buf, solid); if (r < 0 || r != solid) @@ -160,26 +160,28 @@ ssize_t write_blockwise(int fd, const void *orig_buf, size_t count) goto out; r = read(fd, hangover_buf, bsize); - if(r < 0 || r != bsize) goto out; + if (r < 0 || r != bsize) + goto out; r = lseek(fd, -bsize, SEEK_CUR); if (r < 0) goto out; - memcpy(hangover_buf, buf + solid, hangover); + memcpy(hangover_buf, (char*)buf + solid, hangover); r = write(fd, hangover_buf, bsize); - if(r < 0 || r != bsize) goto out; - free(hangover_buf_base); + if (r < 0 || r != bsize) + goto out; } ret = count; - out: +out: + free(hangover_buf_base); if (buf != orig_buf) free(buf_base); return ret; } ssize_t read_blockwise(int fd, void *orig_buf, size_t count) { - void *hangover_buf, *hangover_buf_base; + void *hangover_buf, *hangover_buf_base = NULL; void *buf, *buf_base = NULL; int r, hangover, solid, bsize, alignment; ssize_t ret = -1; @@ -210,11 +212,11 @@ ssize_t read_blockwise(int fd, void *orig_buf, size_t count) { if (r < 0 || r != bsize) goto out; - memcpy(buf + solid, hangover_buf, hangover); - free(hangover_buf_base); + memcpy((char *)buf + solid, hangover_buf, hangover); } ret = count; - out: +out: + free(hangover_buf_base); if (buf != orig_buf) { memcpy(orig_buf, buf, count); free(buf_base); @@ -222,41 +224,61 @@ ssize_t read_blockwise(int fd, void *orig_buf, size_t count) { return ret; } -/* +/* * Combines llseek with blockwise write. write_blockwise can already deal with short writes * but we also need a function to deal with short writes at the start. But this information - * is implicitly included in the read/write offset, which can not be set to non-aligned + * is implicitly included in the read/write offset, which can not be set to non-aligned * boundaries. Hence, we combine llseek with write. */ +ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) { + char *frontPadBuf; + void *frontPadBuf_base = NULL; + int r, bsize, frontHang; + size_t innerCount = 0; + ssize_t ret = -1; -ssize_t write_lseek_blockwise(int fd, const char *buf, size_t count, off_t offset) { - int bsize = sector_size(fd); - const char *orig_buf = buf; - char frontPadBuf[bsize]; - int frontHang = offset % bsize; - int r; - int innerCount = count < bsize ? count : bsize; - - if (bsize < 0) + if ((bsize = sector_size(fd)) < 0) return bsize; - lseek(fd, offset - frontHang, SEEK_SET); - if(offset % bsize) { - r = read(fd,frontPadBuf,bsize); - if(r < 0) return -1; + frontHang = offset % bsize; + + if (lseek(fd, offset - frontHang, SEEK_SET) < 0) + goto out; + + if (frontHang) { + frontPadBuf = aligned_malloc(&frontPadBuf_base, + bsize, get_alignment(fd)); + if (!frontPadBuf) + goto out; + + r = read(fd, frontPadBuf, bsize); + if (r < 0 || r != bsize) + goto out; + + innerCount = bsize - frontHang; + if (innerCount > count) + innerCount = count; - memcpy(frontPadBuf+frontHang, buf, innerCount); + memcpy(frontPadBuf + frontHang, buf, innerCount); - lseek(fd, offset - frontHang, SEEK_SET); - r = write(fd,frontPadBuf,bsize); - if(r < 0) return -1; + if (lseek(fd, offset - frontHang, SEEK_SET) < 0) + goto out; + + r = write(fd, frontPadBuf, bsize); + if (r < 0 || r != bsize) + goto out; buf += innerCount; count -= innerCount; } - if(count <= 0) return buf - orig_buf; - return write_blockwise(fd, buf, count) + innerCount; + ret = count ? write_blockwise(fd, buf, count) : 0; + if (ret >= 0) + ret += innerCount; +out: + free(frontPadBuf_base); + + return ret; } int device_ready(struct crypt_device *cd, const char *device, int mode) -- 2.7.4