From: rick.macklem@gmail.com
To: linux-nfs@vger.kernel.org
Cc: Rick Macklem <rmacklem@uoguelph.ca>
Subject: [PATCH v1 04/17] Add support for encoding/decoding POSIX draft ACLs
Date: Tue, 30 Dec 2025 18:21:06 -0800 [thread overview]
Message-ID: <20251231022119.1714-5-rick.macklem@gmail.com> (raw)
In-Reply-To: <20251231022119.1714-1-rick.macklem@gmail.com>
From: Rick Macklem <rmacklem@uoguelph.ca>
This patch adds encoding/decoding of the new attributes described
by the internet draft "POSIX Draft ACL support for Network
File System Version 4, Minor Version 2".
Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca>
---
fs/nfsd/nfs4xdr.c | 292 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 287 insertions(+), 5 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5065727204b9..5f996b3a4ce4 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -43,6 +43,7 @@
#include <linux/sunrpc/addr.h>
#include <linux/xattr.h>
#include <linux/vmalloc.h>
+#include <linux/nfsacl.h>
#include <uapi/linux/xattr.h>
@@ -377,16 +378,123 @@ nfsd4_decode_security_label(struct nfsd4_compoundargs *argp,
return nfs_ok;
}
+static __be32
+nfsacl4_posix_xdrtotag(struct xdr_stream *xdr, u32 *tag)
+{
+ u32 type;
+
+ if (xdr_stream_decode_u32(xdr, &type) < 0)
+ return nfserr_bad_xdr;
+ switch(type) {
+ case POSIXACE4_TAG_USER_OBJ:
+ *tag = ACL_USER_OBJ;
+ break;
+ case POSIXACE4_TAG_GROUP_OBJ:
+ *tag = ACL_GROUP_OBJ;
+ break;
+ case POSIXACE4_TAG_USER:
+ *tag = ACL_USER;
+ break;
+ case POSIXACE4_TAG_GROUP:
+ *tag = ACL_GROUP;
+ break;
+ case POSIXACE4_TAG_MASK:
+ *tag = ACL_MASK;
+ break;
+ case POSIXACE4_TAG_OTHER:
+ *tag = ACL_OTHER;
+ break;
+ default:
+ return nfserr_bad_xdr;
+ }
+ return nfs_ok;
+}
+
+static __be32
+nfsd4_decode_posixace4(struct nfsd4_compoundargs *argp,
+ struct posix_acl_entry *ace)
+{
+ u32 val;
+ __be32 *p, status;
+
+ status = nfsacl4_posix_xdrtotag(argp->xdr, &val);
+ if (status != nfs_ok)
+ return status;
+ ace->e_tag = val;
+ if (xdr_stream_decode_u32(argp->xdr, &val) < 0)
+ return nfserr_bad_xdr;
+ if (val & ~S_IRWXO)
+ return nfserr_bad_xdr;
+ ace->e_perm = val;
+
+ if (xdr_stream_decode_u32(argp->xdr, &val) < 0)
+ return nfserr_bad_xdr;
+ p = xdr_inline_decode(argp->xdr, val);
+ if (!p)
+ return nfserr_bad_xdr;
+ switch(ace->e_tag) {
+ case ACL_USER:
+ status = nfsd_map_name_to_uid(argp->rqstp,
+ (char *)p, val, &ace->e_uid);
+ break;
+ case ACL_GROUP:
+ status = nfsd_map_name_to_gid(argp->rqstp,
+ (char *)p, val, &ace->e_gid);
+ }
+
+ return status;
+}
+
+static noinline __be32
+nfsd4_decode_posix_acl(struct nfsd4_compoundargs *argp, struct posix_acl **acl)
+{
+ struct posix_acl_entry *ace;
+ __be32 status;
+ u32 count;
+
+ if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
+ return nfserr_bad_xdr;
+
+ if (count > xdr_stream_remaining(argp->xdr) / 16)
+ /*
+ * Even with 4-byte names there wouldn't be
+ * space for that many aces; something fishy is
+ * going on:
+ */
+ return nfserr_fbig;
+
+ *acl = posix_acl_alloc(count, GFP_NOFS);
+ if (*acl == NULL)
+ return nfserr_resource;
+
+ (*acl)->a_count = count;
+ for (ace = (*acl)->a_entries; ace < (*acl)->a_entries + count; ace++) {
+ status = nfsd4_decode_posixace4(argp, ace);
+ if (status) {
+ posix_acl_release(*acl);
+ *acl = NULL;
+ return status;
+ }
+ }
+
+ return nfs_ok;
+}
+
static __be32
nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
struct iattr *iattr, struct nfs4_acl **acl,
- struct xdr_netobj *label, int *umask)
+ struct xdr_netobj *label, int *umask,
+ struct posix_acl **dpaclp, struct posix_acl **paclp)
{
unsigned int starting_pos;
u32 attrlist4_count;
__be32 *p, status;
iattr->ia_valid = 0;
+ if (dpaclp)
+ *dpaclp = NULL;
+ if (paclp)
+ *paclp = NULL;
status = nfsd4_decode_bitmap4(argp, bmval, bmlen);
if (status)
return nfserr_bad_xdr;
@@ -542,6 +650,28 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
iattr->ia_valid |= ATTR_CTIME | ATTR_CTIME_SET |
ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG;
}
+ if (bmval[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) {
+ struct posix_acl *dpacl;
+
+ status = nfsd4_decode_posix_acl(argp, &dpacl);
+ if (status)
+ return status;
+ if (dpaclp)
+ *dpaclp = dpacl;
+ else
+ posix_acl_release(dpacl);
+ }
+ if (bmval[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) {
+ struct posix_acl *pacl;
+
+ status = nfsd4_decode_posix_acl(argp, &pacl);
+ if (status)
+ return status;
+ if (paclp)
+ *paclp = pacl;
+ else
+ posix_acl_release(pacl);
+ }
/* request sanity: did attrlist4 contain the expected number of words? */
if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
@@ -849,7 +979,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
status = nfsd4_decode_fattr4(argp, create->cr_bmval,
ARRAY_SIZE(create->cr_bmval),
&create->cr_iattr, &create->cr_acl,
- &create->cr_label, &create->cr_umask);
+ &create->cr_label, &create->cr_umask,
+ NULL, NULL);
if (status)
return status;
@@ -1000,7 +1131,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open
status = nfsd4_decode_fattr4(argp, open->op_bmval,
ARRAY_SIZE(open->op_bmval),
&open->op_iattr, &open->op_acl,
- &open->op_label, &open->op_umask);
+ &open->op_label, &open->op_umask,
+ NULL, NULL);
if (status)
return status;
break;
@@ -1018,7 +1150,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open
status = nfsd4_decode_fattr4(argp, open->op_bmval,
ARRAY_SIZE(open->op_bmval),
&open->op_iattr, &open->op_acl,
- &open->op_label, &open->op_umask);
+ &open->op_label, &open->op_umask,
+ NULL, NULL);
if (status)
return status;
break;
@@ -1345,7 +1478,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
return nfsd4_decode_fattr4(argp, setattr->sa_bmval,
ARRAY_SIZE(setattr->sa_bmval),
&setattr->sa_iattr, &setattr->sa_acl,
- &setattr->sa_label, NULL);
+ &setattr->sa_label, NULL, &setattr->sa_dpacl,
+ &setattr->sa_pacl);
}
static __be32
@@ -2930,6 +3064,8 @@ struct nfsd4_fattr_args {
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
struct lsm_context context;
#endif
+ struct posix_acl *dpacl;
+ struct posix_acl *pacl;
u32 rdattr_err;
bool contextsupport;
bool ignore_crossmnt;
@@ -3470,6 +3606,128 @@ static __be32 nfsd4_encode_fattr4_open_arguments(struct xdr_stream *xdr,
return nfs_ok;
}
+static __be32 nfsd4_encode_fattr4_acl_trueform(struct xdr_stream *xdr,
+ const struct nfsd4_fattr_args *args)
+{
+
+ return nfsd4_encode_uint32_t(xdr, ACL_MODEL_POSIX_DRAFT);
+}
+
+static __be32 nfsd4_encode_fattr4_acl_trueform_scope(struct xdr_stream *xdr,
+ const struct nfsd4_fattr_args *args)
+{
+
+ return nfsd4_encode_uint32_t(xdr, ACL_SCOPE_FILE_SYSTEM);
+}
+
+static int nfsacl4_posix_tagtotype(u32 tag)
+{
+ int type;
+
+ switch(tag) {
+ case ACL_USER_OBJ:
+ type = POSIXACE4_TAG_USER_OBJ;
+ break;
+ case ACL_GROUP_OBJ:
+ type = POSIXACE4_TAG_GROUP_OBJ;
+ break;
+ case ACL_USER:
+ type = POSIXACE4_TAG_USER;
+ break;
+ case ACL_GROUP:
+ type = POSIXACE4_TAG_GROUP;
+ break;
+ case ACL_MASK:
+ type = POSIXACE4_TAG_MASK;
+ break;
+ case ACL_OTHER:
+ type = POSIXACE4_TAG_OTHER;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return type;
+}
+
+static __be32 xdr_nfs4ace_stream_encode(struct xdr_stream *xdr,
+ struct svc_rqst *rqstp,
+ struct posix_acl_entry *acep)
+{
+ __be32 status;
+ int type;
+
+ type = nfsacl4_posix_tagtotype(acep->e_tag);
+ if (type < 0)
+ return nfserr_resource;
+ if (xdr_stream_encode_u32(xdr, type) != XDR_UNIT)
+ return nfserr_resource;
+ if (xdr_stream_encode_u32(xdr, acep->e_perm) != XDR_UNIT)
+ return nfserr_resource;
+ switch(acep->e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT)
+ return nfserr_resource;
+ break;
+ case ACL_USER:
+ status = nfsd4_encode_user(xdr, rqstp, acep->e_uid);
+ if (status != nfs_ok)
+ return status;
+ break;
+ case ACL_GROUP:
+ status = nfsd4_encode_group(xdr, rqstp, acep->e_gid);
+ if (status != nfs_ok)
+ return status;
+ break;
+ default:
+ return nfserr_resource;
+ }
+ return nfs_ok;
+}
+
+static __be32 encode_stream_posixacl(struct xdr_stream *xdr,
+ struct posix_acl *acl,
+ struct svc_rqst *rqstp)
+{
+ __be32 status;
+ int cnt;
+
+ if (acl == NULL) {
+ if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT)
+ return nfserr_resource;
+ return nfs_ok;
+ }
+ if (acl->a_count > NFS_ACL_MAX_ENTRIES)
+ return nfserr_resource;
+ if (xdr_stream_encode_u32(xdr, acl->a_count) != XDR_UNIT)
+ return nfserr_resource;
+
+ for (cnt = 0; cnt < acl->a_count; cnt++) {
+ status = xdr_nfs4ace_stream_encode(xdr, rqstp,
+ &acl->a_entries[cnt]);
+ if (status != nfs_ok)
+ return status;
+ }
+
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_posix_default_acl(struct xdr_stream *xdr,
+ const struct nfsd4_fattr_args *args)
+{
+
+ return encode_stream_posixacl(xdr, args->dpacl, args->rqstp);
+}
+
+static __be32 nfsd4_encode_fattr4_posix_access_acl(struct xdr_stream *xdr,
+ const struct nfsd4_fattr_args *args)
+{
+
+ return encode_stream_posixacl(xdr, args->pacl, args->rqstp);
+}
+
static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
[FATTR4_SUPPORTED_ATTRS] = nfsd4_encode_fattr4_supported_attrs,
[FATTR4_TYPE] = nfsd4_encode_fattr4_type,
@@ -3573,6 +3831,10 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
[FATTR4_TIME_DELEG_ACCESS] = nfsd4_encode_fattr4__inval,
[FATTR4_TIME_DELEG_MODIFY] = nfsd4_encode_fattr4__inval,
[FATTR4_OPEN_ARGUMENTS] = nfsd4_encode_fattr4_open_arguments,
+ [FATTR4_ACL_TRUEFORM] = nfsd4_encode_fattr4_acl_trueform,
+ [FATTR4_ACL_TRUEFORM_SCOPE] = nfsd4_encode_fattr4_acl_trueform_scope,
+ [FATTR4_POSIX_DEFAULT_ACL] = nfsd4_encode_fattr4_posix_default_acl,
+ [FATTR4_POSIX_ACCESS_ACL] = nfsd4_encode_fattr4_posix_access_acl,
};
/*
@@ -3610,6 +3872,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
args.dentry = dentry;
args.ignore_crossmnt = (ignore_crossmnt != 0);
args.acl = NULL;
+ args.pacl = NULL;
+ args.dpacl = NULL;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
args.context.context = NULL;
#endif
@@ -3699,6 +3963,20 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
goto out_nfserr;
}
+ if (attrmask[2] & (FATTR4_WORD2_POSIX_DEFAULT_ACL |
+ FATTR4_WORD2_POSIX_ACCESS_ACL)) {
+ err = nfsd4_get_posix_acl(rqstp, dentry, &args.pacl,
+ &args.dpacl);
+ if (err == -EOPNOTSUPP)
+ attrmask[2] &= ~(FATTR4_WORD2_POSIX_DEFAULT_ACL |
+ FATTR4_WORD2_POSIX_ACCESS_ACL);
+ else if (err == -EINVAL) {
+ status = nfserr_attrnotsupp;
+ goto out;
+ } else if (err != 0)
+ goto out_nfserr;
+ }
+
args.contextsupport = false;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
@@ -3747,6 +4025,10 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
security_release_secctx(&args.context);
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
kfree(args.acl);
+ if (args.pacl)
+ posix_acl_release(args.pacl);
+ if (args.dpacl)
+ posix_acl_release(args.dpacl);
if (tempfh) {
fh_put(tempfh);
kfree(tempfh);
--
2.49.0
next prev parent reply other threads:[~2025-12-31 2:22 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-31 2:21 [PATCH v1 00/17] Add NFSv4.2 POSIX ACL support rick.macklem
2025-12-31 2:21 ` [PATCH v1 01/17] Add definitions for the POSIX draft ACL attributes rick.macklem
2025-12-31 2:21 ` [PATCH v1 02/17] Add a new function to acquire the POSIX draft ACLs rick.macklem
2025-12-31 2:21 ` [PATCH v1 03/17] Add a function to set POSIX ACLs rick.macklem
2025-12-31 2:21 ` rick.macklem [this message]
2025-12-31 2:21 ` [PATCH v1 05/17] Add a check for both POSIX and NFSv4 ACLs being set rick.macklem
2025-12-31 2:21 ` [PATCH v1 06/17] Add na_dpaclerr and na_paclerr for file creation rick.macklem
2025-12-31 2:21 ` [PATCH v1 07/17] Add support for POSIX draft ACLs " rick.macklem
2025-12-31 2:21 ` [PATCH v1 08/17] Add the arguments for decoding of POSIX ACLs rick.macklem
2025-12-31 2:21 ` [PATCH v1 09/17] Fix a couple of bugs in POSIX ACL decoding rick.macklem
2025-12-31 2:21 ` [PATCH v1 10/17] Improve correctness for the ACL_TRUEFORM attribute rick.macklem
2025-12-31 2:21 ` [PATCH v1 11/17] Make sort_pacl_range() global rick.macklem
2025-12-31 2:21 ` [PATCH v1 12/17] Call sort_pacl_range() for decoded POSIX draft ACLs rick.macklem
2025-12-31 2:21 ` [PATCH v1 13/17] Fix handling of POSIX ACLs with zero ACEs rick.macklem
2025-12-31 2:21 ` [PATCH v1 14/17] Fix handling of zero length ACLs for file creation rick.macklem
2025-12-31 2:21 ` [PATCH v1 15/17] Do not allow (N)VERIFY to check POSIX ACL attributes rick.macklem
2025-12-31 2:21 ` [PATCH v1 16/17] Set the POSIX ACL attributes supported rick.macklem
2025-12-31 2:21 ` [PATCH v1 17/17] Change a bunch of function prefixes to nfsd42_ rick.macklem
2025-12-31 2:47 ` [PATCH v1 00/17] Add NFSv4.2 POSIX ACL support Chuck Lever
2025-12-31 2:49 ` Rick Macklem
2025-12-31 2:57 ` Rick Macklem
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251231022119.1714-5-rick.macklem@gmail.com \
--to=rick.macklem@gmail.com \
--cc=linux-nfs@vger.kernel.org \
--cc=rmacklem@uoguelph.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox