FAILED: patch "[PATCH] NFSD: map fh_verify() status codes for NFS_ACLv2 replies" failed to apply to 7.3-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 7.3-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-7.3.y
git checkout FETCH_HEAD
git cherry-pick -x ccfc4db5ab740175b9958ea0cf5986957bf4e659
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026110436-sputter-backdrop-7c80@gregkh' --subject-prefix 'PATCH 7.3.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ccfc4db5ab740175b9958ea0cf5986957bf4e659 Mon Sep 17 00:00:00 2001
From: Chuck Lever <[email protected]>
Date: Tue, 15 Sep 2026 20:42:39 -0400
Subject: [PATCH] NFSD: map fh_verify() status codes for NFS_ACLv2 replies
The NFS_ACL v2 protocol shares its status code space with NFSv2, which has no NFSERR_BADHANDLE and no NFSERR_NOFILEHANDLE. An NFS_ACLv2 GETACL, SETACL, GETATTR, or ACCESS request that carries a malformed or empty file handle gets a reply with status 10001 or 10020, values the client cannot interpret.
Commit 1459ad57673b ("nfsd: Move error code mapping to per-version proc code.") removed the version check from fh_verify() that turned those codes into NFSERR_STALE for any version 2 program. The NFSv2 procedures gained nfsd_map_status() in exchange, but the NFS_ACL v2 procedures did not, so the unmapped status reaches the encoder.
Add the same mapping to the NFS_ACL v2 procedures.
fs/nfsd/nfs2acl.c +18 -0
@@ -59,6 +59,20 @@ static const struct nfsd_access_maps nfsd2_access_maps = { .other = nfsd2_otheraccess, }; +static __be32 nfsacld_map_status (__be32 status) +{ +switch (status) { +case nfserr_nofilehandle: +case nfserr_badhandle: + status = nfserr_stale; +break ; +case nfserr_wrongsec: + status = nfserr_acces; +break ; + } +return status; +} +/* * NULL call. */
@@ -123,6 +137,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)/* resp->acl_{access,default} are released in nfssvc_release_getacl. */ out: + resp->status =nfsacld_map_status (resp->status);return rpc_success; fail:
@@ -181,6 +196,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) out:/* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */ + resp->status =nfsacld_map_status (resp->status);return rpc_success; out_drop_lock:
@@ -207,6 +223,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp) goto out; resp->status =fh_getattr (&resp->fh, &resp->stat); out: + resp->status =nfsacld_map_status (resp->status);return rpc_success; }
@@ -231,6 +248,7 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) goto out; resp->status =fh_getattr (&resp->fh, &resp->stat); out: + resp->status =nfsacld_map_status (resp->status);return rpc_success; }
Sasha Levin
maintainerPATCH 1/3 NFSD: Replace nfsd_write()'s "stable" argument with "iocb_flags"
From: Chuck Lever <[email protected]>
[ Upstream commit 7f7dde9a45dfd9b3c9f35cb24aff9e45669071cc ]
The current nfsd_write() API is not NFS version-agnostic, as it relies on callers to pass an NFSv3 stable_how value to determine the persistence of the requested WRITE. NFSv2 does not use a stable-how value on the wire, and NFSv4 has its own stable_how4 (though stable_how and stable_how4 happen to share the same numeric values).
To remove the dependence on NFSv3-specific XDR values from NFSD's generic VFS APIs, replace nfsd_write()'s stable argument with an argument that passes a set of IOCB flags instead of an XDR-defined value.
The NFSv4 WRITE and COPY paths had been borrowing the NFSv3 stable_how constants for their own on-the-wire stable values, relying on the numeric coincidence noted above. Convert those sites to the stable_how4 enumerators so the v4 code expresses its own protocol's values directly, with no change in behavior.
While here, bound-check the decoded NFSv3 WRITE stable value, as the NFSv4 WRITE decoder already does, and make the nfsd3_writeargs stable field unsigned to suit.
The larger benefit is one less NFSv4 dependency on nfs3.h.
Stable-dep-of: ccfc4db5ab74 ("NFSD: map fh_verify() status codes for NFS_ACLv2 replies")
--- fs/nfsd/nfs3proc.c | 17 ++++++++++++++++- fs/nfsd/nfs3xdr.c | 2 ++ fs/nfsd/nfs4proc.c | 18 ++++++++++++++++-- fs/nfsd/nfs4xdr.c | 2 +- fs/nfsd/nfsproc.c | 2 +- fs/nfsd/vfs.c | 30 ++++++++++-------------------- fs/nfsd/vfs.h | 6 ++++-- fs/nfsd/xdr3.h | 2 +- include/linux/nfs4.h | 6 ++++++ 9 files changed, 57 insertions(+), 28 deletions(-)
fs/nfsd/nfs3proc.c +16 -1
@@ -48,6 +48,20 @@ static bool nfsd3_time_in_range(const struct iattr *iap)return true; } +static int nfsd3_iocb_flags (enum nfs3_stable_how how) +{ +switch (how) { +case NFS_FILE_SYNC : +/* persist data and timestamps */ +return IOCB_DSYNC |IOCB_SYNC ; +case NFS_DATA_SYNC : +/* persist data only */ +return IOCB_DSYNC ; +default : +return 0 ; + } +} +static __be32 nfsd3_map_status (__be32 status) {switch (status) {
@@ -260,7 +274,8 @@ nfsd3_proc_write(struct svc_rqst *rqstp) resp->committed = argp->stable; resp->status =nfsd_write (rqstp, &resp->fh, argp->offset, &argp->payload, &cnt, - resp->committed, resp->verf); +nfsd3_iocb_flags (resp->committed), + resp->verf); resp->count = cnt; resp->status =nfsd3_map_status (resp->status);return rpc_success;
fs/nfsd/nfs3xdr.c +2 -0
@@ -556,6 +556,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)return false;if (xdr_stream_decode_u32 (xdr, &args->stable) <0 )return false; +if (args->stable >NFS_FILE_SYNC ) +return false;/* opaque data */ if (xdr_stream_decode_u32 (xdr, &args->len) <0 )
fs/nfsd/nfs4proc.c +16 -2
@@ -69,6 +69,20 @@ MODULE_PARM_DESC(nfsd4_ssc_umount_timeout,#define NFSDDBG_FACILITY NFSDDBG_PROC +static int nfsd4_iocb_flags (enum stable_how4 how) +{ +switch (how) { +case FILE_SYNC4 : +/* persist data and timestamps */ +return IOCB_DSYNC |IOCB_SYNC ; +case DATA_SYNC4 : +/* persist data only */ +return IOCB_DSYNC ; +default : +return 0 ; + } +} +static u32 nfsd_attrmask[] = {NFSD_WRITEABLE_ATTRS_WORD0 ,NFSD_WRITEABLE_ATTRS_WORD1 ,
@@ -1377,7 +1391,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, write->wr_how_written = write->wr_stable_how; status =nfsd_vfs_write (rqstp, &cstate->current_fh, nf, write->wr_offset, &write->wr_payload, - &cnt, write->wr_how_written, + &cnt,nfsd4_iocb_flags (write->wr_how_written), (__be32 *)write->wr_verifier.data);nfsd_file_put (nf);
@@ -1974,7 +1988,7 @@ static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) { copy->cp_res.wr_stable_how =test_bit (NFSD4_COPY_F_COMMITTED , ©->cp_flags) ? -NFS_FILE_SYNC :NFS_UNSTABLE ; +FILE_SYNC4 :UNSTABLE4 ;nfsd4_copy_set_sync (copy, sync); }
fs/nfsd/nfs4xdr.c +1 -1
@@ -1606,7 +1606,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)return nfserr_bad_xdr;if (xdr_stream_decode_u32 (argp->xdr, &write->wr_stable_how) <0 )return nfserr_bad_xdr; -if (write->wr_stable_how >NFS_FILE_SYNC ) +if (write->wr_stable_how >FILE_SYNC4 )return nfserr_bad_xdr;if (xdr_stream_decode_u32 (argp->xdr, &write->wr_buflen) <0 )return nfserr_bad_xdr;
fs/nfsd/nfsproc.c +1 -1
@@ -280,7 +280,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)fh_copy (&resp->fh, &argp->fh); resp->status =nfsd_write (rqstp, &resp->fh, argp->offset, - &argp->payload, &cnt,NFS_DATA_SYNC ,NULL ); + &argp->payload, &cnt,IOCB_DSYNC ,NULL );if (resp->status == nfs_ok) resp->status =fh_getattr (&resp->fh, &resp->stat);else if (resp->status == nfserr_jukebox)
fs/nfsd/vfs.c +10 -20
@@ -1424,7 +1424,7 @@ nfsd_direct_write(struct svc_rqst *rqstp, struct svc_fh *fhp,* @offset: Byte offset of start * @payload: xdr_buf containing the write payload * @cnt: IN: number of bytes to write, OUT: number of bytes actually written -* @stable: An NFS stable_how value +* @iocb_flags: VFS IOCB_* flags expressing the requested write stability * @verf: NFS WRITE verifier * * Upon return, caller must invoke fh_put on @fhp.
@@ -1436,7 +1436,7 @@ __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, loff_t offset, const struct xdr_buf *payload, unsigned long *cnt, - int stable, __be32 *verf) + int iocb_flags, __be32 *verf) { struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);struct file *file = nf->nf_file;
@@ -1473,21 +1473,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, exp = fhp->fh_export;if (!EX_ISSYNC (exp)) - stable =NFS_UNSTABLE ; + iocb_flags =0 ;init_sync_kiocb (&kiocb, file); kiocb.ki_pos = offset; -if (likely (!fhp->fh_use_wgather)) { -switch (stable) { -case NFS_FILE_SYNC : -/* persist data and timestamps */ - kiocb.ki_flags |=IOCB_DSYNC |IOCB_SYNC ; -break ; -case NFS_DATA_SYNC : -/* persist data only */ - kiocb.ki_flags |=IOCB_DSYNC ; -break ; - } - } +if (likely (!fhp->fh_use_wgather)) + kiocb.ki_flags |= iocb_flags; nvecs =xdr_buf_to_bvec (rqstp->rq_bvec, rqstp->rq_maxpages, payload);if (nvecs <0 ) {
@@ -1528,7 +1518,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out_nfserr; } -if (stable && fhp->fh_use_wgather) { +if (iocb_flags && fhp->fh_use_wgather) { host_err =wait_for_concurrent_writes (file);if (host_err <0 )commit_reset_write_verifier (nn, rqstp, host_err);
@@ -1619,7 +1609,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,* @offset: Byte offset of start * @payload: xdr_buf containing the write payload * @cnt: IN: number of bytes to write, OUT: number of bytes actually written -* @stable: An NFS stable_how value +* @iocb_flags: VFS IOCB_* flags expressing the requested write stability * @verf: NFS WRITE verifier * * Upon return, caller must invoke fh_put on @fhp.
@@ -1629,8 +1619,8 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,*/ __be32 nfsd_write (struct svc_rqst *rqstp,struct svc_fh *fhp,loff_t offset, -const struct xdr_buf *payload,unsigned long *cnt,int stable, -__be32 *verf) +const struct xdr_buf *payload,unsigned long *cnt, +int iocb_flags,__be32 *verf) {struct nfsd_file *nf;__be32 err;
@@ -1642,7 +1632,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, goto out; err =nfsd_vfs_write (rqstp, fhp, nf, offset, payload, cnt, - stable, verf); + iocb_flags, verf);nfsd_file_put (nf); out:trace_nfsd_write_done (rqstp, fhp, offset, *cnt);
fs/nfsd/vfs.h +4 -2
@@ -135,11 +135,13 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *eof);__be32 nfsd_write (struct svc_rqst *rqstp,struct svc_fh *fhp,loff_t offset,const struct xdr_buf *payload, -unsigned long *cnt,int stable,__be32 *verf); +unsigned long *cnt,int iocb_flags, +__be32 *verf);__be32 nfsd_vfs_write (struct svc_rqst *rqstp,struct svc_fh *fhp,struct nfsd_file *nf,loff_t offset,const struct xdr_buf *payload, -unsigned long *cnt,int stable,__be32 *verf); +unsigned long *cnt,int iocb_flags, +__be32 *verf);__be32 nfsd_readlink (struct svc_rqst *,struct svc_fh *,char *,int *); __be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
fs/nfsd/xdr3.h +1 -1
@@ -39,7 +39,7 @@ struct nfsd3_writeargs {svc_fh fh;__u64 offset;__u32 count; -int stable; +__u32 stable;__u32 len;struct xdr_buf payload; };
include/linux/nfs4.h +6 -0
@@ -263,6 +263,12 @@ enum why_no_delegation4 { /* new to v4.1 */ WND4_IS_DIR = 8, }; +enum stable_how4 { +UNSTABLE4 =0 , +DATA_SYNC4 =1 , +FILE_SYNC4 =2 , +}; +enum lock_type4 {NFS4_UNLOCK_LT =0 ,NFS4_READ_LT =1 ,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 NFSD: Move version-specific ACCESS maps into per-version code
From: Chuck Lever <[email protected]>
[ Upstream commit 3423b5f91d80d3a76424e1c9f1d0f95d4dd80101 ]
nfsd_access() owns three static tables that map on-the-wire ACCESS bits to NFSD_MAY flags, and every NFS version shares them. That puts protocol-version specifics in the version-agnostic VFS layer. The NFSv4.2 extended-attribute bits are wedged into the NFSv3 tables under CONFIG_NFSD_V4.
Give each version its own tables in its proc code and pass the matching set into nfsd_access() as a new argument.
Splitting the tables also stops the NFSv2-ACL and NFSv3 ACCESS paths from answering for the NFSv4.2 extended-attribute bits. Both use the NFSv4-augmented table whenever CONFIG_NFSD_V4 is set, so an NFSv3 request that sets an xattr bit has it echoed back in the reply even though those bits are undefined for v3.
Stable-dep-of: ccfc4db5ab74 ("NFSD: map fh_verify() status codes for NFS_ACLv2 replies")
--- fs/nfsd/nfs2acl.c | 46 ++++++++++++++++++++++++++- fs/nfsd/nfs3proc.c | 41 +++++++++++++++++++++++- fs/nfsd/nfs4proc.c | 42 +++++++++++++++++++++++-- fs/nfsd/vfs.c | 78 ++++++++++------------------------------------ fs/nfsd/vfs.h | 15 ++++++++- 5 files changed, 155 insertions(+), 67 deletions(-)
fs/nfsd/nfs2acl.c +45 -1
@@ -15,6 +15,48 @@#define NFSDDBG_FACILITY NFSDDBG_PROC +/* +* These maps are identical to the NFSv3 maps (nfs3proc.c). This enables +* the behavior of the two versions to diverge if needed. +*/ +static const struct nfsd_access_map nfsd2_regaccess[] = { + {NFS3_ACCESS_READ ,NFSD_MAY_READ }, + {NFS3_ACCESS_EXECUTE ,NFSD_MAY_EXEC }, + {NFS3_ACCESS_MODIFY ,NFSD_MAY_WRITE |NFSD_MAY_TRUNC }, + {NFS3_ACCESS_EXTEND ,NFSD_MAY_WRITE }, + {0 ,0 } +}; + +static const struct nfsd_access_map nfsd2_diraccess[] = { + {NFS3_ACCESS_READ ,NFSD_MAY_READ }, + {NFS3_ACCESS_LOOKUP ,NFSD_MAY_EXEC }, + {NFS3_ACCESS_MODIFY ,NFSD_MAY_EXEC |NFSD_MAY_WRITE |NFSD_MAY_TRUNC }, + {NFS3_ACCESS_EXTEND ,NFSD_MAY_EXEC |NFSD_MAY_WRITE }, + {NFS3_ACCESS_DELETE ,NFSD_MAY_REMOVE }, + {0 ,0 } +}; + +/* +* Some clients - Solaris 2.6 at least, make an access call to the NFS +* server to check for access for things like /dev/null (which really, +* NFSD doesn't care about). So NFSD provides simple access checking +* for those objects, looking mainly at mode bits, ignoring read-only +* filesystem checks. +*/ +static const struct nfsd_access_map nfsd2_otheraccess[] = { + {NFS3_ACCESS_READ ,NFSD_MAY_READ }, + {NFS3_ACCESS_EXECUTE ,NFSD_MAY_EXEC }, + {NFS3_ACCESS_MODIFY ,NFSD_MAY_WRITE |NFSD_MAY_LOCAL_ACCESS }, + {NFS3_ACCESS_EXTEND ,NFSD_MAY_WRITE |NFSD_MAY_LOCAL_ACCESS }, + {0 ,0 } +}; + +static const struct nfsd_access_maps nfsd2_access_maps = { + .regular = nfsd2_regaccess, + .directory = nfsd2_diraccess, + .other = nfsd2_otheraccess, +}; +/* * NULL call. */
@@ -180,7 +222,9 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)fh_copy (&resp->fh, &argp->fh); resp->access = argp->access; - resp->status =nfsd_access (rqstp, &resp->fh, &resp->access,NULL ); + + resp->status =nfsd_access (rqstp, &resp->fh, &nfsd2_access_maps, + &resp->access,NULL );if (resp->status != nfs_ok) goto out; resp->status =fh_getattr (&resp->fh, &resp->stat);
fs/nfsd/nfs3proc.c +40 -1
53 lines not on this page · raw message
fs/nfsd/nfs4proc.c +39 -3
55 lines not on this page · raw message
fs/nfsd/vfs.c +17 -61
100 lines not on this page · raw message
fs/nfsd/vfs.h +14 -1
@@ -37,6 +37,17 @@#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) +struct nfsd_access_map { +u32 access; +int may; +}; + +struct nfsd_access_maps { +const struct nfsd_access_map *regular; +const struct nfsd_access_map *directory; +const struct nfsd_access_map *other; +}; +struct nfsd_file ;/*
@@ -100,7 +111,9 @@ __be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *,__be32 nfsd_create (struct svc_rqst *,struct svc_fh *,char *name,int len,struct nfsd_attrs *attrs,int type,dev_t rdev,struct svc_fh *res); -__be32 nfsd_access (struct svc_rqst *,struct svc_fh *,u32 *,u32 *); +__be32 nfsd_access (struct svc_rqst *rqstp,struct svc_fh *fhp, +const struct nfsd_access_maps *maps, +u32 *access,u32 *supported);__be32 nfsd_create_setattr (struct svc_rqst *rqstp,struct svc_fh *fhp,struct svc_fh *resfhp,struct nfsd_attrs *iap); __be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 NFSD: map fh_verify() status codes for NFS_ACLv2 replies
In reply to Sasha LevinFrom: Chuck Lever <[email protected]>
[ Upstream commit ccfc4db5ab740175b9958ea0cf5986957bf4e659 ]
The NFS_ACL v2 protocol shares its status code space with NFSv2, which has no NFSERR_BADHANDLE and no NFSERR_NOFILEHANDLE. An NFS_ACLv2 GETACL, SETACL, GETATTR, or ACCESS request that carries a malformed or empty file handle gets a reply with status 10001 or 10020, values the client cannot interpret.
Commit 1459ad57673b ("nfsd: Move error code mapping to per-version proc code.") removed the version check from fh_verify() that turned those codes into NFSERR_STALE for any version 2 program. The NFSv2 procedures gained nfsd_map_status() in exchange, but the NFS_ACL v2 procedures did not, so the unmapped status reaches the encoder.
Add the same mapping to the NFS_ACL v2 procedures.
--- fs/nfsd/nfs2acl.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
fs/nfsd/nfs2acl.c +18 -0
@@ -57,6 +57,20 @@ static const struct nfsd_access_maps nfsd2_access_maps = { .other = nfsd2_otheraccess, }; +static __be32 nfsacld_map_status (__be32 status) +{ +switch (status) { +case nfserr_nofilehandle: +case nfserr_badhandle: + status = nfserr_stale; +break ; +case nfserr_wrongsec: + status = nfserr_acces; +break ; + } +return status; +} +/* * NULL call. */
@@ -121,6 +135,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)/* resp->acl_{access,default} are released in nfssvc_release_getacl. */ out: + resp->status =nfsacld_map_status (resp->status);return rpc_success; fail:
@@ -179,6 +194,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) out:/* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */ + resp->status =nfsacld_map_status (resp->status);return rpc_success; out_drop_lock:
@@ -205,6 +221,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp) goto out; resp->status =fh_getattr (&resp->fh, &resp->stat); out: + resp->status =nfsacld_map_status (resp->status);return rpc_success; }
@@ -229,6 +246,7 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) goto out; resp->status =fh_getattr (&resp->fh, &resp->stat); out: + resp->status =nfsacld_map_status (resp->status);return rpc_success; }
Signature · 1 line
2.53.0