git: 61d9b0cb38bb - stable/14 - uipc_bindat(): Explicitly specify exclusive locking for the new vnode

From: Jason A. Harmening <jah_at_FreeBSD.org>
Date: Sun, 24 Mar 2024 03:04:42 UTC
The branch stable/14 has been updated by jah:

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

commit 61d9b0cb38bb0b057929997c7eab689105bfdeb6
Author:     Jason A. Harmening <jah@FreeBSD.org>
AuthorDate: 2024-02-03 17:07:16 +0000
Commit:     Jason A. Harmening <jah@FreeBSD.org>
CommitDate: 2024-03-24 02:55:38 +0000

    uipc_bindat(): Explicitly specify exclusive locking for the new vnode
    
    When calling VOP_CREATE(), uipc_bindat() reuses the componentname
    object from the preceding lookup operation, which is likely to specify
    LK_SHARED.  Furthermore, the VOP_CREATE() interface technically only
    requires the newly-created vnode to be returned with a shared lock.
    However, the socket layer requires the new vnode to be locked exclusive
    and asserts to that effect.
    
    In most cases, this is not a practical concern because most if not
    all base-layer filesystems (certainly FFS, ZFS, and msdosfs at least)
    always return the vnode locked exclusive regardless of the lock flags.
    However, it is an issue for unionfs which uses cn_lkflags to determine
    how the new unionfs wrapper vnode should be locked.  While it would
    be easy enough to work around this issue within unionfs itself, it
    seems better for the socket layer to be explicit about its locking
    requirements when issuing VOP_CREATE().
    
    Reviewed by:            kib, olce
    Differential Revision:  https://reviews.freebsd.org/D44047
    
    (cherry picked from commit d56c175ac9353bd701a488bb2606a3372623dcc5)
---
 sys/kern/uipc_usrreq.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 5d39e5ea91c1..e54cd01956bf 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -622,8 +622,19 @@ restart:
 	error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
 	    &vattr);
 #endif
-	if (error == 0)
+	if (error == 0) {
+		/*
+		 * The prior lookup may have left LK_SHARED in cn_lkflags,
+		 * and VOP_CREATE technically only requires the new vnode to
+		 * be locked shared. Most filesystems will return the new vnode
+		 * locked exclusive regardless, but we should explicitly
+		 * specify that here since we require it and assert to that
+		 * effect below.
+		 */
+		nd.ni_cnd.cn_lkflags = (nd.ni_cnd.cn_lkflags & ~LK_SHARED) |
+		    LK_EXCLUSIVE;
 		error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+	}
 	NDFREE_PNBUF(&nd);
 	if (error) {
 		VOP_VPUT_PAIR(nd.ni_dvp, NULL, true);