git: c8d6c9351a92 - stable/14 - unionfs_lookup(): fix wild accesses to vnode private data

From: Jason A. Harmening <jah_at_FreeBSD.org>
Date: Sat, 27 Apr 2024 17:46:31 UTC
The branch stable/14 has been updated by jah:

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

commit c8d6c9351a9255becf3a772be441d4648b998306
Author:     Jason A. Harmening <jah@FreeBSD.org>
AuthorDate: 2024-02-18 00:19:32 +0000
Commit:     Jason A. Harmening <jah@FreeBSD.org>
CommitDate: 2024-04-27 17:42:36 +0000

    unionfs_lookup(): fix wild accesses to vnode private data
    
    There are a few spots in which unionfs_lookup() accesses unionfs vnode
    private data without holding the corresponding vnode lock or interlock.
    
    Reviewed by:            kib, olce
    Differential Revision:  https://reviews.freebsd.org/D44601
    
    (cherry picked from commit b18029bc59d2ed6b0eeeb233189cf713b34b467c)
---
 sys/fs/unionfs/union_vnops.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 5a2d4751ed4f..eff437fbcad3 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -81,7 +81,7 @@
 static int
 unionfs_lookup(struct vop_cachedlookup_args *ap)
 {
-	struct unionfs_node *dunp;
+	struct unionfs_node *dunp, *unp;
 	struct vnode   *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
 	struct vattr	va;
 	struct componentname *cnp;
@@ -141,6 +141,9 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
 		if (dtmpvp == udvp && ldvp != NULLVP) {
 			VOP_UNLOCK(udvp);
 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
+			dunp = VTOUNIONFS(dvp);
+			if (error == 0 && dunp == NULL)
+				error = ENOENT;
 		}
 
 		if (error == 0) {
@@ -154,14 +157,15 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
 				VOP_UNLOCK(vp);
 			vrele(vp);
 
+			dtmpvp = dunp->un_dvp;
+			vref(dtmpvp);
 			VOP_UNLOCK(dvp);
-			*(ap->a_vpp) = dunp->un_dvp;
-			vref(dunp->un_dvp);
+			*(ap->a_vpp) = dtmpvp;
 
 			if (nameiop == DELETE || nameiop == RENAME)
-				vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY);
+				vn_lock(dtmpvp, LK_EXCLUSIVE | LK_RETRY);
 			else if (cnp->cn_lkflags & LK_TYPE_MASK)
-				vn_lock(dunp->un_dvp, cnp->cn_lkflags |
+				vn_lock(dtmpvp, cnp->cn_lkflags |
 				    LK_RETRY);
 
 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
@@ -274,8 +278,12 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 			lockflag = 1;
 		}
-		error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
-		    udvp, VTOUNIONFS(vp), cnp, td);
+		unp = VTOUNIONFS(vp);
+		if (unp == NULL)
+			error = ENOENT;
+		else
+			error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
+			    udvp, unp, cnp, td);
 		if (lockflag != 0)
 			VOP_UNLOCK(vp);
 		if (error != 0) {