aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2023-05-28 00:09:02 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2023-05-28 00:12:30 +0000
commit101a9ac07128a17d8797cc3e93978d2cfa457e99 (patch)
tree117712c3ddecac3c468241eafa1c8c7e9e91878f /sbin
parentdcf5d5603b3af831002caa7b2f64aec8bda14071 (diff)
downloadsrc-101a9ac07128a17d8797cc3e93978d2cfa457e99.tar.gz
src-101a9ac07128a17d8797cc3e93978d2cfa457e99.zip
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
Diffstat (limited to 'sbin')
-rw-r--r--sbin/fsck_ffs/fsck.h1
-rw-r--r--sbin/fsck_ffs/fsutil.c25
-rw-r--r--sbin/fsck_ffs/pass1.c12
-rw-r--r--sbin/fsck_ffs/suj.c3
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
@@ -1208,6 +1208,31 @@ std_checkblkavail(ufs2_daddr_t blkno, long frags)
}
/*
+ * 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
*/
void
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;