]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
_dbus_server_new_for_socket: Properly disconnect during error unwinding
authorSimon McVittie <smcv@collabora.com>
Tue, 21 Nov 2017 14:38:13 +0000 (14:38 +0000)
committerSimon McVittie <smcv@collabora.com>
Fri, 24 Nov 2017 12:17:26 +0000 (12:17 +0000)
_dbus_server_finalize_base() asserts that the socket has been
disconnected, but in some OOM code paths we would call it without
officially disconnecting. Do so.

This means we need to be a bit more careful about what is
socket_disconnect()'s responsibility to clean up, what is
_dbus_server_new_for_socket()'s responsibility, and what is the caller's
responsibility.

Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall <withnall@endlessm.com>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89104

dbus/dbus-server-protected.h
dbus/dbus-server-socket.c
dbus/dbus-server.c

index f613bf34e0d806c91e4ee4c6f69dedb72e04244c..5664b2b4e1508f86955621fa0c8ec7af5baa7970 100644 (file)
@@ -96,6 +96,7 @@ dbus_bool_t _dbus_server_init_base      (DBusServer             *server,
                                          const DBusString       *address,
                                          DBusError              *error);
 void        _dbus_server_finalize_base  (DBusServer             *server);
+void        _dbus_server_disconnect_unlocked (DBusServer        *server);
 dbus_bool_t _dbus_server_add_watch      (DBusServer             *server,
                                          DBusWatch              *watch);
 void        _dbus_server_remove_watch   (DBusServer             *server,
index b5179be6a7ef5a6b3577ddda8e0f214c431f726c..460b535cad446bdba90db5bad570dde2e6d0161d 100644 (file)
@@ -241,8 +241,11 @@ socket_disconnect (DBusServer *server)
           socket_server->watch[i] = NULL;
         }
 
-      _dbus_close_socket (socket_server->fds[i], NULL);
-      _dbus_socket_invalidate (&socket_server->fds[i]);
+      if (_dbus_socket_is_valid (socket_server->fds[i]))
+        {
+          _dbus_close_socket (socket_server->fds[i], NULL);
+          _dbus_socket_invalidate (&socket_server->fds[i]);
+        }
     }
 
   if (socket_server->socket_name != NULL)
@@ -336,10 +339,24 @@ _dbus_server_new_for_socket (DBusSocket       *fds,
                                    socket_server->watch[i]))
         {
           int j;
-          for (j = 0 ; j < i ; j++)
-            _dbus_server_remove_watch (server,
-                                       socket_server->watch[j]);
 
+          /* The caller is still responsible for closing the fds until
+           * we return successfully, so don't let socket_disconnect()
+           * close them */
+          for (j = 0; j < n_fds; j++)
+            _dbus_socket_invalidate (&socket_server->fds[i]);
+
+          /* socket_disconnect() will try to remove all the watches;
+           * make sure it doesn't see the ones that weren't even added
+           * yet */
+          for (j = i; j < n_fds; j++)
+            {
+              _dbus_watch_invalidate (socket_server->watch[i]);
+              _dbus_watch_unref (socket_server->watch[i]);
+              socket_server->watch[i] = NULL;
+            }
+
+          _dbus_server_disconnect_unlocked (server);
           SERVER_UNLOCK (server);
           _dbus_server_finalize_base (&socket_server->base);
           goto failed_2;
index ea9aff2dbe458d31db44a234599a2a37e3d8dcff..d91df8325cd70ed9557d7f3dc90dc0804b773caa 100644 (file)
@@ -764,6 +764,20 @@ dbus_server_unref (DBusServer *server)
     }
 }
 
+void
+_dbus_server_disconnect_unlocked (DBusServer *server)
+{
+  _dbus_assert (server->vtable->disconnect != NULL);
+
+  if (!server->disconnected)
+    {
+      /* this has to be first so recursive calls to disconnect don't happen */
+      server->disconnected = TRUE;
+
+      (* server->vtable->disconnect) (server);
+    }
+}
+
 /**
  * Releases the server's address and stops listening for
  * new clients. If called more than once, only the first
@@ -780,15 +794,7 @@ dbus_server_disconnect (DBusServer *server)
   dbus_server_ref (server);
   SERVER_LOCK (server);
 
-  _dbus_assert (server->vtable->disconnect != NULL);
-
-  if (!server->disconnected)
-    {
-      /* this has to be first so recursive calls to disconnect don't happen */
-      server->disconnected = TRUE;
-      
-      (* server->vtable->disconnect) (server);
-    }
+  _dbus_server_disconnect_unlocked (server);
 
   SERVER_UNLOCK (server);
   dbus_server_unref (server);