Skip to content

Commit f8f9ab2

Browse files
committed
io_uring/net: ensure socket is marked connected on connect retry
io_uring does non-blocking connection attempts, which can yield some unexpected results if a connect request is re-attempted by an an application. This is equivalent to the following sync syscall sequence: sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP); connect(sock, &addr, sizeof(addr); ret == -1 and errno == EINPROGRESS expected here. Now poll for POLLOUT on sock, and when that returns, we expect the socket to be connected. But if we follow that procedure with: connect(sock, &addr, sizeof(addr)); you'd expect ret == -1 and errno == EISCONN here, but you actually get ret == 0. If we attempt the connection one more time, then we get EISCON as expected. io_uring used to do this, but turns out that bluetooth fails with EBADFD if you attempt to re-connect. Also looks like EISCONN _could_ occur with this sequence. Retain the ->in_progress logic, but work-around a potential EISCONN or EBADFD error and only in those cases look at the sock_error(). This should work in general and avoid the odd sequence of a repeated connect request returning success when the socket is already connected. This is all a side effect of the socket state being in a CONNECTING state when we get EINPROGRESS, and only a re-connect or other related operation will turn that into CONNECTED. Cc: stable@vger.kernel.org Fixes: 3fb1bd6 ("io_uring/net: handle -EINPROGRESS correct for IORING_OP_CONNECT") Link: axboe/liburing#980 Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 0df96fb commit f8f9ab2

File tree

1 file changed

+11
-13
lines changed

1 file changed

+11
-13
lines changed

io_uring/net.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,16 +1461,6 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
14611461
int ret;
14621462
bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
14631463

1464-
if (connect->in_progress) {
1465-
struct socket *socket;
1466-
1467-
ret = -ENOTSOCK;
1468-
socket = sock_from_file(req->file);
1469-
if (socket)
1470-
ret = sock_error(socket->sk);
1471-
goto out;
1472-
}
1473-
14741464
if (req_has_async_data(req)) {
14751465
io = req->async_data;
14761466
} else {
@@ -1490,9 +1480,7 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
14901480
&& force_nonblock) {
14911481
if (ret == -EINPROGRESS) {
14921482
connect->in_progress = true;
1493-
return -EAGAIN;
1494-
}
1495-
if (ret == -ECONNABORTED) {
1483+
} else if (ret == -ECONNABORTED) {
14961484
if (connect->seen_econnaborted)
14971485
goto out;
14981486
connect->seen_econnaborted = true;
@@ -1506,6 +1494,16 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
15061494
memcpy(req->async_data, &__io, sizeof(__io));
15071495
return -EAGAIN;
15081496
}
1497+
if (connect->in_progress) {
1498+
/*
1499+
* At least bluetooth will return -EBADFD on a re-connect
1500+
* attempt, and it's (supposedly) also valid to get -EISCONN
1501+
* which means the previous result is good. For both of these,
1502+
* grab the sock_error() and use that for the completion.
1503+
*/
1504+
if (ret == -EBADFD || ret == -EISCONN)
1505+
ret = sock_error(sock_from_file(req->file)->sk);
1506+
}
15091507
if (ret == -ERESTARTSYS)
15101508
ret = -EINTR;
15111509
out:

0 commit comments

Comments
 (0)