Skip to content

Commit a438402

Browse files
committed
Merge: CVE-2024-47679: vfs: fix race between evice_inodes() and find_inode()&iput()
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/5468 JIRA: https://issues.redhat.com/browse/RHEL-63193 CVE: CVE-2024-47679 ``` vfs: fix race between evice_inodes() and find_inode()&iput() Hi, all Recently I noticed a bug[1] in btrfs, after digged it into and I believe it'a race in vfs. Let's assume there's a inode (ie ino 261) with i_count 1 is called by iput(), and there's a concurrent thread calling generic_shutdown_super(). cpu0: cpu1: iput() // i_count is 1 ->spin_lock(inode) ->dec i_count to 0 ->iput_final() generic_shutdown_super() ->__inode_add_lru() ->evict_inodes() // cause some reason[2] ->if (atomic_read(inode->i_count)) continue; // return before // inode 261 passed the above check // list_lru_add_obj() // and then schedule out ->spin_unlock() // note here: the inode 261 // was still at sb list and hash list, // and I_FREEING|I_WILL_FREE was not been set btrfs_iget() // after some function calls ->find_inode() // found the above inode 261 ->spin_lock(inode) // check I_FREEING|I_WILL_FREE // and passed ->__iget() ->spin_unlock(inode) // schedule back ->spin_lock(inode) // check (I_NEW|I_FREEING|I_WILL_FREE) flags, // passed and set I_FREEING iput() ->spin_unlock(inode) ->spin_lock(inode) ->evict() // dec i_count to 0 ->iput_final() ->spin_unlock() ->evict() Now, we have two threads simultaneously evicting the same inode, which may trigger the BUG(inode->i_state & I_CLEAR) statement both within clear_inode() and iput(). To fix the bug, recheck the inode->i_count after holding i_lock. Because in the most scenarios, the first check is valid, and the overhead of spin_lock() can be reduced. If there is any misunderstanding, please let me know, thanks. [1]: https://lore.kernel.org/linux-btrfs/[email protected]/ [2]: The reason might be 1. SB_ACTIVE was removed or 2. mapping_shrinkable() return false when I reproduced the bug. Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=67ba3c42bcbb4665d3ad CC: [email protected] Fixes: 63997e9 ("split invalidate_inodes()") Signed-off-by: Julian Sun <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Jan Kara <[email protected]> Signed-off-by: Christian Brauner <[email protected]> (cherry picked from commit 88b1afb) ``` Signed-off-by: CKI Backport Bot <[email protected]> --- <small>Created 2024-10-21 13:27 UTC by backporter - [KWF FAQ](https://red.ht/kernel_workflow_doc) - [Slack #team-kernel-workflow](https://redhat-internal.slack.com/archives/C04LRUPMJQ5) - [Source](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/webhook/utils/backporter.py) - [Documentation](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/docs/README.backporter.md) - [Report an issue](https://gitlab.com/cki-project/kernel-workflow/-/issues/new?issue%5Btitle%5D=backporter%20webhook%20issue)</small> Approved-by: Pavel Reichl <[email protected]> Approved-by: Andrey Albershteyn <[email protected]> Approved-by: CKI KWF Bot <[email protected]> Merged-by: Augusto Caringi <[email protected]>
2 parents 73c1699 + 991d40c commit a438402

File tree

1 file changed

+4
-0
lines changed

1 file changed

+4
-0
lines changed

fs/inode.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,10 @@ void evict_inodes(struct super_block *sb)
728728
continue;
729729

730730
spin_lock(&inode->i_lock);
731+
if (atomic_read(&inode->i_count)) {
732+
spin_unlock(&inode->i_lock);
733+
continue;
734+
}
731735
if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
732736
spin_unlock(&inode->i_lock);
733737
continue;

0 commit comments

Comments
 (0)