* [PATCH v1 0/2] nfs_common: Encode an ACL with fewer than three entries as empty
@ 2026-09-24 21:22 Chuck Lever
2026-09-24 21:22 ` [PATCH v1 1/2] nfs_common: Do not encode an ACL with fewer than three entries Chuck Lever
2026-09-24 21:22 ` [PATCH v1 2/2] nfs_common: Do not stream-encode " Chuck Lever
0 siblings, 2 replies; 4+ messages in thread
From: Chuck Lever @ 2026-09-24 21:22 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker
Cc: linux-nfs
Both ACL encoders in fs/nfs_common report at least four wire entries
for any ACL that has entries, then walk a_entries[] up to that count.
An ACL with one or two entries sends the walk past the end of the
posix_acl allocation.
nfsacl_encode() builds only the NFS client's SETACL arguments, and
nfs_stream_encode_acl() builds only NFSD's GETACL replies. The fixes
are separate patches because a combined one does not apply to the
stable trees that predate nfs_stream_encode_acl().
The NFS client still caches a GETACL result without validating it.
This series does not change that.
Neither over-read has been observed at runtime. Both paths were
traced from the code, and the patches are build-tested only.
Patch 1 changes what the NFS client sends in SETACL, so it needs an
Acked-by from the NFS client maintainers before it goes through the
nfsd tree.
Chuck Lever (2):
nfs_common: Do not encode an ACL with fewer than three entries
nfs_common: Do not stream-encode an ACL with fewer than three entries
fs/nfs_common/nfsacl.c | 6 ++++--
include/linux/nfsacl.h | 5 +++--
2 files changed, 7 insertions(+), 4 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v1 1/2] nfs_common: Do not encode an ACL with fewer than three entries
2026-09-24 21:22 [PATCH v1 0/2] nfs_common: Encode an ACL with fewer than three entries as empty Chuck Lever
@ 2026-09-24 21:22 ` Chuck Lever
2026-10-02 17:24 ` Anna Schumaker
2026-09-24 21:22 ` [PATCH v1 2/2] nfs_common: Do not stream-encode " Chuck Lever
1 sibling, 1 reply; 4+ messages in thread
From: Chuck Lever @ 2026-09-24 21:22 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker
Cc: linux-nfs
nfsacl_encode() reports at least four wire entries for any ACL
that has entries, because a three-entry ACL is sent as four with a
synthesized ACL_MASK. The entry encoder then walks a_entries[] up
to that count.
A one- or two-entry ACL cannot arrive from setfacl, because
set_posix_acl() validates it first. It can arrive from an NFS
server. The NFS client caches a GETACL result without validating
it, and posix_acl_create() hands the cached default ACL to
nfs3_proc_setacls() when the client creates a directory. The walk
then reads past the end of the posix_acl allocation and copies the
bytes into the SETACL arguments.
Report zero wire entries for an ACL with fewer than three, the
same as for an ACL with none. Count them the same way in
nfsacl_size(), which otherwise sizes such an ACL at four entries
and leaves the reserved bytes unwritten in the SETACL arguments.
Fixes: a257cdd0e217 ("[PATCH] NFSD: Add server support for NFSv3 ACLs.")
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfs_common/nfsacl.c | 3 ++-
include/linux/nfsacl.h | 5 +++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index e2eaac14fd8e..38bb2c294d7c 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -93,7 +93,8 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
struct posix_acl *acl, int encode_entries, int typeflag)
{
- int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
+ int entries = (acl && acl->a_count >= 3) ?
+ max_t(int, acl->a_count, 4) : 0;
struct nfsacl_encode_desc nfsacl_desc = {
.desc = {
.elem_size = 12,
diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h
index 8e76a79cdc6a..e4155e69c8dd 100644
--- a/include/linux/nfsacl.h
+++ b/include/linux/nfsacl.h
@@ -26,8 +26,9 @@ static inline unsigned int
nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
{
unsigned int w = 16;
- w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12;
- if (acl_default)
+ if (acl_access && acl_access->a_count >= 3)
+ w += max((int)acl_access->a_count, 4) * 12;
+ if (acl_default && acl_default->a_count >= 3)
w += max((int)acl_default->a_count, 4) * 12;
return w;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v1 2/2] nfs_common: Do not stream-encode an ACL with fewer than three entries
2026-09-24 21:22 [PATCH v1 0/2] nfs_common: Encode an ACL with fewer than three entries as empty Chuck Lever
2026-09-24 21:22 ` [PATCH v1 1/2] nfs_common: Do not encode an ACL with fewer than three entries Chuck Lever
@ 2026-09-24 21:22 ` Chuck Lever
1 sibling, 0 replies; 4+ messages in thread
From: Chuck Lever @ 2026-09-24 21:22 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker
Cc: linux-nfs
nfs_stream_encode_acl() reports at least four wire entries for any
ACL that has entries, because a three-entry ACL is sent as four
with a synthesized ACL_MASK. The entry encoder then walks
a_entries[] up to that count. For an ACL with one or two entries,
which posix_acl_from_xattr() and the filesystem on-disk parsers do
not reject, the walk reads past the end of the posix_acl
allocation and copies the bytes into the GETACL reply.
Report zero wire entries for an ACL with fewer than three, the
same as for an ACL with none.
Fixes: 8edc0648880a ("NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs")
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfs_common/nfsacl.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index 38bb2c294d7c..24ee7f622b18 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -157,7 +157,8 @@ bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode,
int typeflag)
{
const size_t elem_size = XDR_UNIT * 3;
- u32 entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
+ u32 entries = (acl && acl->a_count >= 3) ?
+ max_t(int, acl->a_count, 4) : 0;
struct nfsacl_encode_desc nfsacl_desc = {
.desc = {
.elem_size = elem_size,
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v1 1/2] nfs_common: Do not encode an ACL with fewer than three entries
2026-09-24 21:22 ` [PATCH v1 1/2] nfs_common: Do not encode an ACL with fewer than three entries Chuck Lever
@ 2026-10-02 17:24 ` Anna Schumaker
0 siblings, 0 replies; 4+ messages in thread
From: Anna Schumaker @ 2026-10-02 17:24 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo,
Tom Talpey, Trond Myklebust
Cc: linux-nfs
On Thu, Sep 24, 2026, at 5:22 PM, Chuck Lever wrote:
> nfsacl_encode() reports at least four wire entries for any ACL
> that has entries, because a three-entry ACL is sent as four with a
> synthesized ACL_MASK. The entry encoder then walks a_entries[] up
> to that count.
>
> A one- or two-entry ACL cannot arrive from setfacl, because
> set_posix_acl() validates it first. It can arrive from an NFS
> server. The NFS client caches a GETACL result without validating
> it, and posix_acl_create() hands the cached default ACL to
> nfs3_proc_setacls() when the client creates a directory. The walk
> then reads past the end of the posix_acl allocation and copies the
> bytes into the SETACL arguments.
>
> Report zero wire entries for an ACL with fewer than three, the
> same as for an ACL with none. Count them the same way in
> nfsacl_size(), which otherwise sizes such an ACL at four entries
> and leaves the reserved bytes unwritten in the SETACL arguments.
>
> Fixes: a257cdd0e217 ("[PATCH] NFSD: Add server support for NFSv3 ACLs.")
> Signed-off-by: Chuck Lever <cel@kernel.org>
Acked-by: Anna Schumaker <anna.schumaker@hammerspace.com>
> ---
> fs/nfs_common/nfsacl.c | 3 ++-
> include/linux/nfsacl.h | 5 +++--
> 2 files changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
> index e2eaac14fd8e..38bb2c294d7c 100644
> --- a/fs/nfs_common/nfsacl.c
> +++ b/fs/nfs_common/nfsacl.c
> @@ -93,7 +93,8 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
> int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
> struct posix_acl *acl, int encode_entries, int typeflag)
> {
> - int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
> + int entries = (acl && acl->a_count >= 3) ?
> + max_t(int, acl->a_count, 4) : 0;
> struct nfsacl_encode_desc nfsacl_desc = {
> .desc = {
> .elem_size = 12,
> diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h
> index 8e76a79cdc6a..e4155e69c8dd 100644
> --- a/include/linux/nfsacl.h
> +++ b/include/linux/nfsacl.h
> @@ -26,8 +26,9 @@ static inline unsigned int
> nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
> {
> unsigned int w = 16;
> - w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12;
> - if (acl_default)
> + if (acl_access && acl_access->a_count >= 3)
> + w += max((int)acl_access->a_count, 4) * 12;
> + if (acl_default && acl_default->a_count >= 3)
> w += max((int)acl_default->a_count, 4) * 12;
> return w;
> }
> --
> 2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-02 17:24 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-24 21:22 [PATCH v1 0/2] nfs_common: Encode an ACL with fewer than three entries as empty Chuck Lever
2026-09-24 21:22 ` [PATCH v1 1/2] nfs_common: Do not encode an ACL with fewer than three entries Chuck Lever
2026-10-02 17:24 ` Anna Schumaker
2026-09-24 21:22 ` [PATCH v1 2/2] nfs_common: Do not stream-encode " Chuck Lever
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox