From 4da159bc53d3db4a98c923d3f57d656713ff5813 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 26 Aug 2023 00:39:23 +0800 Subject: [PATCH] core,systemctl: refuse switching root if we're not in initrd --- NEWS | 4 ++++ TODO | 5 ----- src/core/dbus-manager.c | 27 ++++++++++++++++----------- src/systemctl/systemctl-switch-root.c | 4 ++++ 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 3acbafc44af..8ba35e5b315 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,10 @@ CHANGES WITH 255 in spe: by default when combined with --scope, will be changed in a future release to be enabled by default. + * "systemctl switch-root" is now restricted to initrd transtions only. + Transitions between real systems should be done with "systemctl soft-reboot" + instead. + Device Management: * udev will now create symlinks to loopback block devices in the diff --git a/TODO b/TODO index eda525dc443..20d81c4ba7f 100644 --- a/TODO +++ b/TODO @@ -274,11 +274,6 @@ Features: idea, and specifically works around the fact the autofs ignores busy by mount namespaces) -* refuse using the switch-root operation without /etc/initrd-release. Now - that we have a concept of userspace reboot, we can clearly say: switch-root - is for transitioning from initrd to host (or initrd to next initrd), while - userspace reboot is for switching host to next version of the host. - * mount most file systems with a restrictive uidmap. e.g. mount /usr/ with a uidmap that blocks out anything outside 0…1000 (i.e. system users) and similar. diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 253c315277e..3d1a38b21ed 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -26,6 +26,7 @@ #include "fd-util.h" #include "fileio.h" #include "format-util.h" +#include "initrd-util.h" #include "install.h" #include "log.h" #include "manager-dump.h" @@ -1880,17 +1881,21 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er } /* Safety check */ - if (isempty(init)) { - r = path_is_os_tree(root); - if (r < 0) - return sd_bus_error_set_errnof(error, r, - "Failed to determine whether root path '%s' contains an OS tree: %m", - root); - if (r == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, - "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", - root); - } else { + if (!in_initrd()) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Not in initrd, refusing switch-root operation."); + + r = path_is_os_tree(root); + if (r < 0) + return sd_bus_error_set_errnof(error, r, + "Failed to determine whether root path '%s' contains an OS tree: %m", + root); + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", + root); + + if (!isempty(init)) { if (!path_is_valid(init)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' is not a valid path.", init); diff --git a/src/systemctl/systemctl-switch-root.c b/src/systemctl/systemctl-switch-root.c index cc31cf0e196..ae4a1a72c2b 100644 --- a/src/systemctl/systemctl-switch-root.c +++ b/src/systemctl/systemctl-switch-root.c @@ -5,6 +5,7 @@ #include "bus-locator.h" #include "chase.h" #include "fd-util.h" +#include "initrd-util.h" #include "parse-util.h" #include "path-util.h" #include "proc-cmdline.h" @@ -63,6 +64,9 @@ int verb_switch_root(int argc, char *argv[], void *userdata) { } else root = "/sysroot"; + if (!in_initrd()) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not in initrd, refusing switch-root operation."); + if (argc >= 3) init = argv[2]; else {