[PATCH] Add a read memory barrier to wait_on_buffer

From: Mikulas Patocka
Date: Sun Jul 31 2022 - 07:43:54 EST


Let's have a look at this piece of code in __bread_slow:
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ, 0, bh);
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
Neither wait_on_buffer nor buffer_uptodate contain a memory barrier.
Consequently, if someone calls sb_bread and then reads the buffer data,
the read of buffer data may be speculatively executed before
wait_on_buffer(bh) and it may return invalid data.

Also, there is this pattern present several times:
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
err = -EIO;
It may be possible that buffer_uptodate is executed before wait_on_buffer
and it may return spurious error.

Fix these bugs by adding a read memory barrier to wait_on_buffer().

Signed-off-by: Mikulas Patocka <mpatocka@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx

Index: linux-2.6/include/linux/buffer_head.h
===================================================================
--- linux-2.6.orig/include/linux/buffer_head.h
+++ linux-2.6/include/linux/buffer_head.h
@@ -353,6 +353,11 @@ static inline void wait_on_buffer(struct
might_sleep();
if (buffer_locked(bh))
__wait_on_buffer(bh);
+ /*
+ * Make sure that the following accesses to buffer state or buffer data
+ * are not reordered with buffer_locked(bh).
+ */
+ smp_rmb();
}

static inline int trylock_buffer(struct buffer_head *bh)