summaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>2024-07-12 08:15:20 +0000
committerBob Beck <beck@cvs.openbsd.org>2024-07-12 08:15:20 +0000
commit89413f200efe95cd81f3067313a5802e1f39bc3b (patch)
tree8ea63569c126d602e0cbd8525d2504f85cd68127 /sys/ufs
parent0fae8424df55fc9eeb2e693c18ce0c6dc6b59cfc (diff)
Add vdoom() to fix ufs/ext2fs re-use of invalid vnode.
This was noticed by syzkiller and analyzed in isolaiton by mbuhl@ and visa@ two years ago. As the kernel has become more unlocked it has started to appear more and was being hit regularly by jsing@ on the Go builder. The problem was during reclaim of a inode the corresponding vnode could be picked up by a vget() by another thread while the inode was being cleared out in the ufs_inactive routine and the thread running ufs_inactive slept for i/o. When raced the vnode would then not have zero use count and would not be cleared out on exit from ufs_inactive with a dead/invalid vnode being used. While this could get "fixed" by checking for the race happening and trying again in the inactive routine, or by adding "yet another visible vnode locking flag" we choose to add a vdoom() api for the moment that allows the caller to block future attempts to grab this vnode until it is cleared out fully with vclean. Teste by jsing@ on the Go builder and seems to solve the issue. ok kettenis@, claudio@
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ext2fs/ext2fs_inode.c16
-rw-r--r--sys/ufs/ufs/ufs_inode.c14
2 files changed, 23 insertions, 7 deletions
diff --git a/sys/ufs/ext2fs/ext2fs_inode.c b/sys/ufs/ext2fs/ext2fs_inode.c
index 2962628f865..3bbe98b6688 100644
--- a/sys/ufs/ext2fs/ext2fs_inode.c
+++ b/sys/ufs/ext2fs/ext2fs_inode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_inode.c,v 1.66 2022/08/12 14:30:53 visa Exp $ */
+/* $OpenBSD: ext2fs_inode.c,v 1.67 2024/07/12 08:15:19 beck Exp $ */
/* $NetBSD: ext2fs_inode.c,v 1.24 2001/06/19 12:59:18 wiz Exp $ */
/*
@@ -105,20 +105,28 @@ ext2fs_inactive(void *v)
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
struct timespec ts;
+ int recycle_vnode = 0;
int error = 0;
#ifdef DIAGNOSTIC
extern int prtactive;
- if (prtactive && vp->v_usecount != 0)
+ if (prtactive && vp->v_usecount != 0)
vprint("ext2fs_inactive: pushing active", vp);
#endif
/* Get rid of inodes related to stale file handles. */
- if (ip->i_e2din == NULL || ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime)
+ if (ip->i_e2din == NULL || ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime) {
+ recycle_vnode = 1;
+ vdoom(vp);
goto out;
+ }
error = 0;
if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+ /* lock this vnode and promise to vclean it */
+ recycle_vnode = 1;
+ vdoom(vp);
+
if (ext2fs_size(ip) != 0) {
error = ext2fs_truncate(ip, (off_t)0, 0, NOCRED);
}
@@ -136,7 +144,7 @@ out:
* If we are done with the inode, reclaim it
* so that it can be reused immediately.
*/
- if (ip->i_e2din == NULL || ip->i_e2fs_dtime != 0)
+ if (recycle_vnode)
vrecycle(vp, ap->a_p);
return (error);
}
diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
index 4ea385d0477..67182ceb655 100644
--- a/sys/ufs/ufs/ufs_inode.c
+++ b/sys/ufs/ufs/ufs_inode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_inode.c,v 1.45 2024/02/03 18:51:58 beck Exp $ */
+/* $OpenBSD: ufs_inode.c,v 1.46 2024/07/12 08:15:19 beck Exp $ */
/* $NetBSD: ufs_inode.c,v 1.7 1996/05/11 18:27:52 mycroft Exp $ */
/*
@@ -63,6 +63,7 @@ ufs_inactive(void *v)
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
mode_t mode;
+ int recycle_vnode = 0;
int error = 0;
#ifdef DIAGNOSTIC
extern int prtactive;
@@ -74,10 +75,17 @@ ufs_inactive(void *v)
/*
* Ignore inodes related to stale file handles.
*/
- if (ip->i_din1 == NULL || DIP(ip, mode) == 0)
+ if (ip->i_din1 == NULL || DIP(ip, mode) == 0) {
+ recycle_vnode = 1;
+ vdoom(vp);
goto out;
+ }
if (DIP(ip, nlink) <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+ /* lock this vnode and promise to vclean it */
+ recycle_vnode = 1;
+ vdoom(vp);
+
if (getinoquota(ip) == 0)
(void)ufs_quota_free_inode(ip, NOCRED);
@@ -101,7 +109,7 @@ out:
* If we are done with the inode, reclaim it
* so that it can be reused immediately.
*/
- if (ip->i_din1 == NULL || DIP(ip, mode) == 0)
+ if (recycle_vnode)
vrecycle(vp, ap->a_p);
return (error);