core, shared: in deserializing, match same files reached via different paths

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
(cherry picked from commit c78e47a61f)
(cherry picked from commit 25e6978bb3)
This commit is contained in:
Michal Schmidt
2015-03-23 02:23:52 -04:00
committed by Zbigniew Jędrzejewski-Szmek
parent 67ca59c0e3
commit cd9740bae3
4 changed files with 12 additions and 9 deletions
+3 -3
View File
@@ -2097,7 +2097,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) {
@@ -2116,7 +2116,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) {
@@ -2135,7 +2135,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) {
+4
View 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);
+1
View 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);
+4 -6
View 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;