1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

serialize: add explicit calls for finishing serialization

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.
This commit is contained in:
Lennart Poettering 2024-12-16 11:29:52 +01:00
parent 4d98709cb2
commit 5d1e57b820
8 changed files with 59 additions and 21 deletions

View 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)

View File

@ -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)

View 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");

View 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;

View 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;
}

View 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);
}

View 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);

View 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) {