]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
serialize: add explicit calls for finishing serialization
authorLennart Poettering <lennart@poettering.net>
Mon, 16 Dec 2024 10:29:52 +0000 (11:29 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 17 Dec 2024 17:26:15 +0000 (18:26 +0100)
These new calls will do three things:

1. in case of FILE* stuff: flush any pending bytes onto the fd, just in
   case
2. seal the backing memfd
3. seek back to the beginning.

Note that this adds sealing to serialization: once we serialized fully,
we'll seal the thing off for further modifications, before we pass the
fd over to the target process. This should add a bit of robustness, and
maybe finds a bug or two one day, if we accidentally write to a
serialization that is complete.

src/core/execute.c
src/core/main.c
src/core/manager-serialize.c
src/core/manager.c
src/shared/exec-util.c
src/shared/serialize.c
src/shared/serialize.h
src/test/test-fd-util.c

index 3c8d4c2be1211363e939d829d797c81972269f50..f12667f17549c2cf00352a738216dd1f44c4fc53 100644 (file)
@@ -516,8 +516,9 @@ int exec_spawn(
         if (r < 0)
                 return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
 
-        if (fseeko(f, 0, SEEK_SET) < 0)
-                return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m");
+        r = finish_serialization_file(f);
+        if (r < 0)
+                return log_unit_error_errno(unit, r, "Failed to finish serialization stream: %m");
 
         r = fd_cloexec(fileno(f), false);
         if (r < 0)
index 172742c76985121215cdb0251adfdd1be2321519..693293ac9c30bac705363cd38086e5e6c0f6d553 100644 (file)
 #include "clock-warp.h"
 #include "conf-parser.h"
 #include "confidential-virt.h"
+#include "constants.h"
 #include "copy.h"
 #include "cpu-set-util.h"
 #include "crash-handler.h"
 #include "dbus-manager.h"
 #include "dbus.h"
-#include "constants.h"
 #include "dev-setup.h"
 #include "efi-random.h"
 #include "efivars.h"
@@ -87,6 +87,7 @@
 #include "seccomp-util.h"
 #include "selinux-setup.h"
 #include "selinux-util.h"
+#include "serialize.h"
 #include "signal-util.h"
 #include "smack-setup.h"
 #include "special.h"
@@ -1233,14 +1234,14 @@ static int prepare_reexecute(
         assert(ret_f);
         assert(ret_fds);
 
-        r = manager_open_serialization(m, &f);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create serialization file: %m");
-
         /* Make sure nothing is really destructed when we shut down */
         m->n_reloading++;
         bus_manager_send_reloading(m, true);
 
+        r = manager_open_serialization(m, &f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create serialization file: %m");
+
         fds = fdset_new();
         if (!fds)
                 return log_oom();
@@ -1249,8 +1250,9 @@ static int prepare_reexecute(
         if (r < 0)
                 return r;
 
-        if (fseeko(f, 0, SEEK_SET) < 0)
-                return log_error_errno(errno, "Failed to rewind serialization fd: %m");
+        r = finish_serialization_file(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to finish serialization file: %m");
 
         r = fd_cloexec(fileno(f), false);
         if (r < 0)
index 3f624619dfd19599ea1e5c652bacd5a9fab961d6..e8bc3d58b75520c924432a26853cec7bf3b20bbb 100644 (file)
@@ -186,10 +186,6 @@ int manager_serialize(
                         return r;
         }
 
-        r = fflush_and_check(f);
-        if (r < 0)
-                return log_error_errno(r, "Failed to flush serialization: %m");
-
         r = bus_fdset_add_all(m, fds);
         if (r < 0)
                 return log_error_errno(r, "Failed to add bus sockets to serialization: %m");
index f21a4f7ceb828c7b3fd24da8b17f31da829b75a0..343bc83a774bde59c1e171856a03c8ba6f5ec5b3 100644 (file)
@@ -80,6 +80,7 @@
 #include "rlimit-util.h"
 #include "rm-rf.h"
 #include "selinux-util.h"
+#include "serialize.h"
 #include "signal-util.h"
 #include "socket-util.h"
 #include "special.h"
@@ -3762,8 +3763,9 @@ int manager_reload(Manager *m) {
         if (r < 0)
                 return r;
 
-        if (fseeko(f, 0, SEEK_SET) < 0)
-                return log_error_errno(errno, "Failed to seek to beginning of serialization: %m");
+        r = finish_serialization_file(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to finish serialization: %m");
 
         /* ðŸ’€ This is the point of no return, from here on there is no way back. ðŸ’€ */
         reloading = NULL;
index fbd66acd9a1a3d1b93b256c319df3e7f0fa130ca..c673e344ee7162cba6684b3bfa3adce644fdc571 100644 (file)
@@ -199,8 +199,9 @@ static int do_execute(
                         }
 
                         if (callbacks) {
-                                if (lseek(fd, 0, SEEK_SET) < 0)
-                                        return log_error_errno(errno, "Failed to seek on serialization fd: %m");
+                                r = finish_serialization_fd(fd);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to finish serialization fd: %m");
 
                                 r = callbacks[STDOUT_GENERATE](TAKE_FD(fd), callback_args[STDOUT_GENERATE]);
                                 if (r < 0)
@@ -290,12 +291,14 @@ int execute_strv(
         if (!callbacks)
                 return 0;
 
-        if (lseek(fd, 0, SEEK_SET) < 0)
-                return log_error_errno(errno, "Failed to rewind serialization fd: %m");
+        r = finish_serialization_fd(fd);
+        if (r < 0)
+                return log_error_errno(r, "Failed to finish serialization fd: %m");
 
         r = callbacks[STDOUT_CONSUME](TAKE_FD(fd), callback_args[STDOUT_CONSUME]);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse returned data: %m");
+
         return 0;
 }
 
index 8fce19ce90335f777e12caea833a8e4c2508349b..4d9ee6cc32113c25d1b9a190d1bf4b6c2f90bd07 100644 (file)
@@ -549,7 +549,7 @@ void deserialize_ratelimit(RateLimit *rl, const char *name, const char *value) {
 int open_serialization_fd(const char *ident) {
         assert(ident);
 
-        int fd = memfd_new(ident);
+        int fd = memfd_new_full(ident, MFD_ALLOW_SEALING);
         if (fd < 0)
                 return fd;
 
@@ -572,6 +572,33 @@ int open_serialization_file(const char *ident, FILE **ret) {
                 return -errno;
 
         *ret = TAKE_PTR(f);
-
         return 0;
 }
+
+int finish_serialization_fd(int fd) {
+        assert(fd >= 0);
+
+        if (lseek(fd, 0, SEEK_SET) < 0)
+                return -errno;
+
+        return memfd_set_sealed(fd);
+}
+
+int finish_serialization_file(FILE *f) {
+        int r;
+
+        assert(f);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return r;
+
+        if (fseeko(f, 0, SEEK_SET) < 0)
+                return -errno;
+
+        int fd = fileno(f);
+        if (fd < 0)
+                return -EBADF;
+
+        return memfd_set_sealed(fd);
+}
index 355eff9b8ffe571021dbc5cae97fe0c74bc23095..dc753465c4b84578625c8191e6eb7876d9987089 100644 (file)
@@ -51,3 +51,6 @@ void deserialize_ratelimit(RateLimit *rl, const char *name, const char *value);
 
 int open_serialization_fd(const char *ident);
 int open_serialization_file(const char *ident, FILE **ret);
+
+int finish_serialization_fd(int fd);
+int finish_serialization_file(FILE *f);
index a0d0bc731ae5147d39d554983681f09c76b48541..2ebc776f479f1f8261d84990a7265c8b686450db 100644 (file)
@@ -127,6 +127,8 @@ TEST(open_serialization_fd) {
         assert_se(fd >= 0);
 
         assert_se(write(fd, "test\n", 5) == 5);
+
+        assert_se(finish_serialization_fd(fd) >= 0);
 }
 
 TEST(open_serialization_file) {
@@ -138,6 +140,8 @@ TEST(open_serialization_file) {
         assert_se(f);
 
         assert_se(fwrite("test\n", 1, 5, f) == 5);
+
+        assert_se(finish_serialization_file(f) >= 0);
 }
 
 TEST(fd_move_above_stdio) {