]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: fix invalid inode pointer dereferences during log replay
authorFilipe Manana <fdmanana@suse.com>
Tue, 3 Jun 2025 18:29:01 +0000 (19:29 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 19 Jun 2025 13:20:42 +0000 (15:20 +0200)
In a few places where we call read_one_inode(), if we get a NULL pointer
we end up jumping into an error path, or fallthrough in case of
__add_inode_ref(), where we then do something like this:

   iput(&inode->vfs_inode);

which results in an invalid inode pointer that triggers an invalid memory
access, resulting in a crash.

Fix this by making sure we don't do such dereferences.

Fixes: b4c50cbb01a1 ("btrfs: return a btrfs_inode from read_one_inode()")
CC: stable@vger.kernel.org # 6.15+
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/tree-log.c

index 97e933113b822fbe24af545efeddc7fe27a1c9a8..21d2f3dded513b4ae8864a0a124dcd0d361a5d8c 100644 (file)
@@ -668,15 +668,12 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                extent_end = ALIGN(start + size,
                                   fs_info->sectorsize);
        } else {
-               ret = 0;
-               goto out;
+               return 0;
        }
 
        inode = read_one_inode(root, key->objectid);
-       if (!inode) {
-               ret = -EIO;
-               goto out;
-       }
+       if (!inode)
+               return -EIO;
 
        /*
         * first check to see if we already have this extent in the
@@ -961,7 +958,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
        ret = unlink_inode_for_log_replay(trans, dir, inode, &name);
 out:
        kfree(name.name);
-       iput(&inode->vfs_inode);
+       if (inode)
+               iput(&inode->vfs_inode);
        return ret;
 }
 
@@ -1176,8 +1174,8 @@ again:
                                        ret = unlink_inode_for_log_replay(trans,
                                                        victim_parent,
                                                        inode, &victim_name);
+                                       iput(&victim_parent->vfs_inode);
                                }
-                               iput(&victim_parent->vfs_inode);
                                kfree(victim_name.name);
                                if (ret)
                                        return ret;