git: 3035f98d56eb - 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:36 UTC
The branch stable/13 has been updated by mckusick:
URL: https://cgit.FreeBSD.org/src/commit/?id=3035f98d56eb72240c6260d667427ab4ade08b45
commit 3035f98d56eb72240c6260d667427ab4ade08b45
Author: Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-28 00:09:02 +0000
Commit: Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-06-07 22:46:53 +0000
Fix a bug in fsck_ffs(8) triggered by corrupted filesystems.
Reported-by: Robert Morris
PR: 271378
Sponsored-by: The FreeBSD Foundation
(cherry picked from commit 101a9ac07128a17d8797cc3e93978d2cfa457e99)
---
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 9f9b1e0a8857..4f77fc39f3f7 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -471,6 +471,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 419d0e91a1df..ab55bdfbb37a 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -1206,6 +1206,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 8bcee7c54c85..cbb6e597dfee 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -1963,6 +1963,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;