git: ced217282230 - main - Add more accurate check for root inode

From: Fedor Uporov <fsu_at_FreeBSD.org>
Date: Thu, 30 Dec 2021 06:15:19 UTC
The branch main has been updated by fsu:

URL: https://cgit.FreeBSD.org/src/commit/?id=ced21728223016429242d1f7cd5e8a160c8a88cb

commit ced21728223016429242d1f7cd5e8a160c8a88cb
Author:     Fedor Uporov <fsu@FreeBSD.org>
AuthorDate: 2021-12-24 14:11:25 +0000
Commit:     Fedor Uporov <fsu@FreeBSD.org>
CommitDate: 2021-12-30 06:14:45 +0000

    Add more accurate check for root inode
    
    Check that root inode has links and is directory.
    
    PR:             259105
    Reported by:    Robert Morris
    MFC after:      2 weeks
---
 sys/fs/ext2fs/ext2_inode_cnv.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c
index 181ea3e04622..445000c509db 100644
--- a/sys/fs/ext2fs/ext2_inode_cnv.c
+++ b/sys/fs/ext2fs/ext2_inode_cnv.c
@@ -157,9 +157,17 @@ ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip)
 		return (EINVAL);
 	}
 
+	/*
+	 * Godmar thinks - if the link count is zero, then the inode is
+	 * unused - according to ext2 standards. Ufs marks this fact by
+	 * setting i_mode to zero - why ? I can see that this might lead to
+	 * problems in an undelete.
+	 */
 	ip->i_nlink = le16toh(ei->e2di_nlink);
-	if (ip->i_number == EXT2_ROOTINO && ip->i_nlink == 0) {
-		SDT_PROBE2(ext2fs, , trace, inode_cnv, 1, "root inode unallocated");
+	ip->i_mode = ip->i_nlink ? le16toh(ei->e2di_mode) : 0;
+	if (ip->i_number == EXT2_ROOTINO &&
+	    (ip->i_nlink < 2 || !S_ISDIR(ip->i_mode))) {
+		SDT_PROBE2(ext2fs, , trace, inode_cnv, 1, "root inode invalid");
 		return (EINVAL);
 	}
 
@@ -174,13 +182,6 @@ ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip)
 		}
 	}
 
-	/*
-	 * Godmar thinks - if the link count is zero, then the inode is
-	 * unused - according to ext2 standards. Ufs marks this fact by
-	 * setting i_mode to zero - why ? I can see that this might lead to
-	 * problems in an undelete.
-	 */
-	ip->i_mode = ip->i_nlink ? le16toh(ei->e2di_mode) : 0;
 	ip->i_size = le32toh(ei->e2di_size);
 	if (S_ISREG(ip->i_mode))
 		ip->i_size |= (uint64_t)le32toh(ei->e2di_size_high) << 32;