[PATCH] nilfs: check filetype/uid/gid at nilfs_read_inode_common()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



syzbot is reporting lockdep warning followed by NULL pointer dereference
at nilfs_bmap_lookup_at_level() [1], for a crafted filesystem which
contains raw_inode->i_mode == 0 is poisoning checkpoint inode at
nilfs_read_inode_common() from nilfs_ifile_read() from
nilfs_attach_checkpoint() from nilfs_fill_super() from nilfs_mount().
Check that filetype/uid/gid are valid as well as i_nlink is valid.

Link: https://syzkaller.appspot.com/bug?extid=2b32eb36c1a825b7a74c [1]
Reported-by: syzot <syzbot+2b32eb36c1a825b7a74c@xxxxxxxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
---
This patch solves crash but I don't know whether this patch is correct.

Commit 05fe58fdc10df9eb ("nilfs2: inode operations") did

+       if (inode->i_nlink == 0 && (inode->i_mode == 0 || ii->i_dtime))

and commit 612392307cb09e49 ("nilfs2: support nanosecond timestamp") did

-       if (inode->i_nlink == 0 && (inode->i_mode == 0 || ii->i_dtime))
+       if (inode->i_nlink == 0 && inode->i_mode == 0)

and commit 705304a863cc4158 ("nilfs2: fix the nilfs_iget() vs. nilfs_new_inode() races") did


-       if (inode->i_nlink == 0 && inode->i_mode == 0)
+       if (inode->i_nlink == 0)

but I don't know which commit was wrong. Is inode->i_mode == 0 valid in nilfs?

 fs/nilfs2/inode.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 67f63cfeade5..798efd879642 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -442,6 +442,20 @@ int nilfs_read_inode_common(struct inode *inode,
 	inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
 	if (inode->i_nlink == 0)
 		return -ESTALE; /* this inode is deleted */
+	switch (inode->i_mode & S_IFMT) {
+	case S_IFLNK:
+	case S_IFREG:
+	case S_IFDIR:
+	case S_IFCHR:
+	case S_IFBLK:
+	case S_IFIFO:
+	case S_IFSOCK:
+		break;
+	default:
+		return -EINVAL; /* Filetype is invalid */
+	}
+	if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+		return -EINVAL; /* UID/GID is invalid */
 
 	inode->i_blocks = le64_to_cpu(raw_inode->i_blocks);
 	ii->i_flags = le32_to_cpu(raw_inode->i_flags);
-- 
2.34.1




[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux