[PATCH 4.19 019/293] SUNRPC/nfs: Fix return value for nfs4_callback_compound()

From: Greg Kroah-Hartman
Date: Mon Sep 20 2021 - 13:34:29 EST


From: Trond Myklebust <trondmy@xxxxxxxxx>

commit 83dd59a0b9afc3b1a2642fb5c9b0585b1c08768f upstream.

RPC server procedures are normally expected to return a __be32 encoded
status value of type 'enum rpc_accept_stat', however at least one function
wants to return an authentication status of type 'enum rpc_auth_stat'
in the case where authentication fails.
This patch adds functionality to allow this.

Fixes: a4e187d83d88 ("NFS: Don't drop CB requests with invalid principals")
Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
Signed-off-by: J. Bruce Fields <bfields@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
fs/nfs/callback_xdr.c | 2 +-
include/linux/sunrpc/svc.h | 2 ++
net/sunrpc/svc.c | 27 ++++++++++++++++++++++-----
3 files changed, 25 insertions(+), 6 deletions(-)

--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -991,7 +991,7 @@ static __be32 nfs4_callback_compound(str

out_invalidcred:
pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
- return rpc_autherr_badcred;
+ return svc_return_autherr(rqstp, rpc_autherr_badcred);
}

/*
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -271,6 +271,7 @@ struct svc_rqst {
#define RQ_VICTIM (5) /* about to be shut down */
#define RQ_BUSY (6) /* request is busy */
#define RQ_DATA (7) /* request has data */
+#define RQ_AUTHERR (8) /* Request status is auth error */
unsigned long rq_flags; /* flags field */
ktime_t rq_qtime; /* enqueue time */

@@ -504,6 +505,7 @@ unsigned int svc_fill_write_vector(st
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
struct kvec *first, void *p,
size_t total);
+__be32 svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);

#define RPC_MAX_ADDRBUFLEN (63U)

--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1146,6 +1146,22 @@ static __printf(2,3) void svc_printk(str

extern void svc_tcp_prep_reply_hdr(struct svc_rqst *);

+__be32
+svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err)
+{
+ set_bit(RQ_AUTHERR, &rqstp->rq_flags);
+ return auth_err;
+}
+EXPORT_SYMBOL_GPL(svc_return_autherr);
+
+static __be32
+svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp)
+{
+ if (test_and_clear_bit(RQ_AUTHERR, &rqstp->rq_flags))
+ return *statp;
+ return rpc_auth_ok;
+}
+
/*
* Common routine for processing the RPC request.
*/
@@ -1296,11 +1312,9 @@ svc_process_common(struct svc_rqst *rqst
procp->pc_release(rqstp);
goto dropit;
}
- if (*statp == rpc_autherr_badcred) {
- if (procp->pc_release)
- procp->pc_release(rqstp);
- goto err_bad_auth;
- }
+ auth_stat = svc_get_autherr(rqstp, statp);
+ if (auth_stat != rpc_auth_ok)
+ goto err_release_bad_auth;
if (*statp == rpc_success && procp->pc_encode &&
!procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) {
dprintk("svc: failed to encode reply\n");
@@ -1359,6 +1373,9 @@ err_bad_rpc:
svc_putnl(resv, 2);
goto sendit;

+err_release_bad_auth:
+ if (procp->pc_release)
+ procp->pc_release(rqstp);
err_bad_auth:
dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
serv->sv_stats->rpcbadauth++;