]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: Fix possible UAF in mark_buffer_write_io_error()
authorJan Kara <jack@suse.cz>
Mon, 27 Jul 2026 10:49:20 +0000 (12:49 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 27 Jul 2026 14:25:31 +0000 (16:25 +0200)
When filesystem is freeing inode it calls mmb_invalidate() which removes
bhs from inode's metadata bh tracking and clears b_mmb for them. However
if the inode is getting deleted, we don't bother with calling mmb_sync()
before and thus these buffers can be under IO and we can be racing with
IO completion handler calling mark_buffer_write_io_error(). This race
can lead to mark_buffer_write_io_error() either hitting NULL pointer
reference or trying to operate on already freed inode. Protect the
mapping handling with RCU to make sure mmb and inode aren't freed before
we are done with them.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-22-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
fs/buffer.c

index 9af5f061a1f85af93055cbbe01e31fcecb035d34..daaa6614a6d63c9aff2a40700937044efa63d7b3 100644 (file)
@@ -1123,12 +1123,18 @@ EXPORT_SYMBOL(mark_buffer_dirty);
 
 void mark_buffer_write_io_error(struct buffer_head *bh)
 {
+       struct mapping_metadata_bhs *mmb;
+
        set_buffer_write_io_error(bh);
        /* FIXME: do we need to set this in both places? */
        if (bh->b_folio && bh->b_folio->mapping)
                mapping_set_error(bh->b_folio->mapping, -EIO);
-       if (bh->b_mmb)
-               mapping_set_error(bh->b_mmb->mapping, -EIO);
+       /* Protect us from mmb & inode getting freed while we work on it */
+       rcu_read_lock();
+       mmb = READ_ONCE(bh->b_mmb);
+       if (mmb)
+               mapping_set_error(mmb->mapping, -EIO);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL(mark_buffer_write_io_error);