This is a note to let you know that I've just added the patch titled
Btrfs: fix use-after-free on root->orphan_block_rsv
to the 4.15-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: btrfs-fix-use-after-free-on-root-orphan_block_rsv.patch and it can be found in the queue-4.15 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From 1a932ef4e47984dee227834667b5ff5a334e4805 Mon Sep 17 00:00:00 2001
From: Liu Bo bo.li.liu@oracle.com Date: Thu, 25 Jan 2018 11:02:54 -0700 Subject: Btrfs: fix use-after-free on root->orphan_block_rsv
From: Liu Bo bo.li.liu@oracle.com
commit 1a932ef4e47984dee227834667b5ff5a334e4805 upstream.
I got these from running generic/475,
WARNING: CPU: 0 PID: 26384 at fs/btrfs/inode.c:3326 btrfs_orphan_commit_root+0x1ac/0x2b0 [btrfs] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 IP: btrfs_block_rsv_release+0x1c/0x70 [btrfs] Call Trace: btrfs_orphan_release_metadata+0x9f/0x200 [btrfs] btrfs_orphan_del+0x10d/0x170 [btrfs] btrfs_setattr+0x500/0x640 [btrfs] notify_change+0x7ae/0x870 do_truncate+0xca/0x130 vfs_truncate+0x2ee/0x3d0 do_sys_truncate+0xaf/0xf0 SyS_truncate+0xe/0x10 entry_SYSCALL_64_fastpath+0x1f/0x96
The race is between btrfs_orphan_commit_root and btrfs_orphan_del, t1 t2 btrfs_orphan_commit_root btrfs_orphan_del spin_lock check (&root->orphan_inodes) root->orphan_block_rsv = NULL; spin_unlock atomic_dec(&root->orphan_inodes); access root->orphan_block_rsv
Accessing root->orphan_block_rsv must be done before decreasing root->orphan_inodes.
cc: stable@vger.kernel.org v3.12+ Fixes: 703c88e03524 ("Btrfs: fix tracking of orphan inode count") Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: Josef Bacik jbacik@fb.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/btrfs/inode.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-)
--- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3369,6 +3369,11 @@ int btrfs_orphan_add(struct btrfs_trans_ ret = btrfs_orphan_reserve_metadata(trans, inode); ASSERT(!ret); if (ret) { + /* + * dec doesn't need spin_lock as ->orphan_block_rsv + * would be released only if ->orphan_inodes is + * zero. + */ atomic_dec(&root->orphan_inodes); clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, &inode->runtime_flags); @@ -3383,12 +3388,17 @@ int btrfs_orphan_add(struct btrfs_trans_ if (insert >= 1) { ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode)); if (ret) { - atomic_dec(&root->orphan_inodes); if (reserve) { clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, &inode->runtime_flags); btrfs_orphan_release_metadata(inode); } + /* + * btrfs_orphan_commit_root may race with us and set + * ->orphan_block_rsv to zero, in order to avoid that, + * decrease ->orphan_inodes after everything is done. + */ + atomic_dec(&root->orphan_inodes); if (ret != -EEXIST) { clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, &inode->runtime_flags); @@ -3420,28 +3430,26 @@ static int btrfs_orphan_del(struct btrfs { struct btrfs_root *root = inode->root; int delete_item = 0; - int release_rsv = 0; int ret = 0;
- spin_lock(&root->orphan_lock); if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, &inode->runtime_flags)) delete_item = 1;
+ if (delete_item && trans) + ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode)); + if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, &inode->runtime_flags)) - release_rsv = 1; - spin_unlock(&root->orphan_lock); + btrfs_orphan_release_metadata(inode);
- if (delete_item) { + /* + * btrfs_orphan_commit_root may race with us and set ->orphan_block_rsv + * to zero, in order to avoid that, decrease ->orphan_inodes after + * everything is done. + */ + if (delete_item) atomic_dec(&root->orphan_inodes); - if (trans) - ret = btrfs_del_orphan_item(trans, root, - btrfs_ino(inode)); - } - - if (release_rsv) - btrfs_orphan_release_metadata(inode);
return ret; }
Patches currently in stable-queue which might be from bo.li.liu@oracle.com are
queue-4.15/btrfs-fix-btrfs_evict_inode-to-handle-abnormal-inodes-correctly.patch queue-4.15/btrfs-fix-crash-due-to-not-cleaning-up-tree-log-block-s-dirty-bits.patch queue-4.15/btrfs-fix-use-after-free-on-root-orphan_block_rsv.patch queue-4.15/btrfs-fix-extent-state-leak-from-tree-log.patch queue-4.15/btrfs-fix-unexpected-eexist-when-creating-new-inode.patch queue-4.15/btrfs-fix-deadlock-in-run_delalloc_nocow.patch
linux-stable-mirror@lists.linaro.org