aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJessica Clarke <jrtc27@FreeBSD.org>2022-01-02 20:55:49 +0000
committerJessica Clarke <jrtc27@FreeBSD.org>2022-01-02 20:55:49 +0000
commit324150d6dab8a5fcde98c6cc1869da0becb7c3bb (patch)
treee169c5a18ccc0f77198bfcc9315c813e0a953c64
parent5b13fa7987c13aa7b5a67cc6b465475912de2d14 (diff)
downloadsrc-324150d6dab8a5fcde98c6cc1869da0becb7c3bb.tar.gz
src-324150d6dab8a5fcde98c6cc1869da0becb7c3bb.zip
ufs: Avoid subobject overflow in snapshot expunge code
The code here tries to be smart and zeroes out both di_db and di_ib with a single bzero call, thereby overrunning the di_db subobject. This is fine on most architectures, if a little dodgy. However, on CHERI, the compiler can optionally restrict the bounds on pointers to subobjects to just that subobject, in order to mitigate intra-object buffer overflows, and this is enabled in CheriBSD's pure-capability kernels. Instead, use separate bzero calls for each array, and let the compiler optimise it as it sees fit; even if it's not generating inline zeroing code, Clang will happily optimise two consecutive bzero's to a single larger call. Reviewed by: mckusick Differential Revision: https://reviews.freebsd.org/D33651
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index 59e5012c0019..c5063bf5f747 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -1084,7 +1084,8 @@ expunge_ufs1(snapvp, cancelip, fs, acctfunc, expungetype, clearmode)
dip->di_size = 0;
dip->di_blocks = 0;
dip->di_flags &= ~SF_SNAPSHOT;
- bzero(&dip->di_db[0], (UFS_NDADDR + UFS_NIADDR) * sizeof(ufs1_daddr_t));
+ bzero(dip->di_db, UFS_NDADDR * sizeof(ufs1_daddr_t));
+ bzero(dip->di_ib, UFS_NIADDR * sizeof(ufs1_daddr_t));
bdwrite(bp);
/*
* Now go through and expunge all the blocks in the file
@@ -1366,7 +1367,8 @@ expunge_ufs2(snapvp, cancelip, fs, acctfunc, expungetype, clearmode)
dip->di_size = 0;
dip->di_blocks = 0;
dip->di_flags &= ~SF_SNAPSHOT;
- bzero(&dip->di_db[0], (UFS_NDADDR + UFS_NIADDR) * sizeof(ufs2_daddr_t));
+ bzero(dip->di_db, UFS_NDADDR * sizeof(ufs2_daddr_t));
+ bzero(dip->di_ib, UFS_NIADDR * sizeof(ufs2_daddr_t));
if (clearmode || cancelip->i_effnlink == 0)
dip->di_mode = 0;
else