hv_sock: Fix hang when a connection is closed
There is a race condition for an established connection that is being closed
by the guest: the refcnt is 4 at the end of hvs_release() (Note: here the
'remove_sock' is false):
1 for the initial value;
1 for the sk being in the bound list;
1 for the sk being in the connected list;
1 for the delayed close_work.
After hvs_release() finishes, __vsock_release() -> sock_put(sk) *may*
decrease the refcnt to 3.
Concurrently, hvs_close_connection() runs in another thread:
calls vsock_remove_sock() to decrease the refcnt by 2;
call sock_put() to decrease the refcnt to 0, and free the sk;
next, the "release_sock(sk)" may hang due to use-after-free.
In the above, after hvs_release() finishes, if hvs_close_connection() runs
faster than "__vsock_release() -> sock_put(sk)", then there is not any issue,
because at the beginning of hvs_close_connection(), the refcnt is still 4.
The issue can be resolved if an extra reference is taken when the
connection is established.
Fixes: a9eeb998c2
("hv_sock: Add support for delayed close")
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Sunil Muthuswamy <sunilmut@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
224c04973d
Коммит
685703b497
|
@ -312,6 +312,11 @@ static void hvs_close_connection(struct vmbus_channel *chan)
|
|||
lock_sock(sk);
|
||||
hvs_do_close_lock_held(vsock_sk(sk), true);
|
||||
release_sock(sk);
|
||||
|
||||
/* Release the refcnt for the channel that's opened in
|
||||
* hvs_open_connection().
|
||||
*/
|
||||
sock_put(sk);
|
||||
}
|
||||
|
||||
static void hvs_open_connection(struct vmbus_channel *chan)
|
||||
|
@ -407,6 +412,9 @@ static void hvs_open_connection(struct vmbus_channel *chan)
|
|||
}
|
||||
|
||||
set_per_channel_state(chan, conn_from_host ? new : sk);
|
||||
|
||||
/* This reference will be dropped by hvs_close_connection(). */
|
||||
sock_hold(conn_from_host ? new : sk);
|
||||
vmbus_set_chn_rescind_callback(chan, hvs_close_connection);
|
||||
|
||||
/* Set the pending send size to max packet size to always get
|
||||
|
|
Загрузка…
Ссылка в новой задаче