swrap: make swrap_accept() more resilient against races related to already disconnect...
authorStefan Metzmacher <metze@samba.org>
Fri, 5 Feb 2021 11:13:12 +0000 (12:13 +0100)
committerAndreas Schneider <asn@samba.org>
Fri, 5 Feb 2021 13:11:31 +0000 (14:11 +0100)
Callers of accept() expect to get ECONNABORTED instead of a disconnected
socket.

Even on Linux we have a potential race calling libc_getsockname()
after accept(), so we map ENOTCONN to ECONNABORTED.

We should do all syscalls in order to have peer and sockname, before
doing in memory things like calling sockaddr_convert_from_un().

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/socket_wrapper.c

index 5839a5c65c8091e83bad298817dbc167e2f0d193..d72b31f0821093e291f46b092719e0455a652fd1 100644 (file)
@@ -3642,10 +3642,12 @@ static int swrap_accept(int s,
        ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen);
 #endif
        if (ret == -1) {
-               if (errno == ENOTSOCK) {
+               int saved_errno = errno;
+               if (saved_errno == ENOTSOCK) {
                        /* Remove stale fds */
                        swrap_remove_stale(s);
                }
+               errno = saved_errno;
                return ret;
        }
 
@@ -3654,6 +3656,23 @@ static int swrap_accept(int s,
        /* Check if we have a stale fd and remove it */
        swrap_remove_stale(fd);
 
+       ret = libc_getsockname(fd,
+                              &un_my_addr.sa.s,
+                              &un_my_addr.sa_socklen);
+       if (ret == -1) {
+               int saved_errno = errno;
+               libc_close(fd);
+               if (saved_errno == ENOTCONN) {
+                       /*
+                        * If the connection is already disconnected
+                        * we should return ECONNABORTED.
+                        */
+                       saved_errno = ECONNABORTED;
+               }
+               errno = saved_errno;
+               return ret;
+       }
+
        SWRAP_LOCK_SI(parent_si);
 
        ret = sockaddr_convert_from_un(parent_si,
@@ -3663,8 +3682,10 @@ static int swrap_accept(int s,
                                       &in_addr.sa.s,
                                       &in_addr.sa_socklen);
        if (ret == -1) {
+               int saved_errno = errno;
                SWRAP_UNLOCK_SI(parent_si);
                libc_close(fd);
+               errno = saved_errno;
                return ret;
        }
 
@@ -3692,14 +3713,6 @@ static int swrap_accept(int s,
                *addrlen = in_addr.sa_socklen;
        }
 
-       ret = libc_getsockname(fd,
-                              &un_my_addr.sa.s,
-                              &un_my_addr.sa_socklen);
-       if (ret == -1) {
-               libc_close(fd);
-               return ret;
-       }
-
        ret = sockaddr_convert_from_un(child_si,
                                       &un_my_addr.sa.un,
                                       un_my_addr.sa_socklen,
@@ -3707,7 +3720,9 @@ static int swrap_accept(int s,
                                       &in_my_addr.sa.s,
                                       &in_my_addr.sa_socklen);
        if (ret == -1) {
+               int saved_errno = errno;
                libc_close(fd);
+               errno = saved_errno;
                return ret;
        }