Commit 636d4eef authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix memory corruption in encryption path

When do_encrypt() was passed a vmalloc address and the buffer spanned
more than a single page, we were encrypting/decrypting completely
different pages than the ones intended.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent 0fbf71f8
...@@ -114,6 +114,7 @@ static inline int do_encrypt(struct crypto_sync_skcipher *tfm, ...@@ -114,6 +114,7 @@ static inline int do_encrypt(struct crypto_sync_skcipher *tfm,
struct nonce nonce, struct nonce nonce,
void *buf, size_t len) void *buf, size_t len)
{ {
if (!is_vmalloc_addr(buf)) {
struct scatterlist sg; struct scatterlist sg;
sg_init_table(&sg, 1); sg_init_table(&sg, 1);
...@@ -123,6 +124,31 @@ static inline int do_encrypt(struct crypto_sync_skcipher *tfm, ...@@ -123,6 +124,31 @@ static inline int do_encrypt(struct crypto_sync_skcipher *tfm,
: virt_to_page(buf), : virt_to_page(buf),
len, offset_in_page(buf)); len, offset_in_page(buf));
return do_encrypt_sg(tfm, nonce, &sg, len); return do_encrypt_sg(tfm, nonce, &sg, len);
} else {
unsigned pages = buf_pages(buf, len);
struct scatterlist *sg;
size_t orig_len = len;
int ret, i;
sg = kmalloc_array(sizeof(*sg), pages, GFP_KERNEL);
if (!sg)
return -ENOMEM;
sg_init_table(sg, pages);
for (i = 0; i < pages; i++) {
unsigned offset = offset_in_page(buf);
unsigned pg_len = min(len, PAGE_SIZE - offset);
sg_set_page(sg + i, vmalloc_to_page(buf), pg_len, offset);
buf += pg_len;
len -= pg_len;
}
ret = do_encrypt_sg(tfm, nonce, sg, orig_len);
kfree(sg);
return ret;
}
} }
int bch2_chacha_encrypt_key(struct bch_key *key, struct nonce nonce, int bch2_chacha_encrypt_key(struct bch_key *key, struct nonce nonce,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment