Re: [PATCH] vsock: use sock_error() to consume sk_err after connect timeout
Phi Nguyen <[email protected]> Tue, 21 Jul 2026 01:34:03 +0800
| Newsgroups | dev.linux.lists.virtualization,org.kernel.vger.linux-kernel,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On 7/20/2026 4:17 PM, Stefano Garzarella wrote: > On Mon, Jul 20, 2026 at 05:57:47AM +0800, Nguyen Dinh Phi wrote: >> After vsock_connect() exits the wait loop due to sk->sk_err being >> set, the error was read but not cleared. This left sk->sk_err set >> for subsequent operations. > > So, is this a fix? If yes, we should put a Fixes tag. > > Also, can you describe how to trigger the issue? > > Because I see this in vsock_connect(), so I thought it was in some way > already handled: > > /* sk_err might have been set as a result of an earlier > * (failed) connect attempt. > */ > sk->sk_err = 0; > This only handles the case where the function following the failed connect is another connect() call. >> Switch to sock_error() which atomically reads and clears sk->sk_err, >> so the error is consumed when returned. >> >> Signed-off-by: Nguyen Dinh Phi <[email protected]> >> Reported-by: [email protected] > > Can you explain how this patch fixes that issue? > (this should be the first information to be put in the commit message IMHO) > > I'd like to understand better if this is a fix of real bug or just an > improvement to the code (which is fine by me). > > Thanks, > Stefano > Here are the steps of the syzkaller reproducer: r0 = socket(AF_VSOCK, SOCK_STREAM, 0) bind(r0, {VMADDR_CID_ANY, PORT}) connect(r0, {VMADDR_CID_LOCAL, PORT}) listen(r0, backlog) r1 = socket(AF_VSOCK, SOCK_STREAM, 0) connect(r1, {VMADDR_CID_LOCAL, PORT}) connect(r0 -> self) -> -1, EPROTO listen(r0) -> 0 connect(r1 -> r0) -> 0 accept(r0) -> -1, EPROTO Basically, it creates a socket (r0) and triggers a self-connect after binding it. This self-connect fails with EPROTO because it loops back to r0 while the socket is still in the TCP_SYN_SENT state, causing it to be incorrectly dispatched to the connecting-client path. The unexpected packet type encountered there sets sk_err to EPROTO. After that, it invokes a listen() call on the same socket. This listen() call succeeds because the kernel's listening path never inspects or clears sk_err. Then, a new socket (r1) is created as a normal client and connects to r0. However, vsock_accept() rejects this incoming connection because the listener's sk_err still holds the EPROTO error from the earlier failed self-connect. This rejection causes the child socket created for r1's connection to never be freed on virtio or hyperv transports; only the VMCI transport implements pending_work to revisit and clean up a rejected socket This patch will prevent the rejection branch to occur in this scenario. I think we might schedule the cleanup worker to run in the rejection path for these transports as well. Thanks, Phi