CVE-2024-45003
Publication date:
04/09/2024
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
vfs: Don&#39;t evict inode under the inode lru traversing context<br />
<br />
The inode reclaiming process(See function prune_icache_sb) collects all<br />
reclaimable inodes and mark them with I_FREEING flag at first, at that<br />
time, other processes will be stuck if they try getting these inodes<br />
(See function find_inode_fast), then the reclaiming process destroy the<br />
inodes by function dispose_list(). Some filesystems(eg. ext4 with<br />
ea_inode feature, ubifs with xattr) may do inode lookup in the inode<br />
evicting callback function, if the inode lookup is operated under the<br />
inode lru traversing context, deadlock problems may happen.<br />
<br />
Case 1: In function ext4_evict_inode(), the ea inode lookup could happen<br />
if ea_inode feature is enabled, the lookup process will be stuck<br />
under the evicting context like this:<br />
<br />
1. File A has inode i_reg and an ea inode i_ea<br />
2. getfattr(A, xattr_buf) // i_ea is added into lru // lru->i_ea<br />
3. Then, following three processes running like this:<br />
<br />
PA PB<br />
echo 2 > /proc/sys/vm/drop_caches<br />
shrink_slab<br />
prune_dcache_sb<br />
// i_reg is added into lru, lru->i_ea->i_reg<br />
prune_icache_sb<br />
list_lru_walk_one<br />
inode_lru_isolate<br />
i_ea->i_state |= I_FREEING // set inode state<br />
inode_lru_isolate<br />
__iget(i_reg)<br />
spin_unlock(&i_reg->i_lock)<br />
spin_unlock(lru_lock)<br />
rm file A<br />
i_reg->nlink = 0<br />
iput(i_reg) // i_reg->nlink is 0, do evict<br />
ext4_evict_inode<br />
ext4_xattr_delete_inode<br />
ext4_xattr_inode_dec_ref_all<br />
ext4_xattr_inode_iget<br />
ext4_iget(i_ea->i_ino)<br />
iget_locked<br />
find_inode_fast<br />
__wait_on_freeing_inode(i_ea) ----→ AA deadlock<br />
dispose_list // cannot be executed by prune_icache_sb<br />
wake_up_bit(&i_ea->i_state)<br />
<br />
Case 2: In deleted inode writing function ubifs_jnl_write_inode(), file<br />
deleting process holds BASEHD&#39;s wbuf->io_mutex while getting the<br />
xattr inode, which could race with inode reclaiming process(The<br />
reclaiming process could try locking BASEHD&#39;s wbuf->io_mutex in<br />
inode evicting function), then an ABBA deadlock problem would<br />
happen as following:<br />
<br />
1. File A has inode ia and a xattr(with inode ixa), regular file B has<br />
inode ib and a xattr.<br />
2. getfattr(A, xattr_buf) // ixa is added into lru // lru->ixa<br />
3. Then, following three processes running like this:<br />
<br />
PA PB PC<br />
echo 2 > /proc/sys/vm/drop_caches<br />
shrink_slab<br />
prune_dcache_sb<br />
// ib and ia are added into lru, lru->ixa->ib->ia<br />
prune_icache_sb<br />
list_lru_walk_one<br />
inode_lru_isolate<br />
ixa->i_state |= I_FREEING // set inode state<br />
inode_lru_isolate<br />
__iget(ib)<br />
spin_unlock(&ib->i_lock)<br />
spin_unlock(lru_lock)<br />
rm file B<br />
ib->nlink = 0<br />
rm file A<br />
iput(ia)<br />
ubifs_evict_inode(ia)<br />
ubifs_jnl_delete_inode(ia)<br />
ubifs_jnl_write_inode(ia)<br />
make_reservation(BASEHD) // Lock wbuf->io_mutex<br />
ubifs_iget(ixa->i_ino)<br />
iget_locked<br />
find_inode_fast<br />
__wait_on_freeing_inode(ixa)<br />
| iput(ib) // ib->nlink is 0, do evict<br />
| ubifs_evict_inode<br />
| ubifs_jnl_delete_inode(ib)<br />
↓ ubifs_jnl_write_inode<br />
ABBA deadlock ←-----make_reservation(BASEHD)<br />
dispose_list // cannot be executed by prune_icache_sb<br />
wake_up_bit(&ixa->i_state)<br />
<br />
Fix the possible deadlock by using new inode state flag I_LRU_ISOLATING<br />
to pin the inode in memory while inode_lru_isolate(<br />
---truncated---
Severity CVSS v4.0: Pending analysis
Last modification:
03/11/2025