aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2014-08-28 11:09:31 -0400
committerMike Snitzer <snitzer@redhat.com>2014-08-28 14:24:09 -0400
commitd49ec52ff6ddcda178fc2476a109cf1bd1fa19ed (patch)
tree789fa01103e1afc9d7a565e57f1e24eaf18db718 /drivers/md
parent52addcf9d6669fa439387610bc65c92fa0980cef (diff)
dm crypt: fix access beyond the end of allocated space
The DM crypt target accesses memory beyond allocated space resulting in a crash on 32 bit x86 systems. This bug is very old (it dates back to 2.6.25 commit 3a7f6c990ad04 "dm crypt: use async crypto"). However, this bug was masked by the fact that kmalloc rounds the size up to the next power of two. This bug wasn't exposed until 3.17-rc1 commit 298a9fa08a ("dm crypt: use per-bio data"). By switching to using per-bio data there was no longer any padding beyond the end of a dm-crypt allocated memory block. To minimize allocation overhead dm-crypt puts several structures into one block allocated with kmalloc. The block holds struct ablkcipher_request, cipher-specific scratch pad (crypto_ablkcipher_reqsize(any_tfm(cc))), struct dm_crypt_request and an initialization vector. The variable dmreq_start is set to offset of struct dm_crypt_request within this memory block. dm-crypt allocates the block with this size: cc->dmreq_start + sizeof(struct dm_crypt_request) + cc->iv_size. When accessing the initialization vector, dm-crypt uses the function iv_of_dmreq, which performs this calculation: ALIGN((unsigned long)(dmreq + 1), crypto_ablkcipher_alignmask(any_tfm(cc)) + 1). dm-crypt allocated "cc->iv_size" bytes beyond the end of dm_crypt_request structure. However, when dm-crypt accesses the initialization vector, it takes a pointer to the end of dm_crypt_request, aligns it, and then uses it as the initialization vector. If the end of dm_crypt_request is not aligned on a crypto_ablkcipher_alignmask(any_tfm(cc)) boundary the alignment causes the initialization vector to point beyond the allocated space. Fix this bug by calculating the variable iv_size_padding and adding it to the allocated size. Also correct the alignment of dm_crypt_request. struct dm_crypt_request is specific to dm-crypt (it isn't used by the crypto subsystem at all), so it is aligned on __alignof__(struct dm_crypt_request). Also align per_bio_data_size on ARCH_KMALLOC_MINALIGN, so that it is aligned as if the block was allocated with kmalloc. Reported-by: Krzysztof Kolasa <kkolasa@winsoft.pl> Tested-by: Milan Broz <gmazyland@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-crypt.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 2785007e0e46..cd15e0801228 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1688,6 +1688,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1688 unsigned int key_size, opt_params; 1688 unsigned int key_size, opt_params;
1689 unsigned long long tmpll; 1689 unsigned long long tmpll;
1690 int ret; 1690 int ret;
1691 size_t iv_size_padding;
1691 struct dm_arg_set as; 1692 struct dm_arg_set as;
1692 const char *opt_string; 1693 const char *opt_string;
1693 char dummy; 1694 char dummy;
@@ -1724,20 +1725,32 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1724 1725
1725 cc->dmreq_start = sizeof(struct ablkcipher_request); 1726 cc->dmreq_start = sizeof(struct ablkcipher_request);
1726 cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc)); 1727 cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
1727 cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment()); 1728 cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
1728 cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) & 1729
1729 ~(crypto_tfm_ctx_alignment() - 1); 1730 if (crypto_ablkcipher_alignmask(any_tfm(cc)) < CRYPTO_MINALIGN) {
1731 /* Allocate the padding exactly */
1732 iv_size_padding = -(cc->dmreq_start + sizeof(struct dm_crypt_request))
1733 & crypto_ablkcipher_alignmask(any_tfm(cc));
1734 } else {
1735 /*
1736 * If the cipher requires greater alignment than kmalloc
1737 * alignment, we don't know the exact position of the
1738 * initialization vector. We must assume worst case.
1739 */
1740 iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
1741 }
1730 1742
1731 cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start + 1743 cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
1732 sizeof(struct dm_crypt_request) + cc->iv_size); 1744 sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size);
1733 if (!cc->req_pool) { 1745 if (!cc->req_pool) {
1734 ti->error = "Cannot allocate crypt request mempool"; 1746 ti->error = "Cannot allocate crypt request mempool";
1735 goto bad; 1747 goto bad;
1736 } 1748 }
1737 1749
1738 cc->per_bio_data_size = ti->per_bio_data_size = 1750 cc->per_bio_data_size = ti->per_bio_data_size =
1739 sizeof(struct dm_crypt_io) + cc->dmreq_start + 1751 ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start +
1740 sizeof(struct dm_crypt_request) + cc->iv_size; 1752 sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size,
1753 ARCH_KMALLOC_MINALIGN);
1741 1754
1742 cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); 1755 cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
1743 if (!cc->page_pool) { 1756 if (!cc->page_pool) {