git: da6f395119a5 - stable/15 - unionfs: detect common deadlock-producing mount misconfigurations
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 26 Dec 2025 07:38:32 UTC
The branch stable/15 has been updated by jah:
URL: https://cgit.FreeBSD.org/src/commit/?id=da6f395119a5eb1ed1dad56874c1c55a5721e220
commit da6f395119a5eb1ed1dad56874c1c55a5721e220
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-26 06:38:06 +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
Differential Revision: https://reviews.freebsd.org/D53988
(cherry picked from commit 0247b4018de2c341ac59a585362c10044cea86ad)
---
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 9342317ad08e..fd48a520f911 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,
- NULLVP, &(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);