]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf, vsock: Invoke proto::close on close()
authorMichal Luczaj <mhal@rbox.co>
Mon, 18 Nov 2024 21:03:43 +0000 (22:03 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 25 Nov 2024 22:19:14 +0000 (14:19 -0800)
vsock defines a BPF callback to be invoked when close() is called. However,
this callback is never actually executed. As a result, a closed vsock
socket is not automatically removed from the sockmap/sockhash.

Introduce a dummy vsock_close() and make vsock_release() call proto::close.

Note: changes in __vsock_release() look messy, but it's only due to indent
level reduction and variables xmas tree reorder.

Fixes: 634f1a7110b4 ("vsock: support sockmap")
Signed-off-by: Michal Luczaj <mhal@rbox.co>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: Luigi Leonardi <leonardi@redhat.com>
Link: https://lore.kernel.org/r/20241118-vsock-bpf-poll-close-v1-3-f1b9669cacdc@rbox.co
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: John Fastabend <john.fastabend@gmail.com>
net/vmw_vsock/af_vsock.c

index 725da7203f2de64fa385761eb30db8223a061b12..5cf8109f672a51f8cf6daca344ae3653dc3beec3 100644 (file)
 static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr);
 static void vsock_sk_destruct(struct sock *sk);
 static int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+static void vsock_close(struct sock *sk, long timeout);
 
 /* Protocol family. */
 struct proto vsock_proto = {
        .name = "AF_VSOCK",
        .owner = THIS_MODULE,
        .obj_size = sizeof(struct vsock_sock),
+       .close = vsock_close,
 #ifdef CONFIG_BPF_SYSCALL
        .psock_update_sk_prot = vsock_bpf_update_proto,
 #endif
@@ -797,39 +799,37 @@ static bool sock_type_connectible(u16 type)
 
 static void __vsock_release(struct sock *sk, int level)
 {
-       if (sk) {
-               struct sock *pending;
-               struct vsock_sock *vsk;
-
-               vsk = vsock_sk(sk);
-               pending = NULL; /* Compiler warning. */
+       struct vsock_sock *vsk;
+       struct sock *pending;
 
-               /* When "level" is SINGLE_DEPTH_NESTING, use the nested
-                * version to avoid the warning "possible recursive locking
-                * detected". When "level" is 0, lock_sock_nested(sk, level)
-                * is the same as lock_sock(sk).
-                */
-               lock_sock_nested(sk, level);
+       vsk = vsock_sk(sk);
+       pending = NULL; /* Compiler warning. */
 
-               if (vsk->transport)
-                       vsk->transport->release(vsk);
-               else if (sock_type_connectible(sk->sk_type))
-                       vsock_remove_sock(vsk);
+       /* When "level" is SINGLE_DEPTH_NESTING, use the nested
+        * version to avoid the warning "possible recursive locking
+        * detected". When "level" is 0, lock_sock_nested(sk, level)
+        * is the same as lock_sock(sk).
+        */
+       lock_sock_nested(sk, level);
 
-               sock_orphan(sk);
-               sk->sk_shutdown = SHUTDOWN_MASK;
+       if (vsk->transport)
+               vsk->transport->release(vsk);
+       else if (sock_type_connectible(sk->sk_type))
+               vsock_remove_sock(vsk);
 
-               skb_queue_purge(&sk->sk_receive_queue);
+       sock_orphan(sk);
+       sk->sk_shutdown = SHUTDOWN_MASK;
 
-               /* Clean up any sockets that never were accepted. */
-               while ((pending = vsock_dequeue_accept(sk)) != NULL) {
-                       __vsock_release(pending, SINGLE_DEPTH_NESTING);
-                       sock_put(pending);
-               }
+       skb_queue_purge(&sk->sk_receive_queue);
 
-               release_sock(sk);
-               sock_put(sk);
+       /* Clean up any sockets that never were accepted. */
+       while ((pending = vsock_dequeue_accept(sk)) != NULL) {
+               __vsock_release(pending, SINGLE_DEPTH_NESTING);
+               sock_put(pending);
        }
+
+       release_sock(sk);
+       sock_put(sk);
 }
 
 static void vsock_sk_destruct(struct sock *sk)
@@ -901,9 +901,22 @@ void vsock_data_ready(struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(vsock_data_ready);
 
+/* Dummy callback required by sockmap.
+ * See unconditional call of saved_close() in sock_map_close().
+ */
+static void vsock_close(struct sock *sk, long timeout)
+{
+}
+
 static int vsock_release(struct socket *sock)
 {
-       __vsock_release(sock->sk, 0);
+       struct sock *sk = sock->sk;
+
+       if (!sk)
+               return 0;
+
+       sk->sk_prot->close(sk, 0);
+       __vsock_release(sk, 0);
        sock->sk = NULL;
        sock->state = SS_FREE;