[syzbot] [nilfs?] WARNING in nilfs_rmdir

38 views
Skip to first unread message

syzbot

unread,
Nov 20, 2024, 12:47:28 PM11/20/24
to konishi...@gmail.com, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot found the following issue on:

HEAD commit: bf9aa14fc523 Merge tag 'timers-core-2024-11-18' of git://g..
git tree: upstream
console+strace: https://syzkaller.appspot.com/x/log.txt?x=1093c6c0580000
kernel config: https://syzkaller.appspot.com/x/.config?x=ccd6152c3e2378ce
dashboard link: https://syzkaller.appspot.com/bug?extid=9260555647a5132edd48
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=1497e930580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=15f0bae8580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/f7f38a2c24fc/disk-bf9aa14f.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/9fe13f1c9a0f/vmlinux-bf9aa14f.xz
kernel image: https://storage.googleapis.com/syzbot-assets/04d354ff9f6b/bzImage-bf9aa14f.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/1605c6d5cd44/mount_0.gz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+926055...@syzkaller.appspotmail.com

NILFS (loop0): deleting nonexistent file (ino=11), 0
------------[ cut here ]------------
WARNING: CPU: 1 PID: 5833 at fs/inode.c:407 drop_nlink+0xc4/0x110 fs/inode.c:407
Modules linked in:
CPU: 1 UID: 0 PID: 5833 Comm: syz-executor181 Not tainted 6.12.0-syzkaller-01782-gbf9aa14fc523 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/30/2024
RIP: 0010:drop_nlink+0xc4/0x110 fs/inode.c:407
Code: bb 70 07 00 00 be 08 00 00 00 e8 07 df e5 ff f0 48 ff 83 70 07 00 00 5b 41 5c 41 5e 41 5f 5d c3 cc cc cc cc e8 6d f4 7e ff 90 <0f> 0b 90 eb 83 44 89 e1 80 e1 07 80 c1 03 38 c1 0f 8c 5c ff ff ff
RSP: 0018:ffffc90003e97c70 EFLAGS: 00010293
RAX: ffffffff8215f523 RBX: 1ffff1100ef7b1cc RCX: ffff888030afbc00
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffffffff8215f4a3 R09: 1ffff1100fb87cee
R10: dffffc0000000000 R11: ffffed100fb87cef R12: ffff888077bd8e60
R13: 1ffff1100ef7b030 R14: ffff888077bd8e18 R15: dffffc0000000000
FS: 0000555584ff0480(0000) GS:ffff8880b8700000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000000000045bdd0 CR3: 0000000074070000 CR4: 00000000003526f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
nilfs_rmdir+0x1b0/0x250 fs/nilfs2/namei.c:342
vfs_rmdir+0x3a3/0x510 fs/namei.c:4394
do_rmdir+0x3b5/0x580 fs/namei.c:4453
__do_sys_rmdir fs/namei.c:4472 [inline]
__se_sys_rmdir fs/namei.c:4470 [inline]
__x64_sys_rmdir+0x47/0x50 fs/namei.c:4470
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7febf80a8507
Code: 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 54 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffc733beac8 EFLAGS: 00000207 ORIG_RAX: 0000000000000054
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007febf80a8507
RDX: 0000000000008790 RSI: 0000000000000000 RDI: 00007ffc733bfc70
RBP: 0000000000000065 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000001000 R11: 0000000000000207 R12: 00007ffc733bfc70
R13: 0000555585001840 R14: 431bde82d7b634db R15: 00007ffc733c1df0
</TASK>


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzk...@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

Edward Adam Davis

unread,
Dec 4, 2024, 6:53:23 AM12/4/24
to syzbot+926055...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
#syz test: https://github.com/ea1davis/linux nilfs/syz_0163

syzbot

unread,
Dec 4, 2024, 7:13:04 AM12/4/24
to ead...@qq.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+926055...@syzkaller.appspotmail.com
Tested-by: syzbot+926055...@syzkaller.appspotmail.com

