Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Jun 2025 16:12:16 GMT
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0d51adee3072 - main - nfsd: Use an NFSv4 ACL for the delegation ACE if available
Message-ID:  <202506291612.55TGCGFi074503@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by rmacklem:

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

commit 0d51adee307296a8031afb75f95a013423f7c396
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-06-29 16:09:23 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-06-29 16:09:23 +0000

    nfsd: Use an NFSv4 ACL for the delegation ACE if available
    
    Without this patch, the ACE in a NFSv4 delegation reply is
    generated from the file's user mode bits.  This is correct
    in most situations, but not if the file has certain NFSv4 ACLs.
    
    This patch uses the @OWNER ACE in the NFSv4 ACL if it comes
    before any deny ACE and returns a "nil access" ACE if a
    deny preceeds the @OWNER.
    
    This change affects few NFSv4 clients, since most clients
    ignore the delegation access ACE and it only affects cases
    where the NFSv4 server is issuing delegations.
    
    Fixes:  8e2a90ac8089 ("nfscommon: Factor out conversion of ae_perm to NFSv4 ACE flags")
---
 sys/fs/nfsserver/nfs_nfsdserv.c | 85 +++++++++++++++++++++++++++++++++++------
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index e54cc594d611..4e15d55eb312 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -64,6 +64,7 @@ extern u_long sb_max_adj;
 extern int nfsrv_pnfsatime;
 extern int nfsrv_maxpnfsmirror;
 extern uint32_t nfs_srvmaxio;
+extern int nfsrv_issuedelegs;
 
 static int	nfs_async = 0;
 SYSCTL_DECL(_vfs_nfsd);
@@ -2866,6 +2867,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 	NFSACL_T *aclp = NULL;
 	struct thread *p = curthread;
 	bool done_namei;
+	__enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL }
+	    delegace;
 
 #ifdef NFS4_ACL_EXTATTR_NAME
 	aclp = acl_alloc(M_WAITOK);
@@ -2873,6 +2876,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 #endif
 	NFSZERO_ATTRBIT(&attrbits);
 	done_namei = false;
+	delegace = USEMODE;
 	named.ni_cnd.cn_nameiop = 0;
 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 	i = fxdr_unsigned(int, *(tl + 5));
@@ -3214,6 +3218,25 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 
 	if (!nd->nd_repstat)
 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
+
+	if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 &&
+	    (dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) {
+		if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) {
+			int retacl;
+
+			/* We do not yet have an ACL, so try and get one. */
+			retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp,
+			    nd->nd_cred, p);
+			if (retacl != 0 && retacl != ENOATTR &&
+			    retacl != EOPNOTSUPP && retacl != EINVAL)
+				delegace = USENONE;
+			else if (retacl == 0 && aclp->acl_cnt > 0)
+				delegace = USENFSV4ACL;
+		} else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) {
+			delegace = USENFSV4ACL;
+		}
+	}
+
 	/*
 	 * Do the open locking/delegation stuff.
 	 */
@@ -3306,18 +3329,56 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
 				txdr_hyper(nva.na_size, tl);
 			}
-			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
-			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
-			*tl++ = txdr_unsigned(0x0);
-			acemask = NFSV4ACE_ALLFILESMASK;
-			if (nva.na_mode & S_IRUSR)
-			    acemask |= NFSV4ACE_READMASK;
-			if (nva.na_mode & S_IWUSR)
-			    acemask |= NFSV4ACE_WRITEMASK;
-			if (nva.na_mode & S_IXUSR)
-			    acemask |= NFSV4ACE_EXECUTEMASK;
-			*tl = txdr_unsigned(acemask);
-			(void) nfsm_strtom(nd, "OWNER@", 6);
+
+			/* Set up the write delegation ACE. */
+			NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+			if (delegace == USENFSV4ACL) {
+				int j;
+
+				for (j = 0; j < aclp->acl_cnt; j++) {
+					if (aclp->acl_entry[j].ae_tag ==
+					    ACL_USER_OBJ ||
+					    aclp->acl_entry[j].ae_entry_type !=
+					    ACL_ENTRY_TYPE_ALLOW)
+						break;
+				}
+				if (j < aclp->acl_cnt &&
+				    aclp->acl_entry[j].ae_tag ==
+				    ACL_USER_OBJ &&
+				    aclp->acl_entry[j].ae_entry_type ==
+				    ACL_ENTRY_TYPE_ALLOW) {
+					/* Use this ACE. */
+					*tl++ = txdr_unsigned(
+					    NFSV4ACE_ALLOWEDTYPE);
+					*tl++ = txdr_unsigned(0x0);
+					*tl = txdr_unsigned(
+					    nfs_aceperm(
+					    aclp->acl_entry[j].ae_perm));
+					(void)nfsm_strtom(nd, "OWNER@", 6);
+				} else
+					delegace = USENONE;
+			}
+			if (delegace == USENONE) {
+				/* Don't allow anything. */
+				*tl++ = 0x0;
+				*tl++ = 0x0;
+				*tl = 0x0;
+				NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+				*tl = 0;
+			} else if (delegace == USEMODE) {
+				/* Build from mode. */
+				*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
+				*tl++ = txdr_unsigned(0x0);
+				acemask = NFSV4ACE_ALLFILESMASK;
+				if (nva.na_mode & S_IRUSR)
+					acemask |= NFSV4ACE_READMASK;
+				if (nva.na_mode & S_IWUSR)
+					acemask |= NFSV4ACE_WRITEMASK;
+				if (nva.na_mode & S_IXUSR)
+					acemask |= NFSV4ACE_EXECUTEMASK;
+				*tl = txdr_unsigned(acemask);
+				(void)nfsm_strtom(nd, "OWNER@", 6);
+			}
 		}
 		*vpp = vp;
 	} else if (vp) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506291612.55TGCGFi074503>