aboutsummaryrefslogtreecommitdiffstats
path: root/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch
diff options
Diffstat (limited to 'queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch')
-rw-r--r--queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch54
1 files changed, 54 insertions, 0 deletions
diff --git a/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch b/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch
new file mode 100644
index 0000000000..a27a16bcdf
--- /dev/null
+++ b/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch
@@ -0,0 +1,54 @@
+From 5d075b4c9c1810fc58c42a4fa5292e74ba3f5c64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 19:02:58 -0400
+Subject: btrfs: fix use-after-free on inode when scanning root during em
+ shrinking
+
+[ Upstream commit 59f37036bb7ab3d554c24abc856aabca01126414 ]
+
+At btrfs_scan_root() we are accessing the inode's root (and fs_info) in a
+call to btrfs_fs_closing() after we have scheduled the inode for a delayed
+iput, and that can result in a use-after-free on the inode in case the
+cleaner kthread does the iput before we dereference the inode in the call
+to btrfs_fs_closing().
+
+Fix this by using the fs_info stored already in a local variable instead
+of doing inode->root->fs_info.
+
+Fixes: 102044384056 ("btrfs: make the extent map shrinker run asynchronously as a work queue job")
+CC: stable@vger.kernel.org # 6.13+
+Tested-by: Ivan Shapovalov <intelfx@intelfx.name>
+Link: https://lore.kernel.org/linux-btrfs/0414d690ac5680d0d77dfc930606cdc36e42e12f.camel@intelfx.name/
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_map.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
+index 93043edc8ff93..36af9aa9aab13 100644
+--- a/fs/btrfs/extent_map.c
++++ b/fs/btrfs/extent_map.c
+@@ -1250,6 +1250,7 @@ static struct btrfs_inode *find_first_inode_to_shrink(struct btrfs_root *root,
+
+ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx *ctx)
+ {
++ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_inode *inode;
+ long nr_dropped = 0;
+ u64 min_ino = ctx->last_ino + 1;
+@@ -1264,7 +1265,7 @@ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx
+ iput(&inode->vfs_inode);
+
+ if (ctx->scanned >= ctx->nr_to_scan ||
+- btrfs_fs_closing(inode->root->fs_info))
++ btrfs_fs_closing(fs_info))
+ break;
+
+ cond_resched();
+--
+2.39.5
+