forked from luck/tmp_suning_uos_patched
vsock/virtio: free queued packets when closing socket
[ Upstream commit 8432b8114957235f42e070a16118a7f750de9d39 ] As reported by syzbot [1], there is a memory leak while closing the socket. We partially solved this issue with commitac03046ece
("vsock/virtio: free packets during the socket release"), but we forgot to drain the RX queue when the socket is definitely closed by the scheduled work. To avoid future issues, let's use the new virtio_transport_remove_sock() to drain the RX queue before removing the socket from the af_vsock lists calling vsock_remove_sock(). [1] https://syzkaller.appspot.com/bug?extid=24452624fc4c571eedd9 Fixes:ac03046ece
("vsock/virtio: free packets during the socket release") Reported-and-tested-by: syzbot+24452624fc4c571eedd9@syzkaller.appspotmail.com Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
5231d17eb9
commit
b605673b52
|
@ -733,6 +733,23 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
|
|||
return t->send_pkt(reply);
|
||||
}
|
||||
|
||||
/* This function should be called with sk_lock held and SOCK_DONE set */
|
||||
static void virtio_transport_remove_sock(struct vsock_sock *vsk)
|
||||
{
|
||||
struct virtio_vsock_sock *vvs = vsk->trans;
|
||||
struct virtio_vsock_pkt *pkt, *tmp;
|
||||
|
||||
/* We don't need to take rx_lock, as the socket is closing and we are
|
||||
* removing it.
|
||||
*/
|
||||
list_for_each_entry_safe(pkt, tmp, &vvs->rx_queue, list) {
|
||||
list_del(&pkt->list);
|
||||
virtio_transport_free_pkt(pkt);
|
||||
}
|
||||
|
||||
vsock_remove_sock(vsk);
|
||||
}
|
||||
|
||||
static void virtio_transport_wait_close(struct sock *sk, long timeout)
|
||||
{
|
||||
if (timeout) {
|
||||
|
@ -765,7 +782,7 @@ static void virtio_transport_do_close(struct vsock_sock *vsk,
|
|||
(!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
|
||||
vsk->close_work_scheduled = false;
|
||||
|
||||
vsock_remove_sock(vsk);
|
||||
virtio_transport_remove_sock(vsk);
|
||||
|
||||
/* Release refcnt obtained when we scheduled the timeout */
|
||||
sock_put(sk);
|
||||
|
@ -828,22 +845,15 @@ static bool virtio_transport_close(struct vsock_sock *vsk)
|
|||
|
||||
void virtio_transport_release(struct vsock_sock *vsk)
|
||||
{
|
||||
struct virtio_vsock_sock *vvs = vsk->trans;
|
||||
struct virtio_vsock_pkt *pkt, *tmp;
|
||||
struct sock *sk = &vsk->sk;
|
||||
bool remove_sock = true;
|
||||
|
||||
if (sk->sk_type == SOCK_STREAM)
|
||||
remove_sock = virtio_transport_close(vsk);
|
||||
|
||||
list_for_each_entry_safe(pkt, tmp, &vvs->rx_queue, list) {
|
||||
list_del(&pkt->list);
|
||||
virtio_transport_free_pkt(pkt);
|
||||
}
|
||||
|
||||
if (remove_sock) {
|
||||
sock_set_flag(sk, SOCK_DONE);
|
||||
vsock_remove_sock(vsk);
|
||||
virtio_transport_remove_sock(vsk);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_transport_release);
|
||||
|
|
Loading…
Reference in New Issue
Block a user