Skip to content

Commit 665bcfc

Browse files
author
Paolo Abeni
committed
Merge branch 'vsock-some-fixes-due-to-transport-de-assignment'
Stefano Garzarella says: ==================== vsock: some fixes due to transport de-assignment v1: https://lore.kernel.org/netdev/[email protected]/ v2: - Added patch 3 to cancel the virtio close delayed work when de-assigning the transport - Added patch 4 to clean the socket state after de-assigning the transport - Added patch 5 as suggested by Michael and Hyunwoo Kim. It's based on Hyunwoo Kim and Wongi Lee patch [1] but using WARN_ON and covering more functions - Added R-b/T-b tags This series includes two patches discussed in the thread started by Hyunwoo Kim a few weeks ago [1], plus 3 more patches added after some discussions on v1 (see changelog). All related to the case where a vsock socket is de-assigned from a transport (e.g., because the connect fails or is interrupted by a signal) and then assigned to another transport or to no-one (NULL). I tested with usual vsock test suite, plus Michal repro [2]. (Note: the repo works only if a G2H transport is not loaded, e.g. virtio-vsock driver). The first patch is a fix more appropriate to the problem reported in that thread, the second patch on the other hand is a related fix but of a different problem highlighted by Michal Luczaj. It's present only in vsock_bpf and already handled in af_vsock.c The third patch is to cancel the virtio close delayed work when de-assigning the transport, the fourth patch is to clean the socket state after de-assigning the transport, the last patch adds warnings and prevents null-ptr-deref in vsock_*[has_data|has_space]. Hyunwoo Kim, Michal, if you can test and report your Tested-by that would be great! [1] https://lore.kernel.org/netdev/Z2K%2FI4nlHdfMRTZC@v4bel-B760M-AORUS-ELITE-AX/ [2] https://lore.kernel.org/netdev/[email protected]/ ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 0865b9f + 91751e2 commit 665bcfc

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

net/vmw_vsock/af_vsock.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,15 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
491491
*/
492492
vsk->transport->release(vsk);
493493
vsock_deassign_transport(vsk);
494+
495+
/* transport's release() and destruct() can touch some socket
496+
* state, since we are reassigning the socket to a new transport
497+
* during vsock_connect(), let's reset these fields to have a
498+
* clean state.
499+
*/
500+
sock_reset_flag(sk, SOCK_DONE);
501+
sk->sk_state = TCP_CLOSE;
502+
vsk->peer_shutdown = 0;
494503
}
495504

496505
/* We increase the module refcnt to prevent the transport unloading
@@ -870,6 +879,9 @@ EXPORT_SYMBOL_GPL(vsock_create_connected);
870879

871880
s64 vsock_stream_has_data(struct vsock_sock *vsk)
872881
{
882+
if (WARN_ON(!vsk->transport))
883+
return 0;
884+
873885
return vsk->transport->stream_has_data(vsk);
874886
}
875887
EXPORT_SYMBOL_GPL(vsock_stream_has_data);
@@ -878,6 +890,9 @@ s64 vsock_connectible_has_data(struct vsock_sock *vsk)
878890
{
879891
struct sock *sk = sk_vsock(vsk);
880892

893+
if (WARN_ON(!vsk->transport))
894+
return 0;
895+
881896
if (sk->sk_type == SOCK_SEQPACKET)
882897
return vsk->transport->seqpacket_has_data(vsk);
883898
else
@@ -887,6 +902,9 @@ EXPORT_SYMBOL_GPL(vsock_connectible_has_data);
887902

888903
s64 vsock_stream_has_space(struct vsock_sock *vsk)
889904
{
905+
if (WARN_ON(!vsk->transport))
906+
return 0;
907+
890908
return vsk->transport->stream_has_space(vsk);
891909
}
892910
EXPORT_SYMBOL_GPL(vsock_stream_has_space);

net/vmw_vsock/virtio_transport_common.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
/* Threshold for detecting small packets to copy */
2727
#define GOOD_COPY_LEN 128
2828

