From: Bryam Vargas iucv_sock_recvmsg() calls iucv_send_ctrl() with message_q.lock held, and iucv_send_ctrl() allocates through sock_alloc_send_skb() with sk->sk_allocation -- GFP_KERNEL here -- so the allocation may sleep inside the spin_lock_bh() section; noblock suppresses only the wait for send buffer space, not the allocation flags. The section's other allocation, alloc_iucv_recv_skb() under iucv_process_message_q(), uses GFP_ATOMIC. Note that the update is due and send it after the lock is dropped. The lock protects backlog_skb_q and message_q.list, neither of which the send touches. It does widen an existing msg_recv race -- afiucv_hs_send() reads the counter and subtracts it later, and recvmsg holds no socket lock, so two recvmsg can now interleave where before only recvmsg and sendmsg could. Both trip the same WARN_ON. Fixes: 3881ac441f64 ("af_iucv: add HiperSockets transport") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas --- net/iucv/af_iucv.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 0bc4a15f4b56..e31ef3a87ec5 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1241,6 +1241,7 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg, struct iucv_sock *iucv = iucv_sk(sk); unsigned int copied, rlen; struct sk_buff *skb, *rskb, *cskb; + bool send_win = false; int err = 0; u32 offset; @@ -1332,16 +1333,18 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg, if (!list_empty(&iucv->message_q.list)) iucv_process_message_q(sk); if (iucv->transport == AF_IUCV_TRANS_HIPER && - atomic_read(&iucv->msg_recv) >= - iucv->msglimit / 2) { - err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN); - if (err) { - sk->sk_state = IUCV_DISCONN; - sk->sk_state_change(sk); - } - } + atomic_read(&iucv->msg_recv) >= iucv->msglimit / 2) + send_win = true; } spin_unlock_bh(&iucv->message_q.lock); + + if (send_win) { + err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN); + if (err) { + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + } + } } done: -- 2.55.0