chiark / gitweb /
core, shared: in deserializing, match same files reached via different paths
authorMichal Schmidt <mschmidt@redhat.com>
Thu, 19 Feb 2015 22:12:38 +0000 (23:12 +0100)
committerMichal Schmidt <mschmidt@redhat.com>
Fri, 20 Feb 2015 02:35:04 +0000 (03:35 +0100)
When dbus.socket is updated like this:
-ListenStream=/var/run/dbus/system_bus_socket
+ListenStream=/run/dbus/system_bus_socket
... and daemon-reload is performed, bad things happen.
During deserialization systemd does not recognize that the two paths
refer to the same named socket and replaces the socket file with a new
one. As a result, applications hang when they try talking to dbus.

Fix this by finding a match not only when the path names are equal, but
also when they point to the same inode.
In socket_address_equal() it is necessary to move the address size
comparison into the abstract sockets branch. For path name sockets the
comparison must not be done and for other families it is redundant
(their sizes are constant and checked by socket_address_verify()).

FIFOs and special files can also have multiple pathnames, so compare the
inodes for them as well. Note that previously the pathname checks used
streq_ptr(), but the paths cannot be NULL.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1186018
src/core/socket.c
src/shared/path-util.c
src/shared/path-util.h
src/shared/socket-util.c

index 48c43a28800447d7a9c58d8932cc660dd8419a05..88aae4815b30da05723d05c91a49e961d0706bfa 100644 (file)
@@ -2100,7 +2100,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
 
                         LIST_FOREACH(port, p, s->ports)
                                 if (p->type == SOCKET_FIFO &&
-                                    streq_ptr(p->path, value+skip))
+                                    path_equal_or_files_same(p->path, value+skip))
                                         break;
 
                         if (p) {
@@ -2119,7 +2119,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
 
                         LIST_FOREACH(port, p, s->ports)
                                 if (p->type == SOCKET_SPECIAL &&
-                                    streq_ptr(p->path, value+skip))
+                                    path_equal_or_files_same(p->path, value+skip))
                                         break;
 
                         if (p) {
@@ -2138,7 +2138,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
 
                         LIST_FOREACH(port, p, s->ports)
                                 if (p->type == SOCKET_MQUEUE &&
-                                    streq_ptr(p->path, value+skip))
+                                    streq(p->path, value+skip))
                                         break;
 
                         if (p) {
index b9db7f1047ab8c6e31b970a63cb9188c7b6a3ef3..70bc1caa2a53ce44092a7c6297f7f3ff4d0e4ab7 100644 (file)
@@ -436,6 +436,10 @@ bool path_equal(const char *a, const char *b) {
         }
 }
 
+bool path_equal_or_files_same(const char *a, const char *b) {
+        return path_equal(a, b) || files_same(a, b) > 0;
+}
+
 char* path_join(const char *root, const char *path, const char *rest) {
         assert(path);
 
index bd0d32473fbd92df5bb734737b285abc36884066..bcf116ed3d57fac2ce7c55ad24d4b93dd1c16fde 100644 (file)
@@ -45,6 +45,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r);
 char* path_kill_slashes(char *path);
 char* path_startswith(const char *path, const char *prefix) _pure_;
 bool path_equal(const char *a, const char *b) _pure_;
+bool path_equal_or_files_same(const char *a, const char *b);
 char* path_join(const char *root, const char *path, const char *rest);
 
 char** path_strv_make_absolute_cwd(char **l);
index c6f64876be4485f6a9c2b4aab41b04b2a094563d..c278d6f9d4eae91480b5b2a2f74de67db40e7c7d 100644 (file)
@@ -325,9 +325,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
         if (a->type != b->type)
                 return false;
 
-        if (a->size != b->size)
-                return false;
-
         if (socket_address_family(a) != socket_address_family(b))
                 return false;
 
@@ -352,14 +349,16 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
                 break;
 
         case AF_UNIX:
-
                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
                         return false;
 
                 if (a->sockaddr.un.sun_path[0]) {
-                        if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
+                        if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
                                 return false;
                 } else {
+                        if (a->size != b->size)
+                                return false;
+
                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
                                 return false;
                 }
@@ -367,7 +366,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
                 break;
 
         case AF_NETLINK:
-
                 if (a->protocol != b->protocol)
                         return false;