aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2018-12-11 22:14:37 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2018-12-11 22:14:37 +0000
commit8f829a5cf0fa341a95fd4bed7091d6c44129d68f (patch)
tree2cb40f5c8c0521451556577ffdfcd8b8aeb90861 /sbin
parentd3cc40300eaa672ce8f7d1782454267d3ea15dfb (diff)
downloadsrc-8f829a5cf0fa341a95fd4bed7091d6c44129d68f.tar.gz
src-8f829a5cf0fa341a95fd4bed7091d6c44129d68f.zip
Continuing efforts to provide hardening of FFS. This change adds a
check hash to the filesystem inodes. Access attempts to files associated with an inode with an invalid check hash will fail with EINVAL (Invalid argument). Access is reestablished after an fsck is run to find and validate the inodes with invalid check-hashes. This check avoids a class of filesystem panics related to corrupted inodes. The hash is done using crc32c. Note this check-hash is for the inode itself and not any of its indirect blocks. Check-hash validation may be extended to also cover indirect block pointers, but that will be a separate (and more costly) feature. Check hashes are added only to UFS2 and not to UFS1 as UFS1 is primarily used in embedded systems with small memories and low-powered processors which need as light-weight a filesystem as possible. Reviewed by: kib Tested by: Peter Holm Sponsored by: Netflix
Notes
Notes: svn path=/head/; revision=341836
Diffstat (limited to 'sbin')
-rw-r--r--sbin/fsck_ffs/inode.c30
-rw-r--r--sbin/fsck_ffs/main.c2
-rw-r--r--sbin/fsirand/fsirand.c1
-rw-r--r--sbin/newfs/mkfs.c2
4 files changed, 33 insertions, 2 deletions
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index a914be8b87a5..6957a41f70c0 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -286,6 +286,7 @@ union dinode *
ginode(ino_t inumber)
{
ufs2_daddr_t iblk;
+ union dinode *dp;
if (inumber < UFS_ROOTINO || inumber > maxino)
errx(EEXIT, "bad inode number %ju to ginode",
@@ -301,7 +302,17 @@ ginode(ino_t inumber)
if (sblock.fs_magic == FS_UFS1_MAGIC)
return ((union dinode *)
&pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);
- return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]);
+ dp = (union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)];
+ if (ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp) != 0) {
+ pwarn("INODE CHECK-HASH FAILED");
+ prtinode(inumber, dp);
+ if (preen || reply("FIX") != 0) {
+ if (preen)
+ printf(" (FIXED)\n");
+ inodirty(dp);
+ }
+ }
+ return (dp);
}
/*
@@ -347,6 +358,21 @@ getnextinode(ino_t inumber, int rebuildcg)
nextinop += sizeof(struct ufs1_dinode);
else
nextinop += sizeof(struct ufs2_dinode);
+ if ((ckhashadd & CK_INODE) != 0) {
+ ffs_update_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp);
+ dirty(&inobuf);
+ }
+ if (ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp) != 0) {
+ pwarn("INODE CHECK-HASH FAILED");
+ prtinode(inumber, dp);
+ if (preen || reply("FIX") != 0) {
+ if (preen)
+ printf(" (FIXED)\n");
+ ffs_update_dinode_ckhash(&sblock,
+ (struct ufs2_dinode *)dp);
+ dirty(&inobuf);
+ }
+ }
if (rebuildcg && (char *)dp == inobuf.b_un.b_buf) {
/*
* Try to determine if we have reached the end of the
@@ -522,6 +548,8 @@ void
inodirty(union dinode *dp)
{
+ if (sblock.fs_magic == FS_UFS2_MAGIC)
+ ffs_update_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp);
dirty(pbp);
}
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index ce4d0a89a36a..47bd3987c8e8 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -468,13 +468,13 @@ checkfilesys(char *filesys)
ckhashadd |= CK_SUPERBLOCK;
sblock.fs_metackhash |= CK_SUPERBLOCK;
}
-#ifdef notyet
if ((sblock.fs_metackhash & CK_INODE) == 0 &&
getosreldate() >= P_OSREL_CK_INODE &&
reply("ADD INODE CHECK-HASH PROTECTION") != 0) {
ckhashadd |= CK_INODE;
sblock.fs_metackhash |= CK_INODE;
}
+#ifdef notyet
if ((sblock.fs_metackhash & CK_INDIR) == 0 &&
getosreldate() >= P_OSREL_CK_INDIR &&
reply("ADD INDIRECT BLOCK CHECK-HASH PROTECTION") != 0) {
diff --git a/sbin/fsirand/fsirand.c b/sbin/fsirand/fsirand.c
index 8675f7c3fd33..f24d34705b72 100644
--- a/sbin/fsirand/fsirand.c
+++ b/sbin/fsirand/fsirand.c
@@ -202,6 +202,7 @@ fsirand(char *device)
dp1++;
} else {
dp2->di_gen = arc4random();
+ ffs_update_dinode_ckhash(sblock, dp2);
dp2++;
}
}
diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c
index 2bea89cf2bc9..96849a791714 100644
--- a/sbin/newfs/mkfs.c
+++ b/sbin/newfs/mkfs.c
@@ -499,6 +499,8 @@ restart:
sblock.fs_metackhash |= CK_CYLGRP;
if (getosreldate() >= P_OSREL_CK_SUPERBLOCK)
sblock.fs_metackhash |= CK_SUPERBLOCK;
+ if (getosreldate() >= P_OSREL_CK_INODE)
+ sblock.fs_metackhash |= CK_INODE;
}
/*