Tested on:

commit: 89e182ea nilfs2: Preventing dirty inode
git tree: https://github.com/ea1davis/linux nilfs/syz_0163
console output: https://syzkaller.appspot.com/x/log.txt?x=1035840f980000
kernel config: https://syzkaller.appspot.com/x/.config?x=35f1fa828fe386c2
dashboard link: https://syzkaller.appspot.com/bug?extid=9260555647a5132edd48
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40

Note: no patches were applied.
Note: testing is done by a robot and is best-effort only.

Edward Adam Davis

unread,
Dec 4, 2024, 8:42:14 AM12/4/24
to syzbot+926055...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
#syz test: https://github.com/ea1davis/linux nilfs/syz_0163_v2

syzbot

unread,
Dec 4, 2024, 9:04:08 AM12/4/24
to ead...@qq.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch but the reproducer is still triggering an issue:
lost connection to test machine



Tested on:

commit: 7a22f39b nilfs2: replace drop with clear for nlink
git tree: https://github.com/ea1davis/linux nilfs/syz_0163_v2
console output: https://syzkaller.appspot.com/x/log.txt?x=1629a330580000

Edward Adam Davis

unread,
Dec 5, 2024, 6:13:49 AM12/5/24
to syzbot+926055...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
#syz test: https://github.com/ea1davis/linux nilfs/syz_0163_v3

syzbot

unread,
Dec 5, 2024, 7:07:05 AM12/5/24
to ead...@qq.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+926055...@syzkaller.appspotmail.com
Tested-by: syzbot+926055...@syzkaller.appspotmail.com

Tested on:

commit: 22aa0501 nilfs2: drop the inode which has been removed
git tree: https://github.com/ea1davis/linux nilfs/syz_0163_v3
console output: https://syzkaller.appspot.com/x/log.txt?x=13a68020580000
kernel config: https://syzkaller.appspot.com/x/.config?x=35f1fa828fe386c2
dashboard link: https://syzkaller.appspot.com/bug?extid=9260555647a5132edd48
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40

Note: no patches were applied.

Edward Adam Davis

unread,
Dec 5, 2024, 7:26:49 AM12/5/24
to syzbot+926055...@syzkaller.appspotmail.com, konishi...@gmail.com, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzkall...@googlegroups.com
syzbot reported a WARNING in nilfs_rmdir. [1]

The inode is used twice by the same task to unmount and remove directories
".nilfs" and "file0", it trigger warning in nilfs_rmdir.

Avoid to this issue, check i_size and i_nlink in nilfs_iget(), if they are
both 0, it means that this inode has been removed, and iput is executed to
reclaim it.

