vsock: correct removal of socket from the list [Linux 4.19.64]

This Linux kernel change "vsock: correct removal of socket from the list" is included in the Linux 4.19.64 release. This change is authored by Sunil Muthuswamy <sunilmut [at] microsoft.com> on Thu Jun 13 03:52:27 2019 +0000. The commit for this change in Linux stable tree is 8a474bc (patch) which is from upstream commit d5afa82. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream d5afa82.

vsock: correct removal of socket from the list

commit d5afa82c977ea06f7119058fa0eb8519ea501031 upstream.

The current vsock code for removal of socket from the list is both
subject to race and inefficient. It takes the lock, checks whether
the socket is in the list, drops the lock and if the socket was on the
list, deletes it from the list. This is subject to race because as soon
as the lock is dropped once it is checked for presence, that condition
cannot be relied upon for any decision. It is also inefficient because
if the socket is present in the list, it takes the lock twice.

Signed-off-by: Sunil Muthuswamy <sunilmut@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 38 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 net/vmw_vsock/af_vsock.c | 38 +++++++-------------------------------
 1 file changed, 7 insertions(+), 31 deletions(-)

diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index ab27a2872..2e30bf1 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -281,7 +281,8 @@ void vsock_insert_connected(struct vsock_sock *vsk)
 void vsock_remove_bound(struct vsock_sock *vsk)
 {
    spin_lock_bh(&vsock_table_lock);
-   __vsock_remove_bound(vsk);
+   if (__vsock_in_bound_table(vsk))
+       __vsock_remove_bound(vsk);
    spin_unlock_bh(&vsock_table_lock);
 }
 EXPORT_SYMBOL_GPL(vsock_remove_bound);
@@ -289,7 +290,8 @@ void vsock_remove_bound(struct vsock_sock *vsk)
 void vsock_remove_connected(struct vsock_sock *vsk)
 {
    spin_lock_bh(&vsock_table_lock);
-   __vsock_remove_connected(vsk);
+   if (__vsock_in_connected_table(vsk))
+       __vsock_remove_connected(vsk);
    spin_unlock_bh(&vsock_table_lock);
 }
 EXPORT_SYMBOL_GPL(vsock_remove_connected);
@@ -325,35 +327,10 @@ struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
 }
 EXPORT_SYMBOL_GPL(vsock_find_connected_socket);

-static bool vsock_in_bound_table(struct vsock_sock *vsk)
-{
-   bool ret;
-
-   spin_lock_bh(&vsock_table_lock);
-   ret = __vsock_in_bound_table(vsk);
-   spin_unlock_bh(&vsock_table_lock);
-
-   return ret;
-}
-
-static bool vsock_in_connected_table(struct vsock_sock *vsk)
-{
-   bool ret;
-
-   spin_lock_bh(&vsock_table_lock);
-   ret = __vsock_in_connected_table(vsk);
-   spin_unlock_bh(&vsock_table_lock);
-
-   return ret;
-}
-
 void vsock_remove_sock(struct vsock_sock *vsk)
 {
-   if (vsock_in_bound_table(vsk))
-       vsock_remove_bound(vsk);
-
-   if (vsock_in_connected_table(vsk))
-       vsock_remove_connected(vsk);
+   vsock_remove_bound(vsk);
+   vsock_remove_connected(vsk);
 }
 EXPORT_SYMBOL_GPL(vsock_remove_sock);

@@ -484,8 +461,7 @@ static void vsock_pending_work(struct work_struct *work)
     * incoming packets can't find this socket, and to reduce the reference
     * count.
     */
-   if (vsock_in_connected_table(vsk))
-       vsock_remove_connected(vsk);
+   vsock_remove_connected(vsk);

    sk->sk_state = TCP_CLOSE;

Leave a Reply

Your email address will not be published. Required fields are marked *