From 7efb45f9685fd9292413f15ea1212f7077c4a35f Mon Sep 17 00:00:00 2001 From: Ahmet Eray Karadag Date: Wed, 3 Dec 2025 01:45:08 +0300 Subject: [PATCH] ocfs2: invalidate inode if i_mode is zero after block read A panic occurs in ocfs2_unlink due to WARN_ON(inode->i_nlink == 0) when handling a corrupted inode with i_mode=0 and i_nlink=0 in memory. This "zombie" inode is created because ocfs2_read_locked_inode proceeds even after ocfs2_validate_inode_block successfully validates a block that structurally looks okay (passes checksum, signature etc.) but contains semantically invalid data (specifically i_mode=0). The current validation function doesn't check for i_mode being zero. This results in an in-memory inode with i_mode=0 being added to the VFS cache, which later triggers the panic during unlink. Prevent this by adding an explicit check for (i_mode == 0, i_nlink == 0, non-orphan) within ocfs2_validate_inode_block. If the check is true, return -EFSCORRUPTED to signal corruption. This causes the caller (ocfs2_read_locked_inode) to invoke make_bad_inode(), correctly preventing the zombie inode from entering the cache. Link: https://lkml.kernel.org/r/20251202224507.53452-2-eraykrdg1@gmail.com Co-developed-by: Albin Babu Varghese Signed-off-by: Albin Babu Varghese Signed-off-by: Ahmet Eray Karadag Reported-by: syzbot+55c40ae8a0e5f3659f2b@syzkaller.appspotmail.com Fixes: https://syzkaller.appspot.com/bug?extid=55c40ae8a0e5f3659f2b Link: https://lore.kernel.org/all/20251022222752.46758-2-eraykrdg1@gmail.com/T/ Reviewed-by: Joseph Qi Cc: David Hunter Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Cc: Heming Zhao Signed-off-by: Andrew Morton --- fs/ocfs2/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 5986d90b007e..ae938fb7c521 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1461,6 +1461,14 @@ int ocfs2_validate_inode_block(struct super_block *sb, goto bail; } + if ((!di->i_links_count && !di->i_links_count_hi) || !di->i_mode) { + mlog(ML_ERROR, "Invalid dinode #%llu: " + "Corrupt state (nlink = %u or mode = %u) detected!\n", + (unsigned long long)bh->b_blocknr, + ocfs2_read_links_count(di), le16_to_cpu(di->i_mode)); + rc = -EFSCORRUPTED; + goto bail; + } /* * Errors after here are fatal. */ -- 2.47.3