[1]
WARNING: CPU: 1 PID: 5824 at fs/inode.c:407 drop_nlink+0xc4/0x110 fs/inode.c:407
Modules linked in:
CPU: 1 UID: 0 PID: 5824 Comm: syz-executor223 Not tainted 6.12.0-syzkaller-12113-gbcc8eda6d349 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024
RIP: 0010:drop_nlink+0xc4/0x110 fs/inode.c:407
Code: bb 70 07 00 00 be 08 00 00 00 e8 57 0b e6 ff f0 48 ff 83 70 07 00 00 5b 41 5c 41 5e 41 5f 5d c3 cc cc cc cc e8 9d 4c 7e ff 90 <0f> 0b 90 eb 83 44 89 e1 80 e1 07 80 c1 03 38 c1 0f 8c 5c ff ff ff
RSP: 0018:ffffc900037f7c70 EFLAGS: 00010293
RAX: ffffffff822124a3 RBX: 1ffff1100e7ae034 RCX: ffff88807cf53c00
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffffffff82212423 R09: 1ffff1100f8ba8ee
R10: dffffc0000000000 R11: ffffed100f8ba8ef R12: ffff888073d701a0
R13: 1ffff1100e79f5c4 R14: ffff888073d70158 R15: dffffc0000000000
FS: 0000555558d1e480(0000) GS:ffff8880b8700000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000555558d37878 CR3: 000000007d920000 CR4: 00000000003526f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
nilfs_rmdir+0x1b0/0x250 fs/nilfs2/namei.c:342
vfs_rmdir+0x3a3/0x510 fs/namei.c:4394
do_rmdir+0x3b5/0x580 fs/namei.c:4453
__do_sys_rmdir fs/namei.c:4472 [inline]
__se_sys_rmdir fs/namei.c:4470 [inline]
__x64_sys_rmdir+0x47/0x50 fs/namei.c:4470
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Reported-and-tested-by: syzbot+926055...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9260555647a5132edd48
Signed-off-by: Edward Adam Davis <ead...@qq.com>
---
fs/nilfs2/inode.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index cf9ba481ae37..254a5e46f8ea 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -544,8 +544,15 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
inode = nilfs_iget_locked(sb, root, ino);
if (unlikely(!inode))
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+
+ if (!(inode->i_state & I_NEW)) {
+ if (!inode->i_size && !inode->i_nlink) {
+ make_bad_inode(inode);
+ iput(inode);
+ return ERR_PTR(-EIO);
+ }
return inode;
+ }

