Commit f2eb8434 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: fix invalid free in dio write path



turns out iterate_iovec() mutates __iov, we need to save our own copy

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
Reported-by: default avatarMarcin Mirosław <marcin@mejor.pl>
parent fa014953
Loading
Loading
Loading
Loading
+5 −8
Original line number Diff line number Diff line
@@ -216,11 +216,11 @@ struct dio_write {
	struct address_space		*mapping;
	struct bch_inode_info		*inode;
	struct mm_struct		*mm;
	const struct iovec		*iov;
	unsigned			loop:1,
					extending:1,
					sync:1,
					flush:1,
					free_iov:1;
					flush:1;
	struct quota_res		quota_res;
	u64				written;

@@ -312,12 +312,10 @@ static noinline int bch2_dio_write_copy_iov(struct dio_write *dio)
		return -1;

	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);
		if (unlikely(!iov))
			return -ENOMEM;

		dio->free_iov = true;
	}

	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);

	if (dio->free_iov)
		kfree(dio->iter.__iov);
	kfree(dio->iov);

	ret = dio->op.error ?: ((long) dio->written << 9);
	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->inode		= inode;
	dio->mm			= current->mm;
	dio->iov		= NULL;
	dio->loop		= false;
	dio->extending		= extending;
	dio->sync		= is_sync_kiocb(req) || extending;
	dio->flush		= iocb_is_dsync(req) && !c->opts.journal_flush_disabled;
	dio->free_iov		= false;
	dio->quota_res.sectors	= 0;
	dio->written		= 0;
	dio->iter		= *iter;