]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: serialize/deserialize varlink sockets for pid1
authorAnita Zhang <the.anitazha@gmail.com>
Wed, 5 Oct 2022 07:13:32 +0000 (00:13 -0700)
committerAnita Zhang <the.anitazha@gmail.com>
Fri, 14 Oct 2022 16:54:05 +0000 (09:54 -0700)
Fixes #20330

src/core/manager-serialize.c
src/shared/meson.build
src/shared/varlink-internal.h [new file with mode: 0644]
src/shared/varlink.c

index 914bd92e36bab564cb794dd4a6a63fbba81b78a2..27cb0925aeb77cacb48111a073d352fd6d5d5fed 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "clean-ipc.h"
+#include "core-varlink.h"
 #include "dbus.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -13,6 +14,7 @@
 #include "syslog-util.h"
 #include "unit-serialize.h"
 #include "user-util.h"
+#include "varlink-internal.h"
 
 int manager_open_serialization(Manager *m, FILE **ret_f) {
         _cleanup_close_ int fd = -1;
@@ -175,6 +177,10 @@ int manager_serialize(
         if (r < 0)
                 return r;
 
+        r = varlink_server_serialize(m->varlink_server, f, fds);
+        if (r < 0)
+                return r;
+
         (void) fputc('\n', f);
 
         HASHMAP_FOREACH_KEY(u, t, m->units) {
@@ -290,6 +296,7 @@ static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
 }
 
 int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
+        bool deserialize_varlink_sockets = false;
         int r = 0;
 
         assert(m);
@@ -516,7 +523,32 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
 
                         if (strv_extend(&m->deserialized_subscribed, val) < 0)
                                 return -ENOMEM;
+                } else if ((val = startswith(l, "varlink-server-socket-address="))) {
+                        if (!m->varlink_server && MANAGER_IS_SYSTEM(m)) {
+                                _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
+
+                                r = manager_setup_varlink_server(m, &s);
+                                if (r < 0) {
+                                        log_warning_errno(r, "Failed to setup varlink server, ignoring: %m");
+                                        continue;
+                                }
+
+                                r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
+                                if (r < 0) {
+                                        log_warning_errno(r, "Failed to attach varlink connection to event loop, ignoring: %m");
+                                        continue;
+                                }
+
+                                m->varlink_server = TAKE_PTR(s);
+                                deserialize_varlink_sockets = true;
+                        }
 
+                        /* To void unnecessary deserialization (i.e. during reload vs. reexec) we only deserialize
+                         * the FDs if we had to create a new m->varlink_server. The deserialize_varlink_sockets flag
+                         * is initialized outside of the loop, is flipped after the VarlinkServer is setup, and
+                         * remains set until all serialized contents are handled. */
+                        if (deserialize_varlink_sockets)
+                                (void) varlink_server_deserialize_one(m->varlink_server, val, fds);
                 } else {
                         ManagerTimestamp q;
 
index e805e9b898cfa95163d33b35ca3532929d2a8438..9e11e1393448b7d28ffd0cd418be9a08578a9d40 100644 (file)
@@ -326,6 +326,7 @@ shared_sources = files(
         'utmp-wtmp.h',
         'varlink.c',
         'varlink.h',
+        'varlink-internal.h',
         'verb-log-control.c',
         'verb-log-control.h',
         'verbs.c',
diff --git a/src/shared/varlink-internal.h b/src/shared/varlink-internal.h
new file mode 100644 (file)
index 0000000..715202a
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdio.h>
+
+#include "fdset.h"
+#include "varlink.h"
+
+int varlink_server_serialize(VarlinkServer *s, FILE *f, FDSet *fds);
+int varlink_server_deserialize_one(VarlinkServer *s, const char *value, FDSet *fds);
index 8b331be6672d79d4c9c0a899abf79651f87c3d6f..4f7ac976891adc7af84d12ecaec230bf173098f4 100644 (file)
@@ -12,6 +12,7 @@
 #include "list.h"
 #include "process-util.h"
 #include "selinux-util.h"
+#include "serialize.h"
 #include "set.h"
 #include "socket-util.h"
 #include "string-table.h"
@@ -21,6 +22,7 @@
 #include "umask-util.h"
 #include "user-util.h"
 #include "varlink.h"
+#include "varlink-internal.h"
 
 #define VARLINK_DEFAULT_CONNECTIONS_MAX 4096U
 #define VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX 1024U
@@ -2577,3 +2579,84 @@ int varlink_server_set_description(VarlinkServer *s, const char *description) {
 
         return free_and_strdup(&s->description, description);
 }
+
+int varlink_server_serialize(VarlinkServer *s, FILE *f, FDSet *fds) {
+        assert(f);
+        assert(fds);
+
+        if (!s)
+                return 0;
+
+        LIST_FOREACH(sockets, ss, s->sockets) {
+                int copy;
+
+                assert(ss->address);
+                assert(ss->fd >= 0);
+
+                fprintf(f, "varlink-server-socket-address=%s", ss->address);
+
+                /* If we fail to serialize the fd, it will be considered an error during deserialization */
+                copy = fdset_put_dup(fds, ss->fd);
+                if (copy < 0)
+                        return copy;
+
+                fprintf(f, " varlink-server-socket-fd=%i", copy);
+
+                fputc('\n', f);
+        }
+
+        return 0;
+}
+
+int varlink_server_deserialize_one(VarlinkServer *s, const char *value, FDSet *fds) {
+        _cleanup_(varlink_server_socket_freep) VarlinkServerSocket *ss = NULL;
+        _cleanup_free_ char *address = NULL;
+        const char *v = ASSERT_PTR(value);
+        int r, fd = -1;
+        char *buf;
+        size_t n;
+
+        assert(s);
+        assert(fds);
+
+        n = strcspn(v, " ");
+        address = strndup(v, n);
+        if (!address)
+                return log_oom_debug();
+
+        if (v[n] != ' ')
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Failed to deserialize VarlinkServerSocket: %s: %m", value);
+        v = startswith(v + n + 1, "varlink-server-socket-fd=");
+        if (!v)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Failed to deserialize VarlinkServerSocket fd %s: %m", value);
+
+        n = strcspn(v, " ");
+        buf = strndupa_safe(v, n);
+
+        r = safe_atoi(buf, &fd);
+        if (r < 0)
+                return log_debug_errno(r, "Unable to parse VarlinkServerSocket varlink-server-socket-fd=%s: %m", buf);
+
+        if (!fdset_contains(fds, fd))
+                return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
+                                       "VarlinkServerSocket varlink-server-socket-fd= has unknown fd %d: %m", fd);
+
+        ss = new(VarlinkServerSocket, 1);
+        if (!ss)
+                return log_oom_debug();
+
+        *ss = (VarlinkServerSocket) {
+                .server = s,
+                .address = TAKE_PTR(address),
+                .fd = fdset_remove(fds, fd),
+        };
+
+        r = varlink_server_add_socket_event_source(s, ss, SD_EVENT_PRIORITY_NORMAL);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to add VarlinkServerSocket event source to the event loop: %m");
+
+        LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss));
+        return 0;
+}