Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fat: avoid parent link count underflow in rmdir

Corrupted FAT images can leave a directory inode with an incorrect
i_nlink (e.g. 2 even though subdirectories exist). rmdir then
unconditionally calls drop_nlink(dir) and can drive i_nlink to 0,
triggering the WARN_ON in drop_nlink().

Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the
parent link count when it is at least 3, otherwise report a filesystem
error.

Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com
Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink")
Signed-off-by: Zhiyu Zhang <zhiyuzhang999@gmail.com>
Reported-by: Zhiyu Zhang <zhiyuzhang999@gmail.com>
Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t
Tested-by: Zhiyu Zhang <zhiyuzhang999@gmail.com>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Zhiyu Zhang and committed by
Andrew Morton
8cafcb88 25929dae

+12 -2
+6 -1
fs/fat/namei_msdos.c
··· 325 325 err = fat_remove_entries(dir, &sinfo); /* and releases bh */ 326 326 if (err) 327 327 goto out; 328 - drop_nlink(dir); 328 + if (dir->i_nlink >= 3) 329 + drop_nlink(dir); 330 + else { 331 + fat_fs_error(sb, "parent dir link count too low (%u)", 332 + dir->i_nlink); 333 + } 329 334 330 335 clear_nlink(inode); 331 336 fat_truncate_time(inode, NULL, S_CTIME);
+6 -1
fs/fat/namei_vfat.c
··· 804 804 err = fat_remove_entries(dir, &sinfo); /* and releases bh */ 805 805 if (err) 806 806 goto out; 807 - drop_nlink(dir); 807 + if (dir->i_nlink >= 3) 808 + drop_nlink(dir); 809 + else { 810 + fat_fs_error(sb, "parent dir link count too low (%u)", 811 + dir->i_nlink); 812 + } 808 813 809 814 clear_nlink(inode); 810 815 fat_truncate_time(inode, NULL, S_ATIME|S_MTIME);