Commit 34b47e3d authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Fix UAF in bchfs_read()



Commit 3ba0240a fixed a bug in the read retry path in __bch2_read(),
and changed bchfs_read() to match - to avoid a landmine if
bch2_read_extent() ever starts returning transaction restarts.

But that was incorrect, because bchfs_read() doesn't use a separate
stack allocated bvec_iter, it uses the one in the rbio being submitted.

Add a comment explaining the issue, and revert the buggy change.

Fixes: 3ba0240a ("bcachefs: Fix silent short reads in data read retry path")
Reported-by: default avatar <syzbot+2deb10b8dc9aae6fab67@syzkaller.appspotmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 4a22a733
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -225,11 +225,26 @@ static void bchfs_read(struct btree_trans *trans,

		bch2_read_extent(trans, rbio, iter.pos,
				 data_btree, k, offset_into_extent, flags);
		swap(rbio->bio.bi_iter.bi_size, bytes);
		/*
		 * Careful there's a landmine here if bch2_read_extent() ever
		 * starts returning transaction restarts here.
		 *
		 * We've changed rbio->bi_iter.bi_size to be "bytes we can read
		 * from this extent" with the swap call, and we restore it
		 * below. That restore needs to come before checking for
		 * errors.
		 *
		 * But unlike __bch2_read(), we use the rbio bvec iter, not one
		 * on the stack, so we can't do the restore right after the
		 * bch2_read_extent() call: we don't own that iterator anymore
		 * if BCH_READ_last_fragment is set, since we may have submitted
		 * that rbio instead of cloning it.
		 */

		if (flags & BCH_READ_last_fragment)
			break;

		swap(rbio->bio.bi_iter.bi_size, bytes);
		bio_advance(&rbio->bio, bytes);
err:
		if (ret &&