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;