Module Name: src
Committed By: hannken
Date: Wed Jan 17 10:20:12 UTC 2024
Modified Files:
src/sys/miscfs/procfs: procfs.h procfs_subr.c procfs_vfsops.c
Log Message:
Using the exechook to revoke procfs nodes is racy and may deadlock:
one thread runs doexechooks() -> procfs_revoke_vnodes() and wants to suspend
the file system for vgone(), while another thread runs a forced unmount,
has the file system suspended, tries to disestablish the exechook and
waits for doexechooks() to complete.
Establish/disestablish the exechook on module load/unload instead
mount/unmount and use the hashmap to access all procfs nodes for this pid.
May fix PR kern/57775 ""panic: unmount: dangling vnode" while umounting procfs"
To generate a diff of this commit:
cvs rdiff -u -r1.83 -r1.84 src/sys/miscfs/procfs/procfs.h
cvs rdiff -u -r1.116 -r1.117 src/sys/miscfs/procfs/procfs_subr.c
cvs rdiff -u -r1.112 -r1.113 src/sys/miscfs/procfs/procfs_vfsops.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/miscfs/procfs/procfs.h
diff -u src/sys/miscfs/procfs/procfs.h:1.83 src/sys/miscfs/procfs/procfs.h:1.84
--- src/sys/miscfs/procfs/procfs.h:1.83 Wed Jan 17 10:19:21 2024
+++ src/sys/miscfs/procfs/procfs.h Wed Jan 17 10:20:12 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs.h,v 1.83 2024/01/17 10:19:21 hannken Exp $ */
+/* $NetBSD: procfs.h,v 1.84 2024/01/17 10:20:12 hannken Exp $ */
/*
* Copyright (c) 1993
@@ -192,7 +192,6 @@ procfs_fileno(pid_t _pid, pfstype _type,
#define PROCFS_TYPE(type) ((type) % PFSlast)
struct procfsmount {
- void *pmnt_exechook;
int pmnt_flags;
};
@@ -272,7 +271,6 @@ int procfs_dolimit(struct lwp *, struct
struct uio *);
void procfs_hashrem(struct pfsnode *);
-void procfs_revoke_vnodes(struct proc *, void *);
int procfs_getfp(struct pfsnode *, struct proc *, struct file **);
/* functions to check whether or not files should be displayed */
Index: src/sys/miscfs/procfs/procfs_subr.c
diff -u src/sys/miscfs/procfs/procfs_subr.c:1.116 src/sys/miscfs/procfs/procfs_subr.c:1.117
--- src/sys/miscfs/procfs/procfs_subr.c:1.116 Sat May 23 23:42:43 2020
+++ src/sys/miscfs/procfs/procfs_subr.c Wed Jan 17 10:20:12 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs_subr.c,v 1.116 2020/05/23 23:42:43 ad Exp $ */
+/* $NetBSD: procfs_subr.c,v 1.117 2024/01/17 10:20:12 hannken Exp $ */
/*-
* Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -102,7 +102,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.116 2020/05/23 23:42:43 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.117 2024/01/17 10:20:12 hannken Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -358,57 +358,6 @@ vfs_findname(const vfs_namemap_t *nm, co
return (0);
}
-static bool
-procfs_revoke_selector(void *arg, struct vnode *vp)
-{
- struct proc *p = arg;
- struct pfsnode *pfs;
-
- KASSERT(mutex_owned(vp->v_interlock));
-
- pfs = VTOPFS(vp);
-
- return (pfs != NULL && pfs->pfs_pid == p->p_pid);
-}
-
-void
-procfs_revoke_vnodes(struct proc *p, void *arg)
-{
- int error;
- bool suspended;
- struct vnode *vp;
- struct vnode_iterator *marker;
- struct mount *mp = (struct mount *)arg;
-
- if (!(p->p_flag & PK_SUGID))
- return;
-
- suspended = false;
- vfs_vnode_iterator_init(mp, &marker);
-
- while ((vp = vfs_vnode_iterator_next(marker,
- procfs_revoke_selector, p)) != NULL) {
- if (vrecycle(vp))
- continue;
- /* Vnode is busy, we have to suspend the mount for vgone(). */
- while (! suspended) {
- error = vfs_suspend(mp, 0);
- if (error == 0) {
- suspended = true;
- } else if (error != EINTR && error != ERESTART) {
- KASSERT(error == EOPNOTSUPP);
- break;
- }
- }
- vgone(vp);
- }
-
- if (suspended)
- vfs_resume(mp);
-
- vfs_vnode_iterator_destroy(marker);
-}
-
bool
procfs_use_linux_compat(struct mount *mp)
{
Index: src/sys/miscfs/procfs/procfs_vfsops.c
diff -u src/sys/miscfs/procfs/procfs_vfsops.c:1.112 src/sys/miscfs/procfs/procfs_vfsops.c:1.113
--- src/sys/miscfs/procfs/procfs_vfsops.c:1.112 Wed Jan 17 10:19:21 2024
+++ src/sys/miscfs/procfs/procfs_vfsops.c Wed Jan 17 10:20:12 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs_vfsops.c,v 1.112 2024/01/17 10:19:21 hannken Exp $ */
+/* $NetBSD: procfs_vfsops.c,v 1.113 2024/01/17 10:20:12 hannken Exp $ */
/*
* Copyright (c) 1993
@@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_vfsops.c,v 1.112 2024/01/17 10:19:21 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_vfsops.c,v 1.113 2024/01/17 10:20:12 hannken Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -88,6 +88,7 @@ __KERNEL_RCSID(0, "$NetBSD: procfs_vfsop
#include <sys/dirent.h>
#include <sys/file.h>
#include <sys/filedesc.h>
+#include <sys/fstrans.h>
#include <sys/kauth.h>
#include <sys/kernel.h>
#include <sys/module.h>
@@ -113,6 +114,7 @@ VFS_PROTOS(procfs);
#define PROCFS_HASHSIZE 256
static kauth_listener_t procfs_listener;
+static void *procfs_exechook;
LIST_HEAD(hashhead, pfsnode);
static u_long procfs_hashmask;
static struct hashhead *procfs_hashtab;
@@ -188,7 +190,6 @@ procfs_mount(
error = set_statvfs_info(path, UIO_USERSPACE, "procfs", UIO_SYSSPACE,
mp->mnt_op->vfs_name, mp, l);
- pmnt->pmnt_exechook = exechook_establish(procfs_revoke_vnodes, mp);
if (*data_len >= sizeof *args)
pmnt->pmnt_flags = args->flags;
else
@@ -213,8 +214,6 @@ procfs_unmount(struct mount *mp, int mnt
if ((error = vflush(mp, 0, flags)) != 0)
return (error);
- exechook_disestablish(VFSTOPROC(mp)->pmnt_exechook);
-
kmem_free(mp->mnt_data, sizeof(struct procfsmount));
mp->mnt_data = NULL;
@@ -513,6 +512,48 @@ struct vfsops procfs_vfsops = {
.vfs_opv_descs = procfs_vnodeopv_descs
};
+static void
+procfs_exechook_cb(struct proc *p, void *arg)
+{
+ struct hashhead *head;
+ struct pfsnode *pfs;
+ struct mount *mp;
+ struct pfskey key;
+ struct vnode *vp;
+ int error;
+
+ if (!(p->p_flag & PK_SUGID))
+ return;
+
+ head = procfs_hashhead(p->p_pid);
+
+again:
+ mutex_enter(&procfs_hashlock);
+ LIST_FOREACH(pfs, head, pfs_hash) {
+ if (pfs->pfs_pid != p->p_pid)
+ continue;
+ mp = pfs->pfs_mount;
+ key = pfs->pfs_key;
+ vfs_ref(mp);
+ mutex_exit(&procfs_hashlock);
+
+ error = vcache_get(mp, &key, sizeof(key), &vp);
+ vfs_rele(mp);
+ if (error != 0)
+ goto again;
+ if (vrecycle(vp))
+ goto again;
+ do {
+ error = vfs_suspend(mp, 0);
+ } while (error == EINTR || error == ERESTART);
+ vgone(vp);
+ if (error == 0)
+ vfs_resume(mp);
+ goto again;
+ }
+ mutex_exit(&procfs_hashlock);
+}
+
static int
procfs_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
void *arg0, void *arg1, void *arg2, void *arg3)
@@ -575,12 +616,21 @@ procfs_modcmd(modcmd_t cmd, void *arg)
procfs_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
procfs_listener_cb, NULL);
+ procfs_exechook = exechook_establish(procfs_exechook_cb, NULL);
+
+ mutex_init(&procfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
+ procfs_hashtab = hashinit(PROCFS_HASHSIZE, HASH_LIST, true,
+ &procfs_hashmask);
+
break;
case MODULE_CMD_FINI:
error = vfs_detach(&procfs_vfsops);
if (error != 0)
break;
kauth_unlisten_scope(procfs_listener);
+ exechook_disestablish(procfs_exechook);
+ mutex_destroy(&procfs_hashlock);
+ hashdone(procfs_hashtab, HASH_LIST, procfs_hashmask);
break;
default:
error = ENOTTY;