diff options
author | Trond Myklebust <trondmy@gmail.com> | 2019-09-10 13:01:35 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2019-09-17 15:14:11 -0400 |
commit | cc204d01262a69218b2d0db5cdea371de85871d9 (patch) | |
tree | 7f77b71e876ff7e2007c45be58e29a28f2633ccb | |
parent | 98ef77d1aaa7a2f4e1b2a721faa084222021fda7 (diff) |
SUNRPC: Dequeue the request from the receive queue while we're re-encoding
Ensure that we dequeue the request from the transport receive queue
while we're re-encoding to prevent issues like use-after-free when
we release the bvec.
Fixes: 7536908982047 ("SUNRPC: Ensure the bvecs are reset when we re-encode...")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: stable@vger.kernel.org # v4.20+
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r-- | include/linux/sunrpc/xprt.h | 1 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 6 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 54 |
3 files changed, 35 insertions, 26 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 13e108bcc9eb..d783e15ba898 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -352,6 +352,7 @@ bool xprt_prepare_transmit(struct rpc_task *task); | |||
352 | void xprt_request_enqueue_transmit(struct rpc_task *task); | 352 | void xprt_request_enqueue_transmit(struct rpc_task *task); |
353 | void xprt_request_enqueue_receive(struct rpc_task *task); | 353 | void xprt_request_enqueue_receive(struct rpc_task *task); |
354 | void xprt_request_wait_receive(struct rpc_task *task); | 354 | void xprt_request_wait_receive(struct rpc_task *task); |
355 | void xprt_request_dequeue_xprt(struct rpc_task *task); | ||
355 | bool xprt_request_need_retransmit(struct rpc_task *task); | 356 | bool xprt_request_need_retransmit(struct rpc_task *task); |
356 | void xprt_transmit(struct rpc_task *task); | 357 | void xprt_transmit(struct rpc_task *task); |
357 | void xprt_end_transmit(struct rpc_task *task); | 358 | void xprt_end_transmit(struct rpc_task *task); |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d8679b6027e9..0359466947e2 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1862,6 +1862,7 @@ rpc_xdr_encode(struct rpc_task *task) | |||
1862 | req->rq_rbuffer, | 1862 | req->rq_rbuffer, |
1863 | req->rq_rcvsize); | 1863 | req->rq_rcvsize); |
1864 | 1864 | ||
1865 | req->rq_reply_bytes_recvd = 0; | ||
1865 | req->rq_snd_buf.head[0].iov_len = 0; | 1866 | req->rq_snd_buf.head[0].iov_len = 0; |
1866 | xdr_init_encode(&xdr, &req->rq_snd_buf, | 1867 | xdr_init_encode(&xdr, &req->rq_snd_buf, |
1867 | req->rq_snd_buf.head[0].iov_base, req); | 1868 | req->rq_snd_buf.head[0].iov_base, req); |
@@ -1881,6 +1882,8 @@ call_encode(struct rpc_task *task) | |||
1881 | if (!rpc_task_need_encode(task)) | 1882 | if (!rpc_task_need_encode(task)) |
1882 | goto out; | 1883 | goto out; |
1883 | dprint_status(task); | 1884 | dprint_status(task); |
1885 | /* Dequeue task from the receive queue while we're encoding */ | ||
1886 | xprt_request_dequeue_xprt(task); | ||
1884 | /* Encode here so that rpcsec_gss can use correct sequence number. */ | 1887 | /* Encode here so that rpcsec_gss can use correct sequence number. */ |
1885 | rpc_xdr_encode(task); | 1888 | rpc_xdr_encode(task); |
1886 | /* Did the encode result in an error condition? */ | 1889 | /* Did the encode result in an error condition? */ |
@@ -2501,9 +2504,6 @@ call_decode(struct rpc_task *task) | |||
2501 | return; | 2504 | return; |
2502 | case -EAGAIN: | 2505 | case -EAGAIN: |
2503 | task->tk_status = 0; | 2506 | task->tk_status = 0; |
2504 | xdr_free_bvec(&req->rq_rcv_buf); | ||
2505 | req->rq_reply_bytes_recvd = 0; | ||
2506 | req->rq_rcv_buf.len = 0; | ||
2507 | if (task->tk_client->cl_discrtry) | 2507 | if (task->tk_client->cl_discrtry) |
2508 | xprt_conditional_disconnect(req->rq_xprt, | 2508 | xprt_conditional_disconnect(req->rq_xprt, |
2509 | req->rq_connect_cookie); | 2509 | req->rq_connect_cookie); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 783748dc5e6f..02d5b2125c07 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -1324,6 +1324,36 @@ xprt_request_dequeue_transmit(struct rpc_task *task) | |||
1324 | } | 1324 | } |
1325 | 1325 | ||
1326 | /** | 1326 | /** |
1327 | * xprt_request_dequeue_xprt - remove a task from the transmit+receive queue | ||
1328 | * @task: pointer to rpc_task | ||
1329 | * | ||
1330 | * Remove a task from the transmit and receive queues, and ensure that | ||
1331 | * it is not pinned by the receive work item. | ||
1332 | */ | ||
1333 | void | ||
1334 | xprt_request_dequeue_xprt(struct rpc_task *task) | ||
1335 | { | ||
1336 | struct rpc_rqst *req = task->tk_rqstp; | ||
1337 | struct rpc_xprt *xprt = req->rq_xprt; | ||
1338 | |||
1339 | if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) || | ||
1340 | test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) || | ||
1341 | xprt_is_pinned_rqst(req)) { | ||
1342 | spin_lock(&xprt->queue_lock); | ||
1343 | xprt_request_dequeue_transmit_locked(task); | ||
1344 | xprt_request_dequeue_receive_locked(task); | ||
1345 | while (xprt_is_pinned_rqst(req)) { | ||
1346 | set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); | ||
1347 | spin_unlock(&xprt->queue_lock); | ||
1348 | xprt_wait_on_pinned_rqst(req); | ||
1349 | spin_lock(&xprt->queue_lock); | ||
1350 | clear_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); | ||
1351 | } | ||
1352 | spin_unlock(&xprt->queue_lock); | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | /** | ||
1327 | * xprt_request_prepare - prepare an encoded request for transport | 1357 | * xprt_request_prepare - prepare an encoded request for transport |
1328 | * @req: pointer to rpc_rqst | 1358 | * @req: pointer to rpc_rqst |
1329 | * | 1359 | * |
@@ -1754,28 +1784,6 @@ void xprt_retry_reserve(struct rpc_task *task) | |||
1754 | xprt_do_reserve(xprt, task); | 1784 | xprt_do_reserve(xprt, task); |
1755 | } | 1785 | } |
1756 | 1786 | ||
1757 | static void | ||
1758 | xprt_request_dequeue_all(struct rpc_task *task, struct rpc_rqst *req) | ||
1759 | { | ||
1760 | struct rpc_xprt *xprt = req->rq_xprt; | ||
1761 | |||
1762 | if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) || | ||
1763 | test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) || | ||
1764 | xprt_is_pinned_rqst(req)) { | ||
1765 | spin_lock(&xprt->queue_lock); | ||
1766 | xprt_request_dequeue_transmit_locked(task); | ||
1767 | xprt_request_dequeue_receive_locked(task); | ||
1768 | while (xprt_is_pinned_rqst(req)) { | ||
1769 | set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); | ||
1770 | spin_unlock(&xprt->queue_lock); | ||
1771 | xprt_wait_on_pinned_rqst(req); | ||
1772 | spin_lock(&xprt->queue_lock); | ||
1773 | clear_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); | ||
1774 | } | ||
1775 | spin_unlock(&xprt->queue_lock); | ||
1776 | } | ||
1777 | } | ||
1778 | |||
1779 | /** | 1787 | /** |
1780 | * xprt_release - release an RPC request slot | 1788 | * xprt_release - release an RPC request slot |
1781 | * @task: task which is finished with the slot | 1789 | * @task: task which is finished with the slot |
@@ -1795,7 +1803,7 @@ void xprt_release(struct rpc_task *task) | |||
1795 | } | 1803 | } |
1796 | 1804 | ||
1797 | xprt = req->rq_xprt; | 1805 | xprt = req->rq_xprt; |
1798 | xprt_request_dequeue_all(task, req); | 1806 | xprt_request_dequeue_xprt(task); |
1799 | spin_lock(&xprt->transport_lock); | 1807 | spin_lock(&xprt->transport_lock); |
1800 | xprt->ops->release_xprt(xprt, task); | 1808 | xprt->ops->release_xprt(xprt, task); |
1801 | if (xprt->ops->release_request) | 1809 | if (xprt->ops->release_request) |