• Jens Axboe's avatar
    io_uring/net: ensure socket is marked connected on connect retry · f8f9ab2d
    Jens Axboe authored
    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: 3fb1bd68 ("io_uring/net: handle -EINPROGRESS correct for IORING_OP_CONNECT")
    Link: https://github.com/axboe/liburing/issues/980Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    f8f9ab2d
net.c 38.1 KB