* [PATCH net v3 0/2] vsock/bpf: fix waiting and flag handling in recvmsg
@ 2026-10-28 17:55 ` Jerome Mohm via B4 Relay
0 siblings, 0 replies; 8+ messages in thread
From: Jerome Mohm @ 2026-10-28 17:55 UTC (permalink / raw)
To: Stefano Garzarella, Bobby Eshleman, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Michael S. Tsirkin
Cc: Michal Luczaj, virtualization, netdev, linux-kernel, bpf, stable,
Jerome Mohm
vsock_bpf_recvmsg() holds lock_sock() while it sleeps for data, so the
transport's delivery worker, which needs that lock to queue the data,
deadlocks with the reader. Patch 1 releases the lock around the wait and
makes the wait loop with the exit conditions of the native path,
including a state check that ends the wait on a reset connection after
getsockopt(SO_ERROR) has cleared sk_err. Patch 2 handles the reads that
should never reach the sockmap wait: len == 0, MSG_ERRQUEUE and MSG_OOB.
v2 was one patch; as Michal noted, it mixed the deadlock fix with
fixes for pre-existing issues, so v3 splits it. Patch 1 alone fixes the
deadlock, the dataless wakeup, the peer shutdown and the reset cases;
the zero-length, MSG_ERRQUEUE and MSG_OOB reads keep their current
behaviour until patch 2.
Not addressed here: the netdev Sashiko review of v2 also noted a
pre-existing case where data that sits only in psock->ingress_skb makes
recvmsg() fall back to the native path, which never looks at the psock
queues. It is independent of this series and I will send a separate
patch for it. Annotating the lockless accesses with
READ_ONCE()/WRITE_ONCE() is likewise left for a separate patch that also
covers the native vsock_connectible_wait_data().
The deadlock and the MSG_ERRQUEUE case were found with the help of
Anthropic's Claude; the other cases come from the netdev Sashiko review.
The reproducers are available on request.
Changes in v3:
- Split into two patches (Michal): 1/2 releases the lock and loops in
the wait, 2/2 handles len == 0, MSG_ERRQUEUE and MSG_OOB.
- 1/2: also end the wait once the socket is no longer TCP_ESTABLISHED
(0 with SOCK_DONE, else -ENOTCONN, as __vsock_connectible_recvmsg()
does), so a reset connection whose error was read with SO_ERROR no
longer waits out the timeout (Sashiko review of v2).
- 2/2: reject MSG_OOB with -EOPNOTSUPP before the len == 0 check, as
unix_bpf does; this also stops MSG_OOB from consuming ordinary bytes
(Sashiko review of v2).
- Stefano's Acked-by on v1 is not carried: neither patch matches v1.
- Drop the Assisted-by trailer (removed upstream); tool use is disclosed
above instead.
- Rebase onto current net.
- Link to v2: https://lore.kernel.org/netdev/20261001-kbh3-1-022-fix-v2-v1-1-cfae958a1976@eldare.de/
Changes in v2:
- Make vsock_msg_wait_data() loop, check sk_err and the peer
SEND_SHUTDOWN, and add the len == 0 guard (Sashiko review of v1);
route MSG_ERRQUEUE to the native path ahead of the guard.
- Link to v1: https://lore.kernel.org/netdev/20260929-kbh3-1-022-fix-v1-1-cc97cc95d269@eldare.de/
---
Jerome Mohm (2):
vsock/bpf: release sock lock while waiting for data in recvmsg
vsock/bpf: fix zero-length, MSG_OOB and MSG_ERRQUEUE reads in recvmsg
net/vmw_vsock/vsock_bpf.c | 71 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 57 insertions(+), 14 deletions(-)
---
base-commit: 363c8c79220d0db4d65dcd570529ddda15067cb5
change-id: 20261001-kbh3-1-022-fix-v2-e3f14290641a
Best regards,
--
Jerome Mohm <jrmmhm.kernel@eldare.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net v3 0/2] vsock/bpf: fix waiting and flag handling in recvmsg
@ 2026-10-28 17:55 ` Jerome Mohm via B4 Relay
0 siblings, 0 replies; 8+ messages in thread
From: Jerome Mohm via B4 Relay @ 2026-10-28 17:55 UTC (permalink / raw)
To: Stefano Garzarella, Bobby Eshleman, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Michael S. Tsirkin
Cc: Michal Luczaj, virtualization, netdev, linux-kernel, bpf, stable,
Jerome Mohm
vsock_bpf_recvmsg() holds lock_sock() while it sleeps for data, so the
transport's delivery worker, which needs that lock to queue the data,
deadlocks with the reader. Patch 1 releases the lock around the wait and
makes the wait loop with the exit conditions of the native path,
including a state check that ends the wait on a reset connection after
getsockopt(SO_ERROR) has cleared sk_err. Patch 2 handles the reads that
should never reach the sockmap wait: len == 0, MSG_ERRQUEUE and MSG_OOB.
v2 was one patch; as Michal noted, it mixed the deadlock fix with
fixes for pre-existing issues, so v3 splits it. Patch 1 alone fixes the
deadlock, the dataless wakeup, the peer shutdown and the reset cases;
the zero-length, MSG_ERRQUEUE and MSG_OOB reads keep their current
behaviour until patch 2.
Not addressed here: the netdev Sashiko review of v2 also noted a
pre-existing case where data that sits only in psock->ingress_skb makes
recvmsg() fall back to the native path, which never looks at the psock
queues. It is independent of this series and I will send a separate
patch for it. Annotating the lockless accesses with
READ_ONCE()/WRITE_ONCE() is likewise left for a separate patch that also
covers the native vsock_connectible_wait_data().
The deadlock and the MSG_ERRQUEUE case were found with the help of
Anthropic's Claude; the other cases come from the netdev Sashiko review.
The reproducers are available on request.
Changes in v3:
- Split into two patches (Michal): 1/2 releases the lock and loops in
the wait, 2/2 handles len == 0, MSG_ERRQUEUE and MSG_OOB.
- 1/2: also end the wait once the socket is no longer TCP_ESTABLISHED
(0 with SOCK_DONE, else -ENOTCONN, as __vsock_connectible_recvmsg()
does), so a reset connection whose error was read with SO_ERROR no
longer waits out the timeout (Sashiko review of v2).
- 2/2: reject MSG_OOB with -EOPNOTSUPP before the len == 0 check, as
unix_bpf does; this also stops MSG_OOB from consuming ordinary bytes
(Sashiko review of v2).
- Stefano's Acked-by on v1 is not carried: neither patch matches v1.
- Drop the Assisted-by trailer (removed upstream); tool use is disclosed
above instead.
- Rebase onto current net.
- Link to v2: https://lore.kernel.org/netdev/20261001-kbh3-1-022-fix-v2-v1-1-cfae958a1976@eldare.de/
Changes in v2:
- Make vsock_msg_wait_data() loop, check sk_err and the peer
SEND_SHUTDOWN, and add the len == 0 guard (Sashiko review of v1);
route MSG_ERRQUEUE to the native path ahead of the guard.
- Link to v1: https://lore.kernel.org/netdev/20260929-kbh3-1-022-fix-v1-1-cc97cc95d269@eldare.de/
---
Jerome Mohm (2):
vsock/bpf: release sock lock while waiting for data in recvmsg
vsock/bpf: fix zero-length, MSG_OOB and MSG_ERRQUEUE reads in recvmsg
net/vmw_vsock/vsock_bpf.c | 71 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 57 insertions(+), 14 deletions(-)
---
base-commit: 363c8c79220d0db4d65dcd570529ddda15067cb5
change-id: 20261001-kbh3-1-022-fix-v2-e3f14290641a
Best regards,
--
Jerome Mohm <jrmmhm.kernel@eldare.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net v3 1/2] vsock/bpf: release sock lock while waiting for data in recvmsg
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
@ 2026-10-28 17:55 ` Jerome Mohm via B4 Relay
-1 siblings, 0 replies; 8+ messages in thread
From: Jerome Mohm @ 2026-10-28 17:55 UTC (permalink / raw)
To: Stefano Garzarella, Bobby Eshleman, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Michael S. Tsirkin
Cc: Michal Luczaj, virtualization, netdev, linux-kernel, bpf, stable,
Jerome Mohm
vsock_bpf_recvmsg() takes lock_sock(sk) and holds it across the receive
loop, including vsock_msg_wait_data(), which sleeps in wait_woken()
without dropping the lock. When data arrives, the transport's delivery
context (the vsock-loopback worker, or the virtio/vhost rx path) calls
virtio_transport_recv_pkt() -> lock_sock() on the same socket and blocks.
That context is the only one that would queue the skb and wake the
reader, so neither side makes progress: a blocking recv() hangs until a
signal arrives or SO_RCVTIMEO expires, and meanwhile the shared delivery
worker is stalled, so all vsock rx on that transport stops. The
hung-task watchdog reports the worker:
INFO: task kworker/1:3:107 blocked for more than 5 seconds.
task:kworker/1:3 state:D Workqueue: vsock-loopback vsock_loopback_work
Call Trace:
__schedule
schedule
__lock_sock
lock_sock_nested
virtio_transport_recv_pkt
vsock_loopback_work
vsock_bpf.c is based on net/unix/unix_bpf.c, whose unix_msg_wait_data()
drops u->iolock around wait_woken(); tcp_bpf and the native
vsock_connectible_wait_data() also drop the lock across the wait.
Releasing the lock alone is not enough. With the lock dropped, the
reader is also woken by events that bring no data, for example a credit
update via sk_write_space(); vsock_msg_wait_data() did not loop, so a
blocking recv() then returned -EAGAIN early. It also checked only for a
local RCV_SHUTDOWN, so a peer shutdown or a reset was not noticed. A
looping wait must stop on everything the native receive path stops on:
without the shutdown checks a peer shutdown, and without the state
check a reset whose error was already read with SO_ERROR, would sleep
until the timeout.
Make vsock_msg_wait_data() loop and release the socket lock around each
wait. It returns 1 when data is ready, -sk_err on a socket error, 0 on
RCV_SHUTDOWN or a peer SEND_SHUTDOWN (as vsock_connectible_wait_data()
does), -EAGAIN on timeout and sock_intr_errno() on a pending signal. It
also stops once the socket is no longer TCP_ESTABLISHED, with 0 if
SOCK_DONE is set and -ENOTCONN otherwise, mirroring the state check in
__vsock_connectible_recvmsg(): a transport reset
(virtio_vsock_reset_sock()) sets only TCP_CLOSE and sk_err, and
getsockopt(SO_ERROR) clears sk_err, so without the state check the loop
would wait out the whole timeout on a dead connection. Data already in
the psock ingress queue is still returned first. vsock_bpf_recvmsg()
returns a negative result as the error and 0 as end of file.
Two userspace-visible results are worth noting: a pending signal now
returns sock_intr_errno() where the old code returned -EAGAIN, and after
a virtio transport reset recv() returns -ECONNRESET until
getsockopt(SO_ERROR) has read the error, where the native path returns
-ENOTCONN.
The deadlock was found with the help of an LLM coding assistant
(Anthropic's Claude); Sashiko AI reviews of two earlier sockmap patches
had already noted it as a pre-existing issue. The early -EAGAIN on a
dataless wakeup, the missed peer shutdown and the wait on a reset
connection were reported by the netdev Sashiko AI review of earlier
versions of this patch. Each reproducer is a C program run as root in
the guest: it adds one end of a vsock stream connection to a BPF sockmap
(CAP_BPF and CAP_NET_ADMIN) and drives a blocking recv(); the reset case
connects to a peer on the host and unbinds the guest's virtio-vsock
device, the others use vsock-loopback. No kernel change or error
injection is needed. The reproducers are available on request.
Testing: built a KASAN + lockdep kernel on net and ran reproducers on a
private VM, before and after this patch. Before: a blocking recv() on a
sockmap socket deadlocks the vsock-loopback worker (hung-task). After:
it returns the data; a dataless credit-update wakeup does not end the
wait; a peer SEND_SHUTDOWN returns 0; and after a reset of a virtio
connection (unbinding the guest's virtio-vsock device) and
getsockopt(SO_ERROR), recv() returns -ENOTCONN at once like a socket
outside the sockmap, where before this patch it waited for SO_RCVTIMEO.
No KASAN, lockdep or hung-task report. With both patches of this series
applied, the three single-VM tests of
tools/testing/selftests/vsock/vmtest.sh (vm_server_host_client,
vm_client_host_server, vm_loopback; 44 vsock_test cases each) pass, as
on net; on both kernels the host-side runs skip the SO_INQ cases (SO_INQ
not supported by the host kernel). The ns_* tests of vmtest.sh were not
run (they need root on the host). The BPF test_progs sockmap_basic,
sockmap_listen and sockmap_redir tests pass (767 of 767 subtests, among
them the three vsock subtests of sockmap_basic and the 240 AF_VSOCK
cases of sockmap_redir).
Fixes: 634f1a7110b4 ("vsock: support sockmap")
Cc: stable@vger.kernel.org
Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
---
net/vmw_vsock/vsock_bpf.c | 62 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 48 insertions(+), 14 deletions(-)
diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
index 9049d2648646..5120911b8143 100644
--- a/net/vmw_vsock/vsock_bpf.c
+++ b/net/vmw_vsock/vsock_bpf.c
@@ -34,24 +34,55 @@ static bool vsock_has_data(struct sock *sk, struct sk_psock *psock)
return vsock_sk_has_data(sk, psock);
}
-static bool vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo)
+/* Returns 1 if data is ready, 0 on EOF/shutdown, or a negative error. */
+static int vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo)
{
- bool ret;
+ struct vsock_sock *vsk = vsock_sk(sk);
+ int ret;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- return true;
-
- if (!timeo)
- return false;
-
add_wait_queue(sk_sleep(sk), &wait);
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
- ret = vsock_has_data(sk, psock);
- if (!ret) {
- wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
- ret = vsock_has_data(sk, psock);
+ while (1) {
+ if (vsock_has_data(sk, psock)) {
+ ret = 1;
+ break;
+ }
+
+ if (sk->sk_err) {
+ ret = -sk->sk_err;
+ break;
+ }
+
+ if ((sk->sk_shutdown & RCV_SHUTDOWN) ||
+ (vsk->peer_shutdown & SEND_SHUTDOWN)) {
+ ret = 0;
+ break;
+ }
+
+ /* virtio_vsock_reset_sock() sets no shutdown bits, and
+ * SO_ERROR clears sk_err: check the state the way
+ * __vsock_connectible_recvmsg() does.
+ */
+ if (sk->sk_state != TCP_ESTABLISHED) {
+ ret = sock_flag(sk, SOCK_DONE) ? 0 : -ENOTCONN;
+ break;
+ }
+
+ if (!timeo) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ release_sock(sk);
+ timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
+ lock_sock(sk);
+
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeo);
+ break;
+ }
}
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
remove_wait_queue(sk_sleep(sk), &wait);
@@ -101,11 +132,14 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
while (copied == 0) {
long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+ int data = vsock_msg_wait_data(sk, psock, timeo);
- if (!vsock_msg_wait_data(sk, psock, timeo)) {
- copied = -EAGAIN;
+ if (data < 0) {
+ copied = data;
break;
}
+ if (!data)
+ break;
if (sk_psock_queue_empty(psock)) {
release_sock(sk);
--
2.56.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net v3 1/2] vsock/bpf: release sock lock while waiting for data in recvmsg
@ 2026-10-28 17:55 ` Jerome Mohm via B4 Relay
0 siblings, 0 replies; 8+ messages in thread
From: Jerome Mohm via B4 Relay @ 2026-10-28 17:55 UTC (permalink / raw)
To: Stefano Garzarella, Bobby Eshleman, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Michael S. Tsirkin
Cc: Michal Luczaj, virtualization, netdev, linux-kernel, bpf, stable,
Jerome Mohm
From: Jerome Mohm <jrmmhm.kernel@eldare.de>
vsock_bpf_recvmsg() takes lock_sock(sk) and holds it across the receive
loop, including vsock_msg_wait_data(), which sleeps in wait_woken()
without dropping the lock. When data arrives, the transport's delivery
context (the vsock-loopback worker, or the virtio/vhost rx path) calls
virtio_transport_recv_pkt() -> lock_sock() on the same socket and blocks.
That context is the only one that would queue the skb and wake the
reader, so neither side makes progress: a blocking recv() hangs until a
signal arrives or SO_RCVTIMEO expires, and meanwhile the shared delivery
worker is stalled, so all vsock rx on that transport stops. The
hung-task watchdog reports the worker:
INFO: task kworker/1:3:107 blocked for more than 5 seconds.
task:kworker/1:3 state:D Workqueue: vsock-loopback vsock_loopback_work
Call Trace:
__schedule
schedule
__lock_sock
lock_sock_nested
virtio_transport_recv_pkt
vsock_loopback_work
vsock_bpf.c is based on net/unix/unix_bpf.c, whose unix_msg_wait_data()
drops u->iolock around wait_woken(); tcp_bpf and the native
vsock_connectible_wait_data() also drop the lock across the wait.
Releasing the lock alone is not enough. With the lock dropped, the
reader is also woken by events that bring no data, for example a credit
update via sk_write_space(); vsock_msg_wait_data() did not loop, so a
blocking recv() then returned -EAGAIN early. It also checked only for a
local RCV_SHUTDOWN, so a peer shutdown or a reset was not noticed. A
looping wait must stop on everything the native receive path stops on:
without the shutdown checks a peer shutdown, and without the state
check a reset whose error was already read with SO_ERROR, would sleep
until the timeout.
Make vsock_msg_wait_data() loop and release the socket lock around each
wait. It returns 1 when data is ready, -sk_err on a socket error, 0 on
RCV_SHUTDOWN or a peer SEND_SHUTDOWN (as vsock_connectible_wait_data()
does), -EAGAIN on timeout and sock_intr_errno() on a pending signal. It
also stops once the socket is no longer TCP_ESTABLISHED, with 0 if
SOCK_DONE is set and -ENOTCONN otherwise, mirroring the state check in
__vsock_connectible_recvmsg(): a transport reset
(virtio_vsock_reset_sock()) sets only TCP_CLOSE and sk_err, and
getsockopt(SO_ERROR) clears sk_err, so without the state check the loop
would wait out the whole timeout on a dead connection. Data already in
the psock ingress queue is still returned first. vsock_bpf_recvmsg()
returns a negative result as the error and 0 as end of file.
Two userspace-visible results are worth noting: a pending signal now
returns sock_intr_errno() where the old code returned -EAGAIN, and after
a virtio transport reset recv() returns -ECONNRESET until
getsockopt(SO_ERROR) has read the error, where the native path returns
-ENOTCONN.
The deadlock was found with the help of an LLM coding assistant
(Anthropic's Claude); Sashiko AI reviews of two earlier sockmap patches
had already noted it as a pre-existing issue. The early -EAGAIN on a
dataless wakeup, the missed peer shutdown and the wait on a reset
connection were reported by the netdev Sashiko AI review of earlier
versions of this patch. Each reproducer is a C program run as root in
the guest: it adds one end of a vsock stream connection to a BPF sockmap
(CAP_BPF and CAP_NET_ADMIN) and drives a blocking recv(); the reset case
connects to a peer on the host and unbinds the guest's virtio-vsock
device, the others use vsock-loopback. No kernel change or error
injection is needed. The reproducers are available on request.
Testing: built a KASAN + lockdep kernel on net and ran reproducers on a
private VM, before and after this patch. Before: a blocking recv() on a
sockmap socket deadlocks the vsock-loopback worker (hung-task). After:
it returns the data; a dataless credit-update wakeup does not end the
wait; a peer SEND_SHUTDOWN returns 0; and after a reset of a virtio
connection (unbinding the guest's virtio-vsock device) and
getsockopt(SO_ERROR), recv() returns -ENOTCONN at once like a socket
outside the sockmap, where before this patch it waited for SO_RCVTIMEO.
No KASAN, lockdep or hung-task report. With both patches of this series
applied, the three single-VM tests of
tools/testing/selftests/vsock/vmtest.sh (vm_server_host_client,
vm_client_host_server, vm_loopback; 44 vsock_test cases each) pass, as
on net; on both kernels the host-side runs skip the SO_INQ cases (SO_INQ
not supported by the host kernel). The ns_* tests of vmtest.sh were not
run (they need root on the host). The BPF test_progs sockmap_basic,
sockmap_listen and sockmap_redir tests pass (767 of 767 subtests, among
them the three vsock subtests of sockmap_basic and the 240 AF_VSOCK
cases of sockmap_redir).
Fixes: 634f1a7110b4 ("vsock: support sockmap")
Cc: stable@vger.kernel.org
Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
---
net/vmw_vsock/vsock_bpf.c | 62 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 48 insertions(+), 14 deletions(-)
diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
index 9049d2648646..5120911b8143 100644
--- a/net/vmw_vsock/vsock_bpf.c
+++ b/net/vmw_vsock/vsock_bpf.c
@@ -34,24 +34,55 @@ static bool vsock_has_data(struct sock *sk, struct sk_psock *psock)
return vsock_sk_has_data(sk, psock);
}
-static bool vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo)
+/* Returns 1 if data is ready, 0 on EOF/shutdown, or a negative error. */
+static int vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo)
{
- bool ret;
+ struct vsock_sock *vsk = vsock_sk(sk);
+ int ret;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- return true;
-
- if (!timeo)
- return false;
-
add_wait_queue(sk_sleep(sk), &wait);
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
- ret = vsock_has_data(sk, psock);
- if (!ret) {
- wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
- ret = vsock_has_data(sk, psock);
+ while (1) {
+ if (vsock_has_data(sk, psock)) {
+ ret = 1;
+ break;
+ }
+
+ if (sk->sk_err) {
+ ret = -sk->sk_err;
+ break;
+ }
+
+ if ((sk->sk_shutdown & RCV_SHUTDOWN) ||
+ (vsk->peer_shutdown & SEND_SHUTDOWN)) {
+ ret = 0;
+ break;
+ }
+
+ /* virtio_vsock_reset_sock() sets no shutdown bits, and
+ * SO_ERROR clears sk_err: check the state the way
+ * __vsock_connectible_recvmsg() does.
+ */
+ if (sk->sk_state != TCP_ESTABLISHED) {
+ ret = sock_flag(sk, SOCK_DONE) ? 0 : -ENOTCONN;
+ break;
+ }
+
+ if (!timeo) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ release_sock(sk);
+ timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
+ lock_sock(sk);
+
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeo);
+ break;
+ }
}
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
remove_wait_queue(sk_sleep(sk), &wait);
@@ -101,11 +132,14 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
while (copied == 0) {
long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+ int data = vsock_msg_wait_data(sk, psock, timeo);
- if (!vsock_msg_wait_data(sk, psock, timeo)) {
- copied = -EAGAIN;
+ if (data < 0) {
+ copied = data;
break;
}
+ if (!data)
+ break;
if (sk_psock_queue_empty(psock)) {
release_sock(sk);
--
2.56.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net v3 2/2] vsock/bpf: fix zero-length, MSG_OOB and MSG_ERRQUEUE reads in recvmsg
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
@ 2026-10-28 17:55 ` Jerome Mohm via B4 Relay
-1 siblings, 0 replies; 8+ messages in thread
From: Jerome Mohm @ 2026-10-28 17:55 UTC (permalink / raw)
To: Stefano Garzarella, Bobby Eshleman, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Michael S. Tsirkin
Cc: Michal Luczaj, virtualization, netdev, linux-kernel, bpf, stable,
Jerome Mohm
vsock_bpf_recvmsg() sends every read that cannot be served from the
transport's own queue through sk_msg_recvmsg() and its wait loop. Three
kinds of read do not fit that path:
- len == 0: with data queued in the psock ingress queue (for example
after an SK_PASS verdict), sk_msg_recvmsg() copies nothing and
returns 0, and the wait reports data ready at once, so the loop spins
with lock_sock() held. The vsock delivery worker then blocks on the
same lock and all rx on the transport stops (hung-task).
tcp_bpf, udp_bpf and unix_bpf return 0 early, and
__vsock_connectible_recvmsg() handles len == 0 too.
- MSG_ERRQUEUE: the read only reaches sock_recv_errqueue() when the
native fallback happens to be taken. With empty queues a blocking
recvmsg(MSG_ERRQUEUE) waits for stream data instead of returning
-EAGAIN for an empty error queue. Route it to the native path first,
as tcp_bpf does, so it is also not caught by the len == 0 check.
- MSG_OOB: vsock has no out-of-band data and the native path returns
-EOPNOTSUPP, but sk_msg_recvmsg() ignores the flag and consumes
ordinary stream bytes; with empty queues the read waits for data.
Reject it right after the MSG_ERRQUEUE route and, as
unix_bpf_recvmsg() does, before the len == 0 check.
The len == 0 and MSG_OOB cases were reported by the netdev Sashiko AI
review of earlier, single-patch versions of this fix; the MSG_ERRQUEUE
case was found with the help of an LLM coding assistant (Anthropic's
Claude). Each reproducer is a C program run as root in the guest: it
adds one end of a vsock-loopback stream connection to a BPF sockmap
(CAP_BPF and CAP_NET_ADMIN), for the queued-byte cases with an SK_PASS
stream-verdict program, and issues the reads below. No kernel change or
error injection is needed. The reproducers are available on request.
Testing: on a private VM with a KASAN + lockdep kernel on net, with
reproducers over vsock-loopback. Before this patch: recv(fd, buf, 0, 0)
with a byte in the psock ingress queue spins and the delivery worker
hangs (hung-task); a zero-length recvmsg(MSG_ERRQUEUE) blocks; and
recv() with MSG_OOB waits for data or returns a queued ordinary byte,
which a following plain recv() then misses. After: a zero-length recv()
returns 0 and the next recv() returns the byte; MSG_ERRQUEUE returns
-EAGAIN from the empty error queue; MSG_OOB returns -EOPNOTSUPP at once
and consumes nothing. With both patches of this series applied, the
three single-VM tests of tools/testing/selftests/vsock/vmtest.sh
(vm_server_host_client, vm_client_host_server, vm_loopback; 44
vsock_test cases each) pass, as on net; on both kernels the host-side
runs skip the SO_INQ cases (SO_INQ not supported by the host kernel).
The ns_* tests of vmtest.sh were not run (they need root on the host).
The BPF test_progs sockmap_basic, sockmap_listen and sockmap_redir tests
pass (767 of 767 subtests, among them the three vsock subtests of
sockmap_basic and the 240 AF_VSOCK cases of sockmap_redir).
Fixes: 634f1a7110b4 ("vsock: support sockmap")
Cc: stable@vger.kernel.org
Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
---
net/vmw_vsock/vsock_bpf.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
index 5120911b8143..3edc01268c42 100644
--- a/net/vmw_vsock/vsock_bpf.c
+++ b/net/vmw_vsock/vsock_bpf.c
@@ -111,6 +111,15 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
struct vsock_sock *vsk;
int copied;
+ if (unlikely(flags & MSG_ERRQUEUE))
+ return __vsock_recvmsg(sk, msg, len, flags);
+
+ if (flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ if (!len)
+ return 0;
+
psock = sk_psock_get(sk);
if (unlikely(!psock))
return __vsock_recvmsg(sk, msg, len, flags);
--
2.56.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net v3 2/2] vsock/bpf: fix zero-length, MSG_OOB and MSG_ERRQUEUE reads in recvmsg
@ 2026-10-28 17:55 ` Jerome Mohm via B4 Relay
0 siblings, 0 replies; 8+ messages in thread
From: Jerome Mohm via B4 Relay @ 2026-10-28 17:55 UTC (permalink / raw)
To: Stefano Garzarella, Bobby Eshleman, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Michael S. Tsirkin
Cc: Michal Luczaj, virtualization, netdev, linux-kernel, bpf, stable,
Jerome Mohm
From: Jerome Mohm <jrmmhm.kernel@eldare.de>
vsock_bpf_recvmsg() sends every read that cannot be served from the
transport's own queue through sk_msg_recvmsg() and its wait loop. Three
kinds of read do not fit that path:
- len == 0: with data queued in the psock ingress queue (for example
after an SK_PASS verdict), sk_msg_recvmsg() copies nothing and
returns 0, and the wait reports data ready at once, so the loop spins
with lock_sock() held. The vsock delivery worker then blocks on the
same lock and all rx on the transport stops (hung-task).
tcp_bpf, udp_bpf and unix_bpf return 0 early, and
__vsock_connectible_recvmsg() handles len == 0 too.
- MSG_ERRQUEUE: the read only reaches sock_recv_errqueue() when the
native fallback happens to be taken. With empty queues a blocking
recvmsg(MSG_ERRQUEUE) waits for stream data instead of returning
-EAGAIN for an empty error queue. Route it to the native path first,
as tcp_bpf does, so it is also not caught by the len == 0 check.
- MSG_OOB: vsock has no out-of-band data and the native path returns
-EOPNOTSUPP, but sk_msg_recvmsg() ignores the flag and consumes
ordinary stream bytes; with empty queues the read waits for data.
Reject it right after the MSG_ERRQUEUE route and, as
unix_bpf_recvmsg() does, before the len == 0 check.
The len == 0 and MSG_OOB cases were reported by the netdev Sashiko AI
review of earlier, single-patch versions of this fix; the MSG_ERRQUEUE
case was found with the help of an LLM coding assistant (Anthropic's
Claude). Each reproducer is a C program run as root in the guest: it
adds one end of a vsock-loopback stream connection to a BPF sockmap
(CAP_BPF and CAP_NET_ADMIN), for the queued-byte cases with an SK_PASS
stream-verdict program, and issues the reads below. No kernel change or
error injection is needed. The reproducers are available on request.
Testing: on a private VM with a KASAN + lockdep kernel on net, with
reproducers over vsock-loopback. Before this patch: recv(fd, buf, 0, 0)
with a byte in the psock ingress queue spins and the delivery worker
hangs (hung-task); a zero-length recvmsg(MSG_ERRQUEUE) blocks; and
recv() with MSG_OOB waits for data or returns a queued ordinary byte,
which a following plain recv() then misses. After: a zero-length recv()
returns 0 and the next recv() returns the byte; MSG_ERRQUEUE returns
-EAGAIN from the empty error queue; MSG_OOB returns -EOPNOTSUPP at once
and consumes nothing. With both patches of this series applied, the
three single-VM tests of tools/testing/selftests/vsock/vmtest.sh
(vm_server_host_client, vm_client_host_server, vm_loopback; 44
vsock_test cases each) pass, as on net; on both kernels the host-side
runs skip the SO_INQ cases (SO_INQ not supported by the host kernel).
The ns_* tests of vmtest.sh were not run (they need root on the host).
The BPF test_progs sockmap_basic, sockmap_listen and sockmap_redir tests
pass (767 of 767 subtests, among them the three vsock subtests of
sockmap_basic and the 240 AF_VSOCK cases of sockmap_redir).
Fixes: 634f1a7110b4 ("vsock: support sockmap")
Cc: stable@vger.kernel.org
Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
---
net/vmw_vsock/vsock_bpf.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
index 5120911b8143..3edc01268c42 100644
--- a/net/vmw_vsock/vsock_bpf.c
+++ b/net/vmw_vsock/vsock_bpf.c
@@ -111,6 +111,15 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
struct vsock_sock *vsk;
int copied;
+ if (unlikely(flags & MSG_ERRQUEUE))
+ return __vsock_recvmsg(sk, msg, len, flags);
+
+ if (flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ if (!len)
+ return 0;
+
psock = sk_psock_get(sk);
if (unlikely(!psock))
return __vsock_recvmsg(sk, msg, len, flags);
--
2.56.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH net v3 1/2] vsock/bpf: release sock lock while waiting for data in recvmsg
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
(?)
@ 2026-10-28 18:14 ` sashiko-bot
-1 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-28 18:14 UTC (permalink / raw)
To: Jerome Mohm; +Cc: virtualization, Michael S. Tsirkin, Eugenio Perez
> From: Jerome Mohm <jrmmhm.kernel@eldare.de>
>
> vsock_bpf_recvmsg() takes lock_sock(sk) and holds it across the receive
> loop, including vsock_msg_wait_data(), which sleeps in wait_woken()
> without dropping the lock. When data arrives, the transport's delivery
> context (the vsock-loopback worker, or the virtio/vhost rx path) calls
> virtio_transport_recv_pkt() -> lock_sock() on the same socket and blocks.
> That context is the only one that would queue the skb and wake the
> reader, so neither side makes progress: a blocking recv() hangs until a
> signal arrives or SO_RCVTIMEO expires, and meanwhile the shared delivery
> worker is stalled, so all vsock rx on that transport stops. The
> hung-task watchdog reports the worker:
>
> INFO: task kworker/1:3:107 blocked for more than 5 seconds.
> task:kworker/1:3 state:D Workqueue: vsock-loopback vsock_loopback_work
> [ ... ]
> cases of sockmap_redir).
>
> Fixes: 634f1a7110b4 ("vsock: support sockmap")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261028-kbh3-1-022-fix-v2-v3-0-bc0752b2d3db@eldare.de?part=1
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v3 2/2] vsock/bpf: fix zero-length, MSG_OOB and MSG_ERRQUEUE reads in recvmsg
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
(?)
@ 2026-10-28 18:14 ` sashiko-bot
-1 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-28 18:14 UTC (permalink / raw)
To: Jerome Mohm; +Cc: virtualization, Michael S. Tsirkin, Eugenio Perez
> From: Jerome Mohm <jrmmhm.kernel@eldare.de>
>
> vsock_bpf_recvmsg() sends every read that cannot be served from the
> transport's own queue through sk_msg_recvmsg() and its wait loop. Three
> kinds of read do not fit that path:
>
> - len == 0: with data queued in the psock ingress queue (for example
> after an SK_PASS verdict), sk_msg_recvmsg() copies nothing and
> returns 0, and the wait reports data ready at once, so the loop spins
> with lock_sock() held. The vsock delivery worker then blocks on the
> same lock and all rx on the transport stops (hung-task).
> tcp_bpf, udp_bpf and unix_bpf return 0 early, and
> __vsock_connectible_recvmsg() handles len == 0 too.
>
> - MSG_ERRQUEUE: the read only reaches sock_recv_errqueue() when the
> [ ... ]
> sockmap_basic and the 240 AF_VSOCK cases of sockmap_redir).
>
> Fixes: 634f1a7110b4 ("vsock: support sockmap")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261028-kbh3-1-022-fix-v2-v3-0-bc0752b2d3db@eldare.de?part=2
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-28 18:14 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-28 17:55 [PATCH net v3 0/2] vsock/bpf: fix waiting and flag handling in recvmsg Jerome Mohm
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
2026-10-28 17:55 ` [PATCH net v3 1/2] vsock/bpf: release sock lock while waiting for data " Jerome Mohm
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
2026-10-28 18:14 ` sashiko-bot
2026-10-28 17:55 ` [PATCH net v3 2/2] vsock/bpf: fix zero-length, MSG_OOB and MSG_ERRQUEUE reads " Jerome Mohm
2026-10-28 17:55 ` Jerome Mohm via B4 Relay
2026-10-28 18:14 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.