Skip to content
/ linux Public

Commit 0464bf7

Browse files
dhowellsgregkh
authored andcommitted
rxrpc: Fix recvmsg() unconditional requeue
[ Upstream commit 2c28769 ] If rxrpc_recvmsg() fails because MSG_DONTWAIT was specified but the call at the front of the recvmsg queue already has its mutex locked, it requeues the call - whether or not the call is already queued. The call may be on the queue because MSG_PEEK was also passed and so the call was not dequeued or because the I/O thread requeued it. The unconditional requeue may then corrupt the recvmsg queue, leading to things like UAFs or refcount underruns. Fix this by only requeuing the call if it isn't already on the queue - and moving it to the front if it is already queued. If we don't queue it, we have to put the ref we obtained by dequeuing it. Also, MSG_PEEK doesn't dequeue the call so shouldn't call rxrpc_notify_socket() for the call if we didn't use up all the data on the queue, so fix that also. Fixes: 540b1c4 ("rxrpc: Fix deadlock between call creation and sendmsg/recvmsg") Reported-by: Faith <faith@zellic.io> Reported-by: Pumpkin Chang <pumpkin@devco.re> Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Marc Dionne <marc.dionne@auristor.com> cc: Nir Ohfeld <niro@wiz.io> cc: Willy Tarreau <w@1wt.eu> cc: Simon Horman <horms@kernel.org> cc: linux-afs@lists.infradead.org cc: stable@kernel.org Link: https://patch.msgid.link/95163.1768428203@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org> [Use spin_unlock instead of spin_unlock_irq to maintain context consistency.] Signed-off-by: Robert Garcia <rob_garcia@163.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1b0edd6 commit 0464bf7

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

include/trace/events/rxrpc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@
270270
EM(rxrpc_call_put_kernel, "PUT kernel ") \
271271
EM(rxrpc_call_put_poke, "PUT poke ") \
272272
EM(rxrpc_call_put_recvmsg, "PUT recvmsg ") \
273+
EM(rxrpc_call_put_recvmsg_peek_nowait, "PUT peek-nwt") \
273274
EM(rxrpc_call_put_release_sock, "PUT rls-sock") \
274275
EM(rxrpc_call_put_release_sock_tba, "PUT rls-sk-a") \
275276
EM(rxrpc_call_put_sendmsg, "PUT sendmsg ") \
@@ -287,6 +288,9 @@
287288
EM(rxrpc_call_see_distribute_error, "SEE dist-err") \
288289
EM(rxrpc_call_see_input, "SEE input ") \
289290
EM(rxrpc_call_see_recvmsg, "SEE recvmsg ") \
291+
EM(rxrpc_call_see_recvmsg_requeue, "SEE recv-rqu") \
292+
EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
293+
EM(rxrpc_call_see_recvmsg_requeue_move, "SEE recv-rqM") \
290294
EM(rxrpc_call_see_release, "SEE release ") \
291295
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
292296
EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \

net/rxrpc/recvmsg.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
430430
if (rxrpc_call_has_failed(call))
431431
goto call_failed;
432432

433-
if (!skb_queue_empty(&call->recvmsg_queue))
433+
if (!(flags & MSG_PEEK) &&
434+
!skb_queue_empty(&call->recvmsg_queue))
434435
rxrpc_notify_socket(call);
435436
goto not_yet_complete;
436437

@@ -461,11 +462,21 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
461462
error_requeue_call:
462463
if (!(flags & MSG_PEEK)) {
463464
spin_lock(&rx->recvmsg_lock);
464-
list_add(&call->recvmsg_link, &rx->recvmsg_q);
465-
spin_unlock(&rx->recvmsg_lock);
465+
if (list_empty(&call->recvmsg_link)) {
466+
list_add(&call->recvmsg_link, &rx->recvmsg_q);
467+
rxrpc_see_call(call, rxrpc_call_see_recvmsg_requeue);
468+
spin_unlock(&rx->recvmsg_lock);
469+
} else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) {
470+
spin_unlock(&rx->recvmsg_lock);
471+
rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first);
472+
} else {
473+
list_move(&call->recvmsg_link, &rx->recvmsg_q);
474+
spin_unlock(&rx->recvmsg_lock);
475+
rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move);
476+
}
466477
trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_requeue, 0);
467478
} else {
468-
rxrpc_put_call(call, rxrpc_call_put_recvmsg);
479+
rxrpc_put_call(call, rxrpc_call_put_recvmsg_peek_nowait);
469480
}
470481
error_no_call:
471482
release_sock(&rx->sk);

0 commit comments

Comments
 (0)