The branch stable/13 has been updated by mckusick:

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

commit fbfbd0638a5a3dd4f76eaf17f81450cc09d48e5b
Author:     Kirk McKusick <[email protected]>
AuthorDate: 2023-05-27 23:07:09 +0000
Commit:     Kirk McKusick <[email protected]>
CommitDate: 2023-06-07 22:44:12 +0000

    Fix a bug in fsck_ffs(8) triggered by corrupted filesystems.
    
    The last valid inode in the filesystem is maxino - 1, not maxino.
    Thus validity checks should ino < maxino, not ino <= maxino.
    
    Reported-by:  Robert Morris
    PR:           271312
    Sponsored-by: The FreeBSD Foundation
    
    (cherry picked from commit 11ce203e0535c1c8f520c9bda81ab9326cf5db80)
---
 sbin/fsck_ffs/dir.c    |  4 ++--
 sbin/fsck_ffs/fsutil.c |  2 +-
 sbin/fsck_ffs/inode.c  | 14 ++++++++------
 sbin/fsck_ffs/pass2.c  |  4 ++--
 4 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index e5f0e1e7e7f4..7ea471bcb30a 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -126,7 +126,7 @@ check_dirdepth(struct inoinfo *inp)
        if (inp->i_depth == 0 && updateasked == 0) {
                updateasked = 1;
                if (preen) {
-                       pwarn("UPDATING FILESYSTEM TO TRACK DIRECTORY DEPTH");
+                       pwarn("UPDATING FILESYSTEM TO TRACK DIRECTORY DEPTH\n");
                        dirdepthupdate = 1;
                } else {
                        /*
@@ -437,7 +437,7 @@ fileerror(ino_t cwd, ino_t ino, const char *errmesg)
        char pathbuf[MAXPATHLEN + 1];
 
        pwarn("%s ", errmesg);
-       if (ino < UFS_ROOTINO || ino > maxino) {
+       if (ino < UFS_ROOTINO || ino >= maxino) {
                pfatal("out-of-range inode number %ju", (uintmax_t)ino);
                return;
        }
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index bed87299a3cf..419d0e91a1df 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -169,7 +169,7 @@ inoinfo(ino_t inum)
        struct inostatlist *ilp;
        int iloff;
 
-       if (inum > maxino)
+       if (inum >= maxino)
                errx(EEXIT, "inoinfo: inumber %ju out of range",
                    (uintmax_t)inum);
        ilp = &inostathead[inum / sblock.fs_ipg];
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 00a60157138c..7dca95129ed1 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -433,8 +433,9 @@ void
 ginode(ino_t inumber, struct inode *ip)
 {
        ufs2_daddr_t iblk;
+       struct ufs2_dinode *dp;
 
-       if (inumber < UFS_ROOTINO || inumber > maxino)
+       if (inumber < UFS_ROOTINO || inumber >= maxino)
                errx(EEXIT, "bad inode number %ju to ginode",
                    (uintmax_t)inumber);
        ip->i_number = inumber;
@@ -473,14 +474,15 @@ ginode(ino_t inumber, struct inode *ip)
        }
        ip->i_dp = (union dinode *)
            &ip->i_bp->b_un.b_dinode2[inumber - ip->i_bp->b_index];
-       if (ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)ip->i_dp)) {
+       dp = (struct ufs2_dinode *)ip->i_dp;
+       /* Do not check hash of inodes being created */
+       if (dp->di_mode != 0 && ffs_verify_dinode_ckhash(&sblock, dp)) {
                pwarn("INODE CHECK-HASH FAILED");
                prtinode(ip);
                if (preen || reply("FIX") != 0) {
                        if (preen)
                                printf(" (FIXED)\n");
-                       ffs_update_dinode_ckhash(&sblock,
-                           (struct ufs2_dinode *)ip->i_dp);
+                       ffs_update_dinode_ckhash(&sblock, dp);
                        inodirty(ip);
                }
        }
@@ -1292,7 +1294,7 @@ findino(struct inodesc *idesc)
        if (dirp->d_ino == 0)
                return (KEEPON);
        if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
-           dirp->d_ino >= UFS_ROOTINO && dirp->d_ino <= maxino) {
+           dirp->d_ino >= UFS_ROOTINO && dirp->d_ino < maxino) {
                idesc->id_parent = dirp->d_ino;
                return (STOP|FOUND);
        }
@@ -1322,7 +1324,7 @@ prtinode(struct inode *ip)
 
        dp = ip->i_dp;
        printf(" I=%lu ", (u_long)ip->i_number);
-       if (ip->i_number < UFS_ROOTINO || ip->i_number > maxino)
+       if (ip->i_number < UFS_ROOTINO || ip->i_number >= maxino)
                return;
        printf(" OWNER=");
        if ((pw = getpwuid((int)DIP(dp, di_uid))) != NULL)
diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c
index 8200209cc03e..48bf27a8b142 100644
--- a/sbin/fsck_ffs/pass2.c
+++ b/sbin/fsck_ffs/pass2.c
@@ -371,7 +371,7 @@ chk1:
                dirp->d_reclen = proto.d_reclen;
        }
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
-               if (dirp->d_ino > maxino) {
+               if (dirp->d_ino >= maxino) {
                        direrror(idesc->id_number, "BAD INODE NUMBER FOR '..'");
                        /*
                         * If we know parent set it now, otherwise let it
@@ -471,7 +471,7 @@ chk2:
        }
        idesc->id_entryno++;
        n = 0;
-       if (dirp->d_ino > maxino) {
+       if (dirp->d_ino >= maxino) {
                fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
                n = reply("REMOVE");
        } else if (((dirp->d_ino == UFS_WINO && dirp->d_type != DT_WHT) ||

Reply via email to