diff --git a/src/core/execute.c b/src/core/execute.c index 3c8d4c2be12..f12667f1754 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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) diff --git a/src/core/main.c b/src/core/main.c index 172742c7698..693293ac9c3 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -34,12 +34,12 @@ #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) diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index 3f624619dfd..e8bc3d58b75 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -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"); diff --git a/src/core/manager.c b/src/core/manager.c index f21a4f7ceb8..343bc83a774 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -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; diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index fbd66acd9a1..c673e344ee7 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -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; } diff --git a/src/shared/serialize.c b/src/shared/serialize.c index 8fce19ce903..4d9ee6cc321 100644 --- a/src/shared/serialize.c +++ b/src/shared/serialize.c @@ -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); +} diff --git a/src/shared/serialize.h b/src/shared/serialize.h index 355eff9b8ff..dc753465c4b 100644 --- a/src/shared/serialize.h +++ b/src/shared/serialize.h @@ -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); diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index a0d0bc731ae..2ebc776f479 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -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) {