bcachefs: fix invalid free in dio write path
turns out iterate_iovec() mutates __iov, we need to save our own copy Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev> Reported-by: Marcin Mirosław <marcin@mejor.pl>
This commit is contained in:
parent
fa014953f9
commit
f2eb8434e4
@ -216,11 +216,11 @@ struct dio_write {
|
|||||||
struct address_space *mapping;
|
struct address_space *mapping;
|
||||||
struct bch_inode_info *inode;
|
struct bch_inode_info *inode;
|
||||||
struct mm_struct *mm;
|
struct mm_struct *mm;
|
||||||
|
const struct iovec *iov;
|
||||||
unsigned loop:1,
|
unsigned loop:1,
|
||||||
extending:1,
|
extending:1,
|
||||||
sync:1,
|
sync:1,
|
||||||
flush:1,
|
flush:1;
|
||||||
free_iov:1;
|
|
||||||
struct quota_res quota_res;
|
struct quota_res quota_res;
|
||||||
u64 written;
|
u64 written;
|
||||||
|
|
||||||
@ -312,12 +312,10 @@ static noinline int bch2_dio_write_copy_iov(struct dio_write *dio)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (dio->iter.nr_segs > ARRAY_SIZE(dio->inline_vecs)) {
|
if (dio->iter.nr_segs > ARRAY_SIZE(dio->inline_vecs)) {
|
||||||
iov = kmalloc_array(dio->iter.nr_segs, sizeof(*iov),
|
dio->iov = iov = kmalloc_array(dio->iter.nr_segs, sizeof(*iov),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (unlikely(!iov))
|
if (unlikely(!iov))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dio->free_iov = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(iov, dio->iter.__iov, dio->iter.nr_segs * sizeof(*iov));
|
memcpy(iov, dio->iter.__iov, dio->iter.nr_segs * sizeof(*iov));
|
||||||
@ -381,8 +379,7 @@ static __always_inline long bch2_dio_write_done(struct dio_write *dio)
|
|||||||
|
|
||||||
bch2_pagecache_block_put(inode);
|
bch2_pagecache_block_put(inode);
|
||||||
|
|
||||||
if (dio->free_iov)
|
kfree(dio->iov);
|
||||||
kfree(dio->iter.__iov);
|
|
||||||
|
|
||||||
ret = dio->op.error ?: ((long) dio->written << 9);
|
ret = dio->op.error ?: ((long) dio->written << 9);
|
||||||
bio_put(&dio->op.wbio.bio);
|
bio_put(&dio->op.wbio.bio);
|
||||||
@ -626,11 +623,11 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
|
|||||||
dio->mapping = mapping;
|
dio->mapping = mapping;
|
||||||
dio->inode = inode;
|
dio->inode = inode;
|
||||||
dio->mm = current->mm;
|
dio->mm = current->mm;
|
||||||
|
dio->iov = NULL;
|
||||||
dio->loop = false;
|
dio->loop = false;
|
||||||
dio->extending = extending;
|
dio->extending = extending;
|
||||||
dio->sync = is_sync_kiocb(req) || extending;
|
dio->sync = is_sync_kiocb(req) || extending;
|
||||||
dio->flush = iocb_is_dsync(req) && !c->opts.journal_flush_disabled;
|
dio->flush = iocb_is_dsync(req) && !c->opts.journal_flush_disabled;
|
||||||
dio->free_iov = false;
|
|
||||||
dio->quota_res.sectors = 0;
|
dio->quota_res.sectors = 0;
|
||||||
dio->written = 0;
|
dio->written = 0;
|
||||||
dio->iter = *iter;
|
dio->iter = *iter;
|
||||||
|
Loading…
Reference in New Issue
Block a user