git: fbfbd0638a5a - stable/13 - Fix a bug in fsck_ffs(8) triggered by corrupted filesystems.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 07 Jun 2023 23:15:35 UTC
The branch stable/13 has been updated by mckusick:
URL: https://cgit.FreeBSD.org/src/commit/?id=fbfbd0638a5a3dd4f76eaf17f81450cc09d48e5b
commit fbfbd0638a5a3dd4f76eaf17f81450cc09d48e5b
Author: Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-27 23:07:09 +0000
Commit: Kirk McKusick <mckusick@FreeBSD.org>
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) ||