Skip to content

Commit 2c28769

Browse files
dhowellskuba-moo
authored andcommitted
rxrpc: Fix recvmsg() unconditional requeue
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>
1 parent 7b8e1a8 commit 2c28769

2 files changed

Lines changed: 19 additions & 4 deletions

File tree

include/trace/events/rxrpc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@
322322
EM(rxrpc_call_put_kernel, "PUT kernel ") \
323323
EM(rxrpc_call_put_poke, "PUT poke ") \
324324
EM(rxrpc_call_put_recvmsg, "PUT recvmsg ") \
325+
EM(rxrpc_call_put_recvmsg_peek_nowait, "PUT peek-nwt") \
325326
EM(rxrpc_call_put_release_recvmsg_q, "PUT rls-rcmq") \
326327
EM(rxrpc_call_put_release_sock, "PUT rls-sock") \
327328
EM(rxrpc_call_put_release_sock_tba, "PUT rls-sk-a") \
@@ -340,6 +341,9 @@
340341
EM(rxrpc_call_see_input, "SEE input ") \
341342
EM(rxrpc_call_see_notify_released, "SEE nfy-rlsd") \
342343
EM(rxrpc_call_see_recvmsg, "SEE recvmsg ") \
344+
EM(rxrpc_call_see_recvmsg_requeue, "SEE recv-rqu") \
345+
EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
346+
EM(rxrpc_call_see_recvmsg_requeue_move, "SEE recv-rqM") \
343347
EM(rxrpc_call_see_release, "SEE release ") \
344348
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
345349
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
@@ -518,7 +518,8 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
518518
if (rxrpc_call_has_failed(call))
519519
goto call_failed;
520520

521-
if (!skb_queue_empty(&call->recvmsg_queue))
521+
if (!(flags & MSG_PEEK) &&
522+
!skb_queue_empty(&call->recvmsg_queue))
522523
rxrpc_notify_socket(call);
523524
goto not_yet_complete;
524525

@@ -549,11 +550,21 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
549550
error_requeue_call:
550551
if (!(flags & MSG_PEEK)) {
551552
spin_lock_irq(&rx->recvmsg_lock);
552-
list_add(&call->recvmsg_link, &rx->recvmsg_q);
553-
spin_unlock_irq(&rx->recvmsg_lock);
553+
if (list_empty(&call->recvmsg_link)) {
554+
list_add(&call->recvmsg_link, &rx->recvmsg_q);
555+
rxrpc_see_call(call, rxrpc_call_see_recvmsg_requeue);
556+
spin_unlock_irq(&rx->recvmsg_lock);
557+
} else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) {
558+
spin_unlock_irq(&rx->recvmsg_lock);
559+
rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first);
560+
} else {
561+
list_move(&call->recvmsg_link, &rx->recvmsg_q);
562+
spin_unlock_irq(&rx->recvmsg_lock);
563+
rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move);
564+
}
554565
trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_requeue, 0);
555566
} else {
556-
rxrpc_put_call(call, rxrpc_call_put_recvmsg);
567+
rxrpc_put_call(call, rxrpc_call_put_recvmsg_peek_nowait);
557568
}
558569
error_no_call:
559570
release_sock(&rx->sk);

0 commit comments

Comments
 (0)