cloexec: set all sockets that are created with SOCK_CLOEXEC
authorLennart Poettering <lennart@poettering.net>
Wed, 6 May 2009 01:41:50 +0000 (03:41 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 20 May 2009 00:09:31 +0000 (02:09 +0200)
Since all socket users enable FD_CLOEXEC anyway we can just do that in
_dbus_open_socket() and be done with it for all cases. By side effect
this allows us to use SOCK_CLOEXEC and hence close the CLOEXEC race.

configure.in
dbus/dbus-server-socket.c
dbus/dbus-server-unix.c
dbus/dbus-sysdeps-unix.c
dbus/dbus-transport-socket.c
dbus/dbus-transport-unix.c

index 7e0c7d5..b087b00 100644 (file)
@@ -816,7 +816,7 @@ fi
 
 AC_CHECK_FUNCS(getpeerucred getpeereid)
 
-AC_CHECK_FUNCS(pipe2)
+AC_CHECK_FUNCS(pipe2 accept4)
 
 #### Abstract sockets
 
index 0cd2bb6..b663e49 100644 (file)
@@ -195,8 +195,6 @@ socket_handle_watch (DBusWatch    *watch,
         }
       else
         {
-         _dbus_fd_set_close_on_exec (client_fd);         
-
           if (!handle_new_client_fd_and_unlock (server, client_fd))
             _dbus_verbose ("Rejected client connection due to lack of memory\n");
         }
@@ -413,9 +411,6 @@ _dbus_server_new_for_tcp_socket (const char     *host,
       goto failed_1;
     }
 
-  for (i = 0 ; i < nlisten_fds ; i++)
-    _dbus_fd_set_close_on_exec (listen_fds[i]);
-
   _dbus_string_init_const (&host_str, host);
   if (!_dbus_string_append (&address, "tcp:host=") ||
       !_dbus_address_append_escaped (&address, &host_str) ||
index 1dda5d1..86a64c8 100644 (file)
@@ -201,8 +201,7 @@ _dbus_server_new_for_domain_socket (const char     *path,
     }
   
   listen_fd = _dbus_listen_unix_socket (path, abstract, error);
-  _dbus_fd_set_close_on_exec (listen_fd);
-  
+
   if (listen_fd < 0)
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
index 9631be1..3312bd1 100644 (file)
@@ -94,9 +94,28 @@ _dbus_open_socket (int              *fd_p,
                    int               protocol,
                    DBusError        *error)
 {
-  *fd_p = socket (domain, type, protocol);
+#ifdef SOCK_CLOEXEC
+  dbus_bool_t cloexec_done;
+
+  *fd_p = socket (domain, type | SOCK_CLOEXEC, protocol);
+  cloexec_done = *fd_p >= 0;
+
+  /* Check if kernel seems to be too old to know SOCK_CLOEXEC */
+  if (*fd_p < 0 && errno == EINVAL)
+#endif
+    {
+      *fd_p = socket (domain, type, protocol);
+    }
+
   if (*fd_p >= 0)
     {
+#ifdef SOCK_CLOEXEC
+      if (!cloexec_done)
+#endif
+        {
+          _dbus_fd_set_close_on_exec(*fd_p);
+        }
+
       _dbus_verbose ("socket fd %d opened\n", *fd_p);
       return TRUE;
     }
@@ -120,6 +139,9 @@ _dbus_open_tcp_socket (int              *fd,
 /**
  * Opens a UNIX domain socket (as in the socket() call).
  * Does not bind the socket.
+ *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param fd return location for socket descriptor
  * @param error return location for an error
  * @returns #FALSE if error is set
@@ -770,6 +792,8 @@ _dbus_write_two (int               fd,
  * requested (it's possible only on Linux; see "man 7 unix" on Linux).
  * On non-Linux abstract socket usage always fails.
  *
+ * This will set FD_CLOEXEC for the socket returned.
+ *
  * @param path the path to UNIX domain socket
  * @param abstract #TRUE to use abstract namespace
  * @param error return location for error code
@@ -906,6 +930,8 @@ _dbus_set_local_creds (int fd, dbus_bool_t on)
  * see "man 7 unix" on Linux).
  * On non-Linux abstract socket usage always fails.
  *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param path the socket name
  * @param abstract #TRUE to use abstract namespace
  * @param error return location for errors
@@ -1042,6 +1068,8 @@ _dbus_listen_unix_socket (const char     *path,
  * and port. The connection fd is returned, and is set up as
  * nonblocking.
  *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param host the host name to connect to
  * @param port the port to connect to
  * @param family the address family to listen on, NULL for all
@@ -1149,6 +1177,8 @@ _dbus_connect_tcp_socket (const char     *host,
  * a random free port is used and returned in the port parameter.
  * If inaddr_any is specified, the hostname is ignored.
  *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param host the host name to listen on
  * @param port the port to listen on, if zero a free port will be used
  * @param family the address family to listen on, NULL for all
@@ -1669,6 +1699,8 @@ _dbus_send_credentials_socket  (int              server_fd,
  * Accepts a connection on a listening socket.
  * Handles EINTR for you.
  *
+ * This will enable FD_CLOEXEC for the returned socket.
+ *
  * @param listen_fd the listen file descriptor
  * @returns the connection fd of the client, or -1 on error
  */
@@ -1678,12 +1710,25 @@ _dbus_accept  (int listen_fd)
   int client_fd;
   struct sockaddr addr;
   socklen_t addrlen;
+#ifdef HAVE_ACCEPT4
+  dbus_bool_t cloexec_done;
+#endif
 
   addrlen = sizeof (addr);
-  
+
  retry:
-  client_fd = accept (listen_fd, &addr, &addrlen);
-  
+
+#ifdef HAVE_ACCEPT4
+  /* We assume that if accept4 is available SOCK_CLOEXEC is too */
+  client_fd = accept4 (listen_fd, &addr, &addrlen, SOCK_CLOEXEC);
+  cloexec_done = client_fd >= 0;
+
+  if (client_fd < 0 && errno == ENOSYS)
+#endif
+    {
+      client_fd = accept (listen_fd, &addr, &addrlen);
+    }
+
   if (client_fd < 0)
     {
       if (errno == EINTR)
@@ -1691,7 +1736,14 @@ _dbus_accept  (int listen_fd)
     }
 
   _dbus_verbose ("client fd %d accepted\n", client_fd);
-  
+
+#ifdef HAVE_ACCEPT4
+  if (!cloexec_done)
+#endif
+    {
+      _dbus_fd_set_close_on_exec(client_fd);
+    }
+
   return client_fd;
 }
 
index c9d4d93..cc49c85 100644 (file)
@@ -1324,8 +1324,6 @@ _dbus_transport_new_for_tcp_socket (const char     *host,
       return NULL;
     }
 
-  _dbus_fd_set_close_on_exec (fd);
-  
   _dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
                  host, port);
   
index a13fde1..777c941 100644 (file)
@@ -85,8 +85,6 @@ _dbus_transport_new_for_domain_socket (const char     *path,
       goto failed_0;
     }
 
-  _dbus_fd_set_close_on_exec (fd);
-  
   _dbus_verbose ("Successfully connected to unix socket %s\n",
                  path);