Message ID | 20220614092557.6713-1-duoming@zju.edu.cn (mailing list archive) |
---|---|
State | Accepted |
Commit | 219b51a6f040fa5367adadd7d58c4dda0896a01d |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net,v5] net: ax25: Fix deadlock caused by skb_recv_datagram in ax25_recvmsg | expand |
On Tue, Jun 14, 2022 at 2:26 AM Duoming Zhou <duoming@zju.edu.cn> wrote: > > The skb_recv_datagram() in ax25_recvmsg() will hold lock_sock > and block until it receives a packet from the remote. If the client > doesn`t connect to server and calls read() directly, it will not > receive any packets forever. As a result, the deadlock will happen. > > The fail log caused by deadlock is shown below: > > This patch replaces skb_recv_datagram() with an open-coded variant of it > releasing the socket lock before the __skb_wait_for_more_packets() call > and re-acquiring it after such call in order that other functions that > need socket lock could be executed. > > what's more, the socket lock will be released only when recvmsg() will > block and that should produce nicer overall behavior. > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") > Suggested-by: Thomas Osterried <thomas@osterried.de> > Signed-off-by: Duoming Zhou <duoming@zju.edu.cn> > Reported-by: Thomas Habets <thomas@@habets.se> > Acked-by: Paolo Abeni <pabeni@redhat.com> > --- Reviewed-by: Eric Dumazet <edumazet@google.com>
Hello: This patch was applied to netdev/net.git (master) by David S. Miller <davem@davemloft.net>: On Tue, 14 Jun 2022 17:25:57 +0800 you wrote: > The skb_recv_datagram() in ax25_recvmsg() will hold lock_sock > and block until it receives a packet from the remote. If the client > doesn`t connect to server and calls read() directly, it will not > receive any packets forever. As a result, the deadlock will happen. > > The fail log caused by deadlock is shown below: > > [...] Here is the summary with links: - [net,v5] net: ax25: Fix deadlock caused by skb_recv_datagram in ax25_recvmsg https://git.kernel.org/netdev/net/c/219b51a6f040 You are awesome, thank you!
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 95393bb2760..4c7030ed8d3 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1661,9 +1661,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { struct sock *sk = sock->sk; - struct sk_buff *skb; + struct sk_buff *skb, *last; + struct sk_buff_head *sk_queue; int copied; int err = 0; + int off = 0; + long timeo; lock_sock(sk); /* @@ -1675,10 +1678,29 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, goto out; } - /* Now we can treat all alike */ - skb = skb_recv_datagram(sk, flags, &err); - if (skb == NULL) - goto out; + /* We need support for non-blocking reads. */ + sk_queue = &sk->sk_receive_queue; + skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, &err, &last); + /* If no packet is available, release_sock(sk) and try again. */ + if (!skb) { + if (err != -EAGAIN) + goto out; + release_sock(sk); + timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); + while (timeo && !__skb_wait_for_more_packets(sk, sk_queue, &err, + &timeo, last)) { + skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, + &err, &last); + if (skb) + break; + + if (err != -EAGAIN) + goto done; + } + if (!skb) + goto done; + lock_sock(sk); + } if (!sk_to_ax25(sk)->pidincl) skb_pull(skb, 1); /* Remove PID */ @@ -1725,6 +1747,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, out: release_sock(sk); +done: return err; }