29+
static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
30+
bool cancel_timeout);
31+
2932
static const struct virtio_transport *
3033
virtio_transport_get_ops(struct vsock_sock *vsk)
3134
{
@@ -1109,6 +1112,8 @@ void virtio_transport_destruct(struct vsock_sock *vsk)
11091112
{
11101113
struct virtio_vsock_sock *vvs = vsk->trans;
11111114

1115+
virtio_transport_cancel_close_work(vsk, true);
1116+
11121117
kfree(vvs);
11131118
vsk->trans = NULL;
11141119
}
@@ -1204,17 +1209,11 @@ static void virtio_transport_wait_close(struct sock *sk, long timeout)
12041209
}
12051210
}
12061211

1207-
static void virtio_transport_do_close(struct vsock_sock *vsk,
1208-
bool cancel_timeout)
1212+
static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
1213+
bool cancel_timeout)
12091214
{
12101215
struct sock *sk = sk_vsock(vsk);
12111216

1212-
sock_set_flag(sk, SOCK_DONE);
1213-
vsk->peer_shutdown = SHUTDOWN_MASK;
1214-
if (vsock_stream_has_data(vsk) <= 0)
1215-
sk->sk_state = TCP_CLOSING;
1216-
sk->sk_state_change(sk);
1217-
12181217
if (vsk->close_work_scheduled &&
12191218
(!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
12201219
vsk->close_work_scheduled = false;
@@ -1226,6 +1225,20 @@ static void virtio_transport_do_close(struct vsock_sock *vsk,
12261225
}
12271226
}
12281227

1228+
static void virtio_transport_do_close(struct vsock_sock *vsk,
1229+
bool cancel_timeout)
1230+
{
1231+
struct sock *sk = sk_vsock(vsk);
1232+
1233+
sock_set_flag(sk, SOCK_DONE);
1234+
vsk->peer_shutdown = SHUTDOWN_MASK;
1235+
if (vsock_stream_has_data(vsk) <= 0)
1236+
sk->sk_state = TCP_CLOSING;
1237+
sk->sk_state_change(sk);
1238+
1239+
virtio_transport_cancel_close_work(vsk, cancel_timeout);
1240+
}
1241+
12291242
static void virtio_transport_close_timeout(struct work_struct *work)
12301243
{
12311244
struct vsock_sock *vsk =
@@ -1628,8 +1641,11 @@ void virtio_transport_recv_pkt(struct virtio_transport *t,
16281641

16291642
lock_sock(sk);
16301643

1631-
/* Check if sk has been closed before lock_sock */
1632-
if (sock_flag(sk, SOCK_DONE)) {
1644+
/* Check if sk has been closed or assigned to another transport before
1645+
* lock_sock (note: listener sockets are not assigned to any transport)
1646+
*/
1647+
if (sock_flag(sk, SOCK_DONE) ||
1648+
(sk->sk_state != TCP_LISTEN && vsk->transport != &t->transport)) {
16331649
(void)virtio_transport_reset_no_sock(t, skb);
16341650
release_sock(sk);
16351651
sock_put(sk);

net/vmw_vsock/vsock_bpf.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,21 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
7777
size_t len, int flags, int *addr_len)
7878
{
7979
struct sk_psock *psock;
80+
struct vsock_sock *vsk;
8081
int copied;
8182

8283
psock = sk_psock_get(sk);
8384
if (unlikely(!psock))
8485
return __vsock_recvmsg(sk, msg, len, flags);
8586

8687
lock_sock(sk);
88+
vsk = vsock_sk(sk);
89+
90+
if (!vsk->transport) {
91+
copied = -ENODEV;
92+
goto out;
93+
}
94+
8795
if (vsock_has_data(sk, psock) && sk_psock_queue_empty(psock)) {
8896
release_sock(sk);
8997
sk_psock_put(sk, psock);
@@ -108,6 +116,7 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
108116
copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
109117
}
110118

119+
out:
111120
release_sock(sk);
112121
sk_psock_put(sk, psock);
113122

0 commit comments

Comments
 (0)