SUNRPC: Set rq_accept_statp inside ->accept methods
authorChuck Lever <chuck.lever@oracle.com>
Sun, 8 Jan 2023 16:31:05 +0000 (11:31 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 20 Feb 2023 14:20:31 +0000 (09:20 -0500)
To navigate around the space that svcauth_gss_accept() reserves
for the RPC payload body length and sequence number fields,
svcauth_gss_release() does a little dance with the reply's
accept_stat, moving the accept_stat value in the response buffer
down by two words.

Instead, let's have the ->accept() methods each set the proper
final location of the accept_stat to avoid having to move
things.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
include/linux/sunrpc/svc.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svc.c
net/sunrpc/svcauth_unix.c

index f40a90c..392d2d2 100644 (file)
@@ -544,4 +544,23 @@ static inline void svcxdr_set_auth_slack(struct svc_rqst *rqstp, int slack)
        WARN_ON(xdr->p > xdr->end);
 }
 
+/**
+ * svcxdr_set_accept_stat - Reserve space for the accept_stat field
+ * @rqstp: RPC transaction context
+ *
+ * Return values:
+ *   %true: Success
+ *   %false: No response buffer space was available
+ */
+static inline bool svcxdr_set_accept_stat(struct svc_rqst *rqstp)
+{
+       struct xdr_stream *xdr = &rqstp->rq_res_stream;
+
+       rqstp->rq_accept_statp = xdr_reserve_space(xdr, XDR_UNIT);
+       if (unlikely(!rqstp->rq_accept_statp))
+               return false;
+       *rqstp->rq_accept_statp = rpc_success;
+       return true;
+}
+
 #endif /* SUNRPC_SVC_H */
index 01080d4..7e7fda9 100644 (file)
@@ -1220,7 +1220,7 @@ svcauth_gss_legacy_init(struct svc_rqst *rqstp,
        if (!svcauth_gss_proc_init_verf(sn->rsc_cache, rqstp, &rsip->out_handle,
                                        &rsip->major_status, GSS_SEQ_WIN))
                goto out;
-       if (xdr_stream_encode_u32(&rqstp->rq_res_stream, RPC_SUCCESS) < 0)
+       if (!svcxdr_set_accept_stat(rqstp))
                goto out;
        if (!svcxdr_encode_gss_init_res(&rqstp->rq_res_stream, &rsip->out_handle,
                                        &rsip->out_token, rsip->major_status,
@@ -1348,7 +1348,7 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
        if (!svcauth_gss_proc_init_verf(sn->rsc_cache, rqstp, &cli_handle,
                                        &ud.major_status, GSS_SEQ_WIN))
                goto out;
-       if (xdr_stream_encode_u32(&rqstp->rq_res_stream, RPC_SUCCESS) < 0)
+       if (!svcxdr_set_accept_stat(rqstp))
                goto out;
        if (!svcxdr_encode_gss_init_res(&rqstp->rq_res_stream, &cli_handle,
                                        &ud.out_token, ud.major_status,
@@ -1640,16 +1640,18 @@ svcauth_gss_accept(struct svc_rqst *rqstp)
        case RPC_GSS_PROC_DESTROY:
                if (!svcauth_gss_encode_verf(rqstp, rsci->mechctx, gc->gc_seq))
                        goto auth_err;
+               if (!svcxdr_set_accept_stat(rqstp))
+                       goto auth_err;
                /* Delete the entry from the cache_list and call cache_put */
                sunrpc_cache_unhash(sn->rsc_cache, &rsci->h);
-               if (xdr_stream_encode_u32(&rqstp->rq_res_stream, RPC_SUCCESS) < 0)
-                       goto auth_err;
                goto complete;
        case RPC_GSS_PROC_DATA:
                rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem;
                svcdata->verf_start = xdr_reserve_space(&rqstp->rq_res_stream, 0);
                if (!svcauth_gss_encode_verf(rqstp, rsci->mechctx, gc->gc_seq))
                        goto auth_err;
+               if (!svcxdr_set_accept_stat(rqstp))
+                       goto auth_err;
                rqstp->rq_cred = rsci->cred;
                get_group_info(rsci->cred.cr_group_info);
                rqstp->rq_auth_stat = rpc_autherr_badcred;
@@ -1706,7 +1708,6 @@ out:
 static __be32 *
 svcauth_gss_prepare_to_wrap(struct svc_rqst *rqstp, struct gss_svc_data *gsd)
 {
-       struct xdr_buf *resbuf = &rqstp->rq_res;
        __be32 *p;
        u32 verf_len;
 
@@ -1721,13 +1722,11 @@ svcauth_gss_prepare_to_wrap(struct svc_rqst *rqstp, struct gss_svc_data *gsd)
        p += 1;
        verf_len = ntohl(*p++);
        p += XDR_QUADLEN(verf_len);
-       /* move accept_stat to right place: */
-       memcpy(p, p + 2, 4);
-       /* Also don't wrap if the accept stat is nonzero: */
-       if (*p != rpc_success) {
-               resbuf->head[0].iov_len -= 2 * 4;
+
+       /* Also don't wrap if the accept_stat is nonzero: */
+       if (*rqstp->rq_accept_statp != rpc_success)
                return NULL;
-       }
+
        p++;
        return p;
 }
index 16760bc..7b208e0 100644 (file)
@@ -1314,8 +1314,6 @@ svc_process_common(struct svc_rqst *rqstp)
        trace_svc_process(rqstp, progp->pg_name);
 
        aoffset = xdr_stream_pos(xdr);
-       rqstp->rq_accept_statp = xdr_reserve_space(&rqstp->rq_res_stream, XDR_UNIT);
-       *rqstp->rq_accept_statp = rpc_success;
 
        /* un-reserve some of the out-queue now that we have a
         * better idea of reply size
index b101700..62dfc8c 100644 (file)
@@ -775,6 +775,8 @@ svcauth_null_accept(struct svc_rqst *rqstp)
        if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream,
                                          RPC_AUTH_NULL, NULL, 0) < 0)
                return SVC_CLOSE;
+       if (!svcxdr_set_accept_stat(rqstp))
+               return SVC_CLOSE;
 
        rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL;
        return SVC_OK;
@@ -866,6 +868,8 @@ svcauth_tls_accept(struct svc_rqst *rqstp)
                                                  RPC_AUTH_NULL, NULL, 0) < 0)
                        return SVC_CLOSE;
        }
+       if (!svcxdr_set_accept_stat(rqstp))
+               return SVC_CLOSE;
 
        rqstp->rq_cred.cr_flavor = RPC_AUTH_TLS;
        return SVC_OK;
@@ -960,6 +964,8 @@ svcauth_unix_accept(struct svc_rqst *rqstp)
        if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream,
                                          RPC_AUTH_NULL, NULL, 0) < 0)
                return SVC_CLOSE;
+       if (!svcxdr_set_accept_stat(rqstp))
+               return SVC_CLOSE;
 
        rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX;
        return SVC_OK;