The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=0d51adee307296a8031afb75f95a013423f7c396
commit 0d51adee307296a8031afb75f95a013423f7c396 Author: Rick Macklem <rmack...@freebsd.org> AuthorDate: 2025-06-29 16:09:23 +0000 Commit: Rick Macklem <rmack...@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) {