Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 May 2023 00:12:48 GMT
From:      Kirk McKusick <mckusick@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 101a9ac07128 - main - Fix a bug in fsck_ffs(8) triggered by corrupted filesystems.
Message-ID:  <202305280012.34S0Cmeo099861@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by mckusick:

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

commit 101a9ac07128a17d8797cc3e93978d2cfa457e99
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-28 00:09:02 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-05-28 00:12:30 +0000

    Fix a bug in fsck_ffs(8) triggered by corrupted filesystems.
    
    Check for valid file size before processing journal entries for it.
    Done by extracting the file size check from pass1.c into chkfilesize()
    then using it in the journal code in suj.c
    
    Reported-by:  Robert Morris
    PR:           271378
    MFC-after:    1 week
    Sponsored-by: The FreeBSD Foundation
---
 sbin/fsck_ffs/fsck.h   |  1 +
 sbin/fsck_ffs/fsutil.c | 25 +++++++++++++++++++++++++
 sbin/fsck_ffs/pass1.c  | 12 +-----------
 sbin/fsck_ffs/suj.c    |  3 +++
 4 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index ad82c5f80da1..3b80169c1e3c 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -470,6 +470,7 @@ void		check_blkcnt(struct inode *ip);
 int		check_cgmagic(int cg, struct bufarea *cgbp);
 void		rebuild_cg(int cg, struct bufarea *cgbp);
 void		check_dirdepth(struct inoinfo *inp);
+int		chkfilesize(mode_t mode, u_int64_t filesize);
 int		chkrange(ufs2_daddr_t blk, int cnt);
 void		ckfini(int markclean);
 int		ckinode(union dinode *dp, struct inodesc *);
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 7602203e6e90..5edc258d54bf 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -1207,6 +1207,31 @@ std_checkblkavail(ufs2_daddr_t blkno, long frags)
 	return (0);
 }
 
+/*
+ * Check whether a file size is within the limits for the filesystem.
+ * Return 1 when valid and 0 when too big.
+ *
+ * This should match the file size limit in ffs_mountfs().
+ */
+int
+chkfilesize(mode_t mode, u_int64_t filesize)
+{
+	u_int64_t kernmaxfilesize;
+
+	if (sblock.fs_magic == FS_UFS1_MAGIC)
+		kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1;
+	else
+		kernmaxfilesize = sblock.fs_maxfilesize;
+	if (filesize > kernmaxfilesize ||
+	    filesize > sblock.fs_maxfilesize ||
+	    (mode == IFDIR && filesize > MAXDIRSIZE)) {
+		if (debug)
+			printf("bad file size %ju:", (uintmax_t)filesize);
+		return (0);
+	}
+	return (1);
+}
+
 /*
  * Slow down IO so as to leave some disk bandwidth for other processes
  */
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index 863bf34ff0fc..d328234220ad 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -256,7 +256,6 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg)
 {
 	struct inode ip;
 	union dinode *dp;
-	off_t kernmaxfilesize;
 	ufs2_daddr_t ndb;
 	mode_t mode;
 	intmax_t size, fixsize;
@@ -293,16 +292,7 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg)
 		return (1);
 	}
 	lastino = inumber;
-	/* This should match the file size limit in ffs_mountfs(). */
-	if (sblock.fs_magic == FS_UFS1_MAGIC)
-		kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1;
-	else
-		kernmaxfilesize = sblock.fs_maxfilesize;
-	if (DIP(dp, di_size) > kernmaxfilesize ||
-	    DIP(dp, di_size) > sblock.fs_maxfilesize ||
-	    (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) {
-		if (debug)
-			printf("bad size %ju:", (uintmax_t)DIP(dp, di_size));
+	if (chkfilesize(mode, DIP(dp, di_size)) == 0) {
 		pfatal("BAD FILE SIZE");
 		goto unknown;
 	}
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index 8fed3d7723d6..d51e0ff4d83b 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -1965,6 +1965,9 @@ ino_build_trunc(struct jtrncrec *rec)
 		printf("ino_build_trunc: op %d ino %ju, size %jd\n",
 		    rec->jt_op, (uintmax_t)rec->jt_ino,
 		    (uintmax_t)rec->jt_size);
+	if (chkfilesize(IFREG, rec->jt_size) == 0)
+		err_suj("ino_build: truncation size too large %ju\n",
+		    (intmax_t)rec->jt_size);
 	sino = ino_lookup(rec->jt_ino, 1);
 	if (rec->jt_op == JOP_SYNC) {
 		sino->si_trunc = NULL;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202305280012.34S0Cmeo099861>