err = __nilfs_read_inode(sb, root, ino, inode);
if (unlikely(err)) {
--
2.47.0

Ryusuke Konishi

unread,
Dec 5, 2024, 11:04:45 AM12/5/24
to Edward Adam Davis, syzbot+926055...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzkall...@googlegroups.com
Thank you Edward.

This fix seems good except for the i_size check, but I think we need
to look into what's going on a bit more.

I was unable to work for a while due to machine trouble, so I'd like
to know if you have made any progress on your investigation.

First, is this caused by a corrupted filesystem image? Or is it that
the directories or files with the same inode number were generated
during the namespace operations (due to a timing issue or something),
and could this problem occur even if the original filesystem image is
normal?

When I mounted the mount_0 image as read-only, the filesystem looked
normal without such inode duplication.

At least, nilfs_read_inode_common(), which reads inodes from block
devices, is implemented to return an error with -ESTALE if i_nlink ==
0. So it seems that nilfs_iget() picked up this inode with i_nlilnk
== 0 because it hit an inode being deleted in the inode cache. Why is
that happening?

Also, why do you put the i_size check as an AND condition?
i_size is independent of i_nlink and the inode lifecycles. If i_size
is also broken, this check will not work properly.
If something is not working and you have included it as a workaround,
I would like to know about it.

Thanks,
Ryusuke Konishi

Edward Adam Davis

unread,
Dec 6, 2024, 8:21:26 AM12/6/24
to konishi...@gmail.com, ead...@qq.com, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzbot+926055...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
According to the log when I reproduced the problem, I analyzed that the
problem occurred like this:

CPU0 CPU1
==== ====
nilfs_mkdir // file0
nilfs_new_inode // ino is 11
mount // mount file0
umount // .nilfs, ino is 11
nilfs_rmdir // ino is 11, i_size = 0, i_nlink = 0
umount // file0, ino is 11
nilfs_rmdir // ino 11, i_size = 0, i_nlink = 0, trigger warning

>
> When I mounted the mount_0 image as read-only, the filesystem looked
> normal without such inode duplication.
>
> At least, nilfs_read_inode_common(), which reads inodes from block
> devices, is implemented to return an error with -ESTALE if i_nlink ==
> 0. So it seems that nilfs_iget() picked up this inode with i_nlilnk
> == 0 because it hit an inode being deleted in the inode cache. Why is
> that happening?
Are you talking about the following call trace?
If so, then because the value of inode->i_state is I_DIRTY (set in nilfs_mkdir)
it will not enter __nilfs_read_inode().

nilfs_iget()->
__nilfs_read_inode()->
nilfs_read_inode_common()
>
> Also, why do you put the i_size check as an AND condition?
i_size will set to 0 in nilfs_rmdir(), so check it too.
> i_size is independent of i_nlink and the inode lifecycles. If i_size
> is also broken, this check will not work properly.
> If something is not working and you have included it as a workaround,
> I would like to know about it.

BR,
Edward

Ryusuke Konishi

unread,
Dec 7, 2024, 12:49:48 PM12/7/24
to Edward Adam Davis, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzbot+926055...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
Thank you for explaining the situation. I understand what's going on.

In the end, going back to my question, this is caused by file system corruption.
Because the inode bitmap is corrupted, an inode with an inode number
that should exist as a ".nilfs" file was reassigned by nilfs_mkdir for
"file0", causing an inode duplication during execution.
And this causes an underflow of i_nlink in rmdir operations.

After considering the issue, I came to the conclusion that although
there is an approach that strengthens checks for bitmap
inconsistencies and inode type inconsistencies to detect errors in
advance, these approaches are difficult to fundamentally solve.

This is caused by a corrupted inode bitmap, but checking is difficult
in the first place when there are multiple directories with the same
inode number in the name space.

Therefore, the appropriate solution is to either check for i_nlink
underflow during rmdir, or to detect i_nlink == 0 in the call path of
nilfs_lookup() --> nilfs_iget(), and I think the latter approach is
better, as you have chosen.

> >
> > When I mounted the mount_0 image as read-only, the filesystem looked
> > normal without such inode duplication.
> >
> > At least, nilfs_read_inode_common(), which reads inodes from block
> > devices, is implemented to return an error with -ESTALE if i_nlink ==
> > 0. So it seems that nilfs_iget() picked up this inode with i_nlilnk
> > == 0 because it hit an inode being deleted in the inode cache. Why is
> > that happening?
> Are you talking about the following call trace?
> If so, then because the value of inode->i_state is I_DIRTY (set in nilfs_mkdir)
> it will not enter __nilfs_read_inode().
>
> nilfs_iget()->
> __nilfs_read_inode()->
> nilfs_read_inode_common()

Yes, in this case __nifls_read_inode() is not called. As mentioned
above, the conclusion is that i_nlink abnormalities can occur in other
FS corruption patterns such as inode bitmap corruption and directory
inconsistency.

> >
> > Also, why do you put the i_size check as an AND condition?
> i_size will set to 0 in nilfs_rmdir(), so check it too.
> > i_size is independent of i_nlink and the inode lifecycles. If i_size
> > is also broken, this check will not work properly.
> > If something is not working and you have included it as a workaround,
> > I would like to know about it.

To fix the problem, please modify the patch as follows:

(1) In nilfs_iget(), if the inode without I_NEW obtained by
nilfs_iget_locked() has i_nlink == 0, call iput() and return
ERR_PTR(-ESTALE). Do not call make_bad_inode(). Also do not check for
i_size == 0 (it is not a good idea to check this to identify the case
of rmdir).

(2) In nilfs_lookup(), if the return value of nilfs_iget() is
ERR_PTR(-ESTALE), output a message with nilfs_error() indicating that
file system corruption has been detected , and returns ERR_PTR(-EIO).
Please refer to ext2_lookup() for the concrete implementation.

The reason for not calling make_bad_inode() is to prevent interference
from the side when i_nlink is set to 0 and nilfs_evict() is trying to
delete the inode. The VFS layer guarantees that inode acquisition and
evict are mutually exclusive, but it is possible to grab it before
evict(), and the result of interference in that case is unpredictable.
Instead, as mentioned above, I think it is safer to call nilfs_error()
at the nilfs_lookup() level, where namespace operations are involved.

Also, could you please explain in the commit log that inode
duplication has occurred due to file system corruption (in this case,
inode bitmap corruption), and that when inode duplication occurs due
to file system inconsistencies like this, a link count underflow can
occur during an rmdir operation, so that a link count check is
necessary at runtime?

Thank you in advance.

Ryusuke Konishi

Edward Adam Davis

unread,
Dec 7, 2024, 9:38:50 PM12/7/24
to syzbot+926055...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
#syz test: https://github.com/ea1davis/linux nilfs/syz_0163_v4

syzbot

unread,
Dec 7, 2024, 10:19:04 PM12/7/24
to ead...@qq.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+926055...@syzkaller.appspotmail.com
Tested-by: syzbot+926055...@syzkaller.appspotmail.com

Tested on:

commit: 9731d37c nilfs2: prevent use of deleted inode
git tree: https://github.com/ea1davis/linux nilfs/syz_0163_v4
console output: https://syzkaller.appspot.com/x/log.txt?x=10b0f330580000

Edward Adam Davis

unread,
Dec 7, 2024, 10:29:24 PM12/7/24
to konishi...@gmail.com, ead...@qq.com, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzbot+926055...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
syzbot reported a WARNING in nilfs_rmdir. [1]

Because the inode bitmap is corrupted, an inode with an inode number
that should exist as a ".nilfs" file was reassigned by nilfs_mkdir for
"file0", causing an inode duplication during execution.
And this causes an underflow of i_nlink in rmdir operations.

Avoid to this issue, check i_nlink in nilfs_iget(), if it is 0, it means
that this inode has been deleted, and iput is executed to reclaim it.
V1 -> V2: Adjust the patch as suggested by Ryusuke Konishi

fs/nilfs2/inode.c | 8 +++++++-
fs/nilfs2/namei.c | 6 ++++++
2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index cf9ba481ae37..b7d4105f37bf 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -544,8 +544,14 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
inode = nilfs_iget_locked(sb, root, ino);
if (unlikely(!inode))
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+
+ if (!(inode->i_state & I_NEW)) {
+ if (!inode->i_nlink) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
return inode;
+ }

err = __nilfs_read_inode(sb, root, ino, inode);
if (unlikely(err)) {
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 9b108052d9f7..7037f47c454f 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -67,6 +67,12 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
inode = NULL;
} else {
inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino);
+ if (inode == ERR_PTR(-ESTALE)) {
+ nilfs_error(dir->i_sb, __func__,
+ "deleted inode referenced: %lu",
+ (unsigned long) ino);
+ return ERR_PTR(-EIO);
+ }
}

return d_splice_alias(inode, dentry);
--
2.47.0

Ryusuke Konishi

unread,
Dec 7, 2024, 11:39:36 PM12/7/24
to Edward Adam Davis, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzbot+926055...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
I'll make a few comments.

> Reported-and-tested-by: syzbot+926055...@syzkaller.appspotmail.com

First please separate "Reported-and-tested-by" into two tags.
Although it is still seen occasionally, it causes warnings for the
checkpatch script. (It has already been explicitly deprecated in some
subtrees, because it just complicates automatic tag extraction.)
Unlink ext2_error(), nilfs_error() does not require __func__, to be
passed as an argument.
nilfs_error() is a wrapper macro for the actual error output function
__nilfs_error(), which hides __func__ there.
(I should have mentioned the difference, sorry.)

Another comment: "ino" is of type "ino_t", which is of type "unsigned
long", so the typecast to "unsigned long" for the argument "ino" is
not necessary.
I don't know why the ext2 implementation does it, but even if this
patch is backported to stable trees, this typecast is not necessary.

Thanks,
Ryusuke Konishi

Edward Adam Davis

unread,
Dec 8, 2024, 1:01:17 AM12/8/24
to konishi...@gmail.com, ead...@qq.com, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzbot+926055...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
syzbot reported a WARNING in nilfs_rmdir. [1]

Because the inode bitmap is corrupted, an inode with an inode number
that should exist as a ".nilfs" file was reassigned by nilfs_mkdir for
"file0", causing an inode duplication during execution.
And this causes an underflow of i_nlink in rmdir operations.

The inode is used twice by the same task to unmount and remove directories
".nilfs" and "file0", it trigger warning in nilfs_rmdir.

Reported-by: syzbot+926055...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9260555647a5132edd48
Tested-by: syzbot+926055...@syzkaller.appspotmail.com
Signed-off-by: Edward Adam Davis <ead...@qq.com>
---
V1 -> V2: Adjust the patch as suggested by Ryusuke Konishi
V2 -> V3: Modify the input parameters of nilfs_error and split Reported-and-tested_by

fs/nilfs2/inode.c | 8 +++++++-
fs/nilfs2/namei.c | 5 +++++
2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index cf9ba481ae37..b7d4105f37bf 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -544,8 +544,14 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
inode = nilfs_iget_locked(sb, root, ino);
if (unlikely(!inode))
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+
+ if (!(inode->i_state & I_NEW)) {
+ if (!inode->i_nlink) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
return inode;
+ }

err = __nilfs_read_inode(sb, root, ino, inode);
if (unlikely(err)) {
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 9b108052d9f7..1d836a5540f3 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -67,6 +67,11 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
inode = NULL;
} else {
inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino);
+ if (inode == ERR_PTR(-ESTALE)) {
+ nilfs_error(dir->i_sb,
+ "deleted inode referenced: %lu", ino);

Ryusuke Konishi

unread,
Dec 8, 2024, 2:35:31 AM12/8/24
to Edward Adam Davis, linux-...@vger.kernel.org, linux...@vger.kernel.org, syzbot+926055...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
Thank you for your help. I'll adopt this and send it upstream after
running tests that include more than just the reproducer.

Thanks,
Ryusuke Konishi

Ryusuke Konishi

unread,
Dec 9, 2024, 1:58:04 AM12/9/24
to Andrew Morton, linux-nilfs, syzbot, syzkall...@googlegroups.com, LKML, Edward Adam Davis
From: Edward Adam Davis <ead...@qq.com>

syzbot reported a WARNING in nilfs_rmdir. [1]

Because the inode bitmap is corrupted, an inode with an inode number
that should exist as a ".nilfs" file was reassigned by nilfs_mkdir for
"file0", causing an inode duplication during execution.
And this causes an underflow of i_nlink in rmdir operations.

The inode is used twice by the same task to unmount and remove directories
".nilfs" and "file0", it trigger warning in nilfs_rmdir.

Avoid to this issue, check i_nlink in nilfs_iget(), if it is 0, it means
that this inode has been deleted, and iput is executed to reclaim it.

[1]
WARNING: CPU: 1 PID: 5824 at fs/inode.c:407 drop_nlink+0xc4/0x110 fs/inode.c:407
...
Call Trace:
<TASK>
nilfs_rmdir+0x1b0/0x250 fs/nilfs2/namei.c:342
vfs_rmdir+0x3a3/0x510 fs/namei.c:4394
do_rmdir+0x3b5/0x580 fs/namei.c:4453
__do_sys_rmdir fs/namei.c:4472 [inline]
__se_sys_rmdir fs/namei.c:4470 [inline]
__x64_sys_rmdir+0x47/0x50 fs/namei.c:4470
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Fixes: d25006523d0b ("nilfs2: pathname operations")
Signed-off-by: Ryusuke Konishi <konishi...@gmail.com>
---
Hi Andrew, please apply this as a bug fix.

This prevents the link count underflow that can occur when deleting
directories in an inconsistent file system, which was recently
reported by syzbot.

Thanks,
Ryusuke Konishi

fs/nilfs2/inode.c | 8 +++++++-
fs/nilfs2/namei.c | 5 +++++
2 files changed, 12 insertions(+), 1 deletion(-)

2.43.0

Reply all
Reply to author
Forward
0 new messages