diff options
author | Stefano Garzarella <sgarzare@redhat.com> | 2019-11-14 10:57:48 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-11-15 03:12:18 +0100 |
commit | 6a2c0962105ae8ceba182c4f616e0e41d7755591 (patch) | |
tree | eddaccb735a16b747cb7e422c93d2319233e91ba /net/vmw_vsock/af_vsock.c | |
parent | vsock/vmci: register vmci_transport only when VMCI guest/host are active (diff) | |
download | linux-6a2c0962105ae8ceba182c4f616e0e41d7755591.tar.xz linux-6a2c0962105ae8ceba182c4f616e0e41d7755591.zip |
vsock: prevent transport modules unloading
This patch adds 'module' member in the 'struct vsock_transport'
in order to get/put the transport module. This prevents the
module unloading while sockets are assigned to it.
We increase the module refcnt when a socket is assigned to a
transport, and we decrease the module refcnt when the socket
is destructed.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Jorgen Hansen <jhansen@vmware.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/vmw_vsock/af_vsock.c')
-rw-r--r-- | net/vmw_vsock/af_vsock.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 5357714b6104..5cb0ae42d916 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -380,6 +380,16 @@ void vsock_enqueue_accept(struct sock *listener, struct sock *connected) } EXPORT_SYMBOL_GPL(vsock_enqueue_accept); +static void vsock_deassign_transport(struct vsock_sock *vsk) +{ + if (!vsk->transport) + return; + + vsk->transport->destruct(vsk); + module_put(vsk->transport->module); + vsk->transport = NULL; +} + /* Assign a transport to a socket and call the .init transport callback. * * Note: for stream socket this must be called when vsk->remote_addr is set @@ -418,10 +428,13 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) return 0; vsk->transport->release(vsk); - vsk->transport->destruct(vsk); + vsock_deassign_transport(vsk); } - if (!new_transport) + /* We increase the module refcnt to prevent the transport unloading + * while there are open sockets assigned to it. + */ + if (!new_transport || !try_module_get(new_transport->module)) return -ENODEV; vsk->transport = new_transport; @@ -741,8 +754,7 @@ static void vsock_sk_destruct(struct sock *sk) { struct vsock_sock *vsk = vsock_sk(sk); - if (vsk->transport) - vsk->transport->destruct(vsk); + vsock_deassign_transport(vsk); /* When clearing these addresses, there's no need to set the family and * possibly register the address family with the kernel. |