]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
SUNRPC: Fix a use after free when a server rejects the RPCSEC_GSS credential
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 29 May 2019 16:49:52 +0000 (12:49 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Jun 2019 10:19:15 +0000 (12:19 +0200)
commit 7987b694ade8cc465ce10fb3dceaa614f13ceaf3 upstream.

The addition of rpc_check_timeout() to call_decode causes an Oops
when the RPCSEC_GSS credential is rejected.
The reason is that rpc_decode_header() will call xprt_release() in
order to free task->tk_rqstp, which is needed by rpc_check_timeout()
to check whether or not we should exit due to a soft timeout.

The fix is to move the call to xprt_release() into call_decode() so
we can perform it after rpc_check_timeout().

Reported-by: Olga Kornievskaia <olga.kornievskaia@gmail.com>
Reported-by: Nick Bowler <nbowler@draconx.ca>
Fixes: cea57789e408 ("SUNRPC: Clean up")
Cc: stable@vger.kernel.org # v5.1+
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/sunrpc/clnt.c

index 13dfd3b33b377e35a8f0068ae4ee0af38f5d8881..ea8d5aed1e2c13f025c6e20cd577c9b89ce621a7 100644 (file)
@@ -2387,17 +2387,21 @@ call_decode(struct rpc_task *task)
                return;
        case -EAGAIN:
                task->tk_status = 0;
-               /* Note: rpc_decode_header() may have freed the RPC slot */
-               if (task->tk_rqstp == req) {
-                       xdr_free_bvec(&req->rq_rcv_buf);
-                       req->rq_reply_bytes_recvd = 0;
-                       req->rq_rcv_buf.len = 0;
-                       if (task->tk_client->cl_discrtry)
-                               xprt_conditional_disconnect(req->rq_xprt,
-                                                           req->rq_connect_cookie);
-               }
+               xdr_free_bvec(&req->rq_rcv_buf);
+               req->rq_reply_bytes_recvd = 0;
+               req->rq_rcv_buf.len = 0;
+               if (task->tk_client->cl_discrtry)
+                       xprt_conditional_disconnect(req->rq_xprt,
+                                                   req->rq_connect_cookie);
                task->tk_action = call_encode;
                rpc_check_timeout(task);
+               break;
+       case -EKEYREJECTED:
+               task->tk_action = call_reserve;
+               rpc_check_timeout(task);
+               rpcauth_invalcred(task);
+               /* Ensure we obtain a new XID if we retry! */
+               xprt_release(task);
        }
 }
 
@@ -2533,11 +2537,7 @@ out_msg_denied:
                        break;
                task->tk_cred_retry--;
                trace_rpc__stale_creds(task);
-               rpcauth_invalcred(task);
-               /* Ensure we obtain a new XID! */
-               xprt_release(task);
-               task->tk_action = call_reserve;
-               return -EAGAIN;
+               return -EKEYREJECTED;
        case rpc_autherr_badcred:
        case rpc_autherr_badverf:
                /* possibly garbled cred/verf? */