git: 0d51adee3072 - main - nfsd: Use an NFSv4 ACL for the delegation ACE if available
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 29 Jun 2025 16:12:16 UTC
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) {