Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Dec 2025 06:32:56 +0000
From:      Jason A. Harmening <jah@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0247b4018de2 - main - unionfs: detect common deadlock-producing mount misconfigurations
Message-ID:  <693bb718.24577.5dcb7e3d@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help

The branch main has been updated by jah:

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

commit 0247b4018de2c341ac59a585362c10044cea86ad
Author:     Jason A. Harmening <jah@FreeBSD.org>
AuthorDate: 2025-11-29 07:53:16 +0000
Commit:     Jason A. Harmening <jah@FreeBSD.org>
CommitDate: 2025-12-12 06:32:05 +0000

    unionfs: detect common deadlock-producing mount misconfigurations
    
    When creating a unionfs mount, it's fairly easy to shoot oneself
    in the foot by specifying upper and lower file hierarchies that
    resolve back to the same vnodes.  This is fairly easy to do if
    the sameness is not obvious due to aliasing through nullfs or other
    unionfs mounts (as in the associated PR), and will produce either
    deadlock or failed locking assertions on any attempt to use the
    resulting unionfs mount.
    
    Leverage VOP_GETLOWVNODE() to detect the most common cases of
    foot-shooting at mount time and fail the mount with EDEADLK.
    This is not meant to be an exhaustive check for all possible
    deadlock-producing scenarios, but it is an extremely cheap and
    simple approach that, unlike previous proposed fixes, also works
    in the presence of nullfs aliases.
    
    PR:             172334
    Reported by:    ngie, Karlo Miličević <karlo98.m@gmail.com>
    Reviewed by:    kib, olce
    Tested by:      pho
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D53988
---
 sys/fs/unionfs/union_vfsops.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c
index 284b24a604f4..3eb67221ec0e 100644
--- a/sys/fs/unionfs/union_vfsops.c
+++ b/sys/fs/unionfs/union_vfsops.c
@@ -73,6 +73,8 @@ unionfs_domount(struct mount *mp)
 {
 	struct vnode   *lowerrootvp;
 	struct vnode   *upperrootvp;
+	struct vnode   *lvp1;
+	struct vnode   *lvp2;
 	struct unionfs_mount *ump;
 	char           *target;
 	char           *tmp;
@@ -276,11 +278,32 @@ unionfs_domount(struct mount *mp)
 	 */
 	VOP_UNLOCK(ump->um_uppervp);
 
+	/*
+	 * Detect common cases in which constructing a unionfs hierarchy
+	 * would produce deadlock (or failed locking assertions) upon
+	 * use of the resulting unionfs vnodes.  This typically happens
+	 * when the requested upper and lower filesytems (which themselves
+	 * may be unionfs instances and/or nullfs aliases) end up resolving
+	 * to the same base-layer files.  Note that this is not meant to be
+	 * an exhaustive check of all possible deadlock-producing scenarios.
+	 */
+	lvp1 = lvp2 = NULL;
+	VOP_GETLOWVNODE(ump->um_lowervp, &lvp1, FREAD);
+	VOP_GETLOWVNODE(ump->um_uppervp, &lvp2, FREAD);
+	if (lvp1 != NULL && lvp1 == lvp2)
+		error = EDEADLK;
+	if (lvp1 != NULL)
+		vrele(lvp1);
+	if (lvp2 != NULL)
+		vrele(lvp2);
+
 	/*
 	 * Get the unionfs root vnode.
 	 */
-	error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp,
-	    NULL, &(ump->um_rootvp), NULL);
+	if (error == 0) {
+		error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp,
+		    NULL, &(ump->um_rootvp), NULL);
+	}
 	if (error != 0) {
 		vrele(upperrootvp);
 		free(ump, M_UNIONFSMNT);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?693bb718.24577.5dcb7e3d>