git: bea382f25b16 - main - kern/coredump_vnode.c: avoid dumping to the mount point we suspended

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 07 Oct 2026 17:01:12 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=bea382f25b16fec0e9a1c2be130935e739075287

commit bea382f25b16fec0e9a1c2be130935e739075287
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-10-03 23:59:30 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-10-07 17:00:53 +0000

    kern/coredump_vnode.c: avoid dumping to the mount point we suspended
    
    PR:     299095
    Reported by:    Rick Richard <rick@sloservers.com>
    Reviewed by:    markj
    Tested by:      Rick Richard <rick@sloservers.com> (previous version)
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D60283
---
 sys/kern/vfs_vnops.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 7b86bb2bdb3f..96b1c5696251 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -241,6 +241,42 @@ vfs_check_namedattr(struct vnode *vp)
 	return (error);
 }
 
+/*
+ * This check is performed when a vnode is opened for dumping the core
+ * from userspace process. The /dev/ufssuspend device allows userspace
+ * to suspend the UFS volume, and we must check that the dump does not
+ * go into the volume the coredumping process suspended.
+ *
+ * Taking MNT_ILOCK around checks is not required, because the process
+ * is single-threaded around dumping core, and we in particular check
+ * if the current process is the suspension owner.
+ */
+static int
+vn_open_nosuspend(struct vnode *vp, u_int vn_open_flags)
+{
+	struct mount *mp;
+	struct thread *susp_owner;
+	int error;
+
+	if ((vn_open_flags & VN_OPEN_COREDUMP) == 0)
+		return (0);
+	MPASS((curproc->p_flag & P_HADTHREADS) == 0 ||
+	    (curproc->p_flag & (P_SINGLE_BOUNDARY | P_SINGLE_EXIT |
+	    P_STOPPED)) != 0);
+
+	mp = NULL;
+	error = VOP_GETWRITEMOUNT(vp, &mp);
+	if (error != 0 || mp == NULL)
+		return (0);
+	susp_owner = atomic_load_ptr(&mp->mnt_susp_owner);
+	if ((atomic_load_int(&mp->mnt_kern_flag) & (MNTK_SUSPEND |
+	    MNTK_SUSPENDED)) != 0 && susp_owner != NULL &&
+	    susp_owner->td_proc == curproc)
+		error = EBUSY;
+	vfs_rel(mp);
+	return (error);
+}
+
 /*
  * Common code for vnode open operations via a name lookup.
  * Lookup the vnode and invoke VOP_CREATE if needed.
@@ -295,6 +331,12 @@ restart:
 				ndp->ni_dvp = NULL;
 				goto bad;
 			}
+			error = vn_open_nosuspend(ndp->ni_dvp, vn_open_flags);
+			if (error != 0) {
+				vp = ndp->ni_dvp;
+				ndp->ni_dvp = NULL;
+				goto bad;
+			}
 			VATTR_NULL(vap);
 			vap->va_type = VREG;
 			vap->va_mode = cmode;
@@ -375,7 +417,9 @@ restart:
 				goto bad;
 		}
 	}
-	error = vn_open_vnode(vp, fmode, cred, curthread, fp);
+	error = vn_open_nosuspend(vp, vn_open_flags);
+	if (error == 0)
+		error = vn_open_vnode(vp, fmode, cred, curthread, fp);
 	if (first_open) {
 		VI_LOCK(vp);
 		vp->v_iflag &= ~VI_FOPENING;