NFSD: Add an xdr_stream-based decoder for NFSv2/3 ACLs
authorChuck Lever <chuck.lever@oracle.com>
Tue, 17 Nov 2020 15:38:46 +0000 (10:38 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 25 Jan 2021 14:36:27 +0000 (09:36 -0500)
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfs_common/nfsacl.c
include/linux/nfsacl.h

index d056ad2..79c563c 100644 (file)
@@ -295,3 +295,55 @@ int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
                   nfsacl_desc.desc.array_len;
 }
 EXPORT_SYMBOL_GPL(nfsacl_decode);
+
+/**
+ * nfs_stream_decode_acl - Decode an NFSv3 ACL
+ *
+ * @xdr: an xdr_stream positioned at an encoded ACL
+ * @aclcnt: OUT: count of ACEs in decoded posix_acl
+ * @pacl: OUT: a dynamically-allocated buffer containing the decoded posix_acl
+ *
+ * Return values:
+ *   %false: The encoded ACL is not valid
+ *   %true: @pacl contains a decoded ACL, and @xdr is advanced
+ *
+ * On a successful return, caller must release *pacl using posix_acl_release().
+ */
+bool nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt,
+                          struct posix_acl **pacl)
+{
+       const size_t elem_size = XDR_UNIT * 3;
+       struct nfsacl_decode_desc nfsacl_desc = {
+               .desc = {
+                       .elem_size = elem_size,
+                       .xcode = pacl ? xdr_nfsace_decode : NULL,
+               },
+       };
+       unsigned int base;
+       u32 entries;
+
+       if (xdr_stream_decode_u32(xdr, &entries) < 0)
+               return false;
+       if (entries > NFS_ACL_MAX_ENTRIES)
+               return false;
+
+       base = xdr_stream_pos(xdr);
+       if (!xdr_inline_decode(xdr, XDR_UNIT + elem_size * entries))
+               return false;
+       nfsacl_desc.desc.array_maxlen = entries;
+       if (xdr_decode_array2(xdr->buf, base, &nfsacl_desc.desc))
+               return false;
+
+       if (pacl) {
+               if (entries != nfsacl_desc.desc.array_len ||
+                   posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
+                       posix_acl_release(nfsacl_desc.acl);
+                       return false;
+               }
+               *pacl = nfsacl_desc.acl;
+       }
+       if (aclcnt)
+               *aclcnt = entries;
+       return true;
+}
+EXPORT_SYMBOL_GPL(nfs_stream_decode_acl);
index 103d446..0ba99c5 100644 (file)
@@ -38,5 +38,8 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
 extern int
 nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
              struct posix_acl **pacl);
+extern bool
+nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt,
+                     struct posix_acl **pacl);
 
 #endif  /* __LINUX_NFSACL_H */