From 77defcf5382a557189350f928967d676510e362c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Sat, 9 Mar 2019 22:30:45 +0200 Subject: [PATCH 1/3] systemctl: restore "systemctl reboot ARG" functionality Commit d85515edcf9700dc068201ab9f7103f04f3b25b2 changed logic how reboot is executed. That commit changed behavior to use emergency action reboot code path to perform the reboot. This inadvertently broke rebooting with argument: $ systemctl reboot custom-reason Restore original behavior so that if reboot service unit similar to systemd-reboot.service is executed it is possible to override reboot reason with "systemctl reboot ARG". When "systemctl reboot ARG" is executed ARG is placed in file /run/systemd/reboot-param and reboot is issued using logind's Reboot dbus-service. If RebootArgument is specified in systemd-reboot.service it takes precedence over what systemctl sets. Fixes: #11828 --- src/core/emergency-action.c | 4 ++-- src/shared/reboot-util.c | 5 ++++- src/shared/reboot-util.h | 2 +- src/systemctl/systemctl.c | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 9731aef5c44..09f8d740927 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -47,7 +47,7 @@ void emergency_action( case EMERGENCY_ACTION_REBOOT: log_and_status(m, warn, "Rebooting", reason); - (void) update_reboot_parameter_and_warn(reboot_arg); + (void) update_reboot_parameter_and_warn(reboot_arg, true); (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); break; @@ -55,7 +55,7 @@ void emergency_action( case EMERGENCY_ACTION_REBOOT_FORCE: log_and_status(m, warn, "Forcibly rebooting", reason); - (void) update_reboot_parameter_and_warn(reboot_arg); + (void) update_reboot_parameter_and_warn(reboot_arg, true); m->objective = MANAGER_REBOOT; break; diff --git a/src/shared/reboot-util.c b/src/shared/reboot-util.c index ca40159b966..6d5eee03173 100644 --- a/src/shared/reboot-util.c +++ b/src/shared/reboot-util.c @@ -12,10 +12,13 @@ #include "umask-util.h" #include "virt.h" -int update_reboot_parameter_and_warn(const char *parameter) { +int update_reboot_parameter_and_warn(const char *parameter, bool keep) { int r; if (isempty(parameter)) { + if (keep) + return 0; + if (unlink("/run/systemd/reboot-param") < 0) { if (errno == ENOENT) return 0; diff --git a/src/shared/reboot-util.h b/src/shared/reboot-util.h index d459333efcc..ac59b7d79c6 100644 --- a/src/shared/reboot-util.h +++ b/src/shared/reboot-util.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -int update_reboot_parameter_and_warn(const char *parameter); +int update_reboot_parameter_and_warn(const char *parameter, bool keep); typedef enum RebootFlags { REBOOT_LOG = 1 << 0, /* log about what we are going to do and all errors */ diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index afe6f84f774..d49d3878a9f 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3735,7 +3735,7 @@ static int start_special(int argc, char *argv[], void *userdata) { return r; if (a == ACTION_REBOOT && argc > 1) { - r = update_reboot_parameter_and_warn(argv[1]); + r = update_reboot_parameter_and_warn(argv[1], false); if (r < 0) return r; @@ -8444,7 +8444,7 @@ static int halt_parse_argv(int argc, char *argv[]) { } if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) { - r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL); + r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false); if (r < 0) return r; } else if (optind < argc) From ce7f10707d069f87a25f79c17bb5fe593c4bb4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Mon, 11 Mar 2019 23:18:29 +0200 Subject: [PATCH 2/3] logind: relocate function return_test_polkit() Relocate function return_test_polkit() upper in file for easier access from other functions. --- src/login/logind-dbus.c | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 003ab45461a..795fc3b645b 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -168,6 +168,32 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char return 0; } +static int return_test_polkit( + sd_bus_message *message, + int capability, + const char *action, + const char **details, + uid_t good_user, + sd_bus_error *e) { + + const char *result; + bool challenge; + int r; + + r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e); + if (r < 0) + return r; + + if (r > 0) + result = "yes"; + else if (challenge) + result = "challenge"; + else + result = "no"; + + return sd_bus_reply_method_return(message, "s", result); +} + static int property_get_idle_hint( sd_bus *bus, const char *path, @@ -2488,32 +2514,6 @@ static int method_set_reboot_to_firmware_setup( return sd_bus_reply_method_return(message, NULL); } -static int return_test_polkit( - sd_bus_message *message, - int capability, - const char *action, - const char **details, - uid_t good_user, - sd_bus_error *e) { - - const char *result; - bool challenge; - int r; - - r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e); - if (r < 0) - return r; - - if (r > 0) - result = "yes"; - else if (challenge) - result = "challenge"; - else - result = "no"; - - return sd_bus_reply_method_return(message, "s", result); -} - static int method_can_reboot_to_firmware_setup( sd_bus_message *message, void *userdata, From 428b296a599d010531c4577d55e1dea007511613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Sat, 9 Mar 2019 22:30:58 +0200 Subject: [PATCH 3/3] logind: Add support for RebootParameter This adds support for user to set & get reboot parameter for reboot. As callee would be next issuing Reboot call same policy checks are being used. If unit file issuing the reboot action defines RebootArgument (or similar) that setting takes precedence. --- src/login/logind-dbus.c | 96 +++++++++++++++++++++++++ src/login/org.freedesktop.login1.conf | 8 +++ src/login/org.freedesktop.login1.policy | 11 +++ src/shared/reboot-util.c | 12 ++++ src/shared/reboot-util.h | 1 + 5 files changed, 128 insertions(+) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 795fc3b645b..5f82b219956 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -32,6 +32,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "reboot-util.h" #include "selinux-util.h" #include "sleep-config.h" #include "special.h" @@ -42,6 +43,7 @@ #include "unit-name.h" #include "user-util.h" #include "utmp-wtmp.h" +#include "virt.h" static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) { @@ -2408,6 +2410,97 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user error); } +static int property_get_reboot_parameter( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + _cleanup_free_ char *parameter = NULL; + int r; + + assert(bus); + assert(reply); + assert(userdata); + + r = read_reboot_parameter(¶meter); + if (r < 0) + return r; + + return sd_bus_message_append(reply, "s", parameter); +} + +static int method_set_reboot_parameter( + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + const char *arg; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &arg); + if (r < 0) + return r; + + r = detect_container(); + if (r < 0) + return r; + if (r > 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Reboot parameter not supported in containers, refusing."); + + r = bus_verify_polkit_async(message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.set-reboot-parameter", + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + + r = update_reboot_parameter_and_warn(arg, false); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_can_reboot_parameter( + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + int r; + + assert(message); + assert(m); + + r = detect_container(); + if (r < 0) + return r; + if (r > 0) /* Inside containers, specifying a reboot parameter, doesn't make much sense */ + return sd_bus_reply_method_return(message, "s", "na"); + + return return_test_polkit( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.set-reboot-parameter", + NULL, + UID_INVALID, + error); +} + static int property_get_reboot_to_firmware_setup( sd_bus *bus, const char *path, @@ -3137,6 +3230,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RebootParameter", "s", property_get_reboot_parameter, 0, 0), SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, 0), SD_BUS_PROPERTY("RebootToBootLoaderMenu", "t", property_get_reboot_to_boot_loader_menu, 0, 0), SD_BUS_PROPERTY("RebootToBootLoaderEntry", "s", property_get_reboot_to_boot_loader_entry, 0, 0), @@ -3213,6 +3307,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanRebootParameter", NULL, "s", method_can_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetRebootParameter", "s", NULL, method_set_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanRebootToBootLoaderMenu", NULL, "s", method_can_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index 5677c15b8a9..f3c13ad89a0 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -190,6 +190,14 @@ send_interface="org.freedesktop.login1.Manager" send_member="CancelScheduledShutdown"/> + + + + diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy index 671384d34e8..6ad6512f5a3 100644 --- a/src/login/org.freedesktop.login1.policy +++ b/src/login/org.freedesktop.login1.policy @@ -337,6 +337,17 @@ + + Configure reboot parameter for kernel's reboot reason driver + Authentication is required to configure reboot parameter for kernel's reboot reason driver. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.reboot + + Indicate to the firmware to boot to setup interface Authentication is required to indicate to the firmware to boot to setup interface. diff --git a/src/shared/reboot-util.c b/src/shared/reboot-util.c index 6d5eee03173..08569e8bf34 100644 --- a/src/shared/reboot-util.c +++ b/src/shared/reboot-util.c @@ -39,6 +39,18 @@ int update_reboot_parameter_and_warn(const char *parameter, bool keep) { return 0; } +int read_reboot_parameter(char **parameter) { + int r; + + assert(parameter); + + r = read_one_line_file("/run/systemd/reboot-param", parameter); + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "Failed to read /run/systemd/reboot-param: %m"); + + return 0; +} + int reboot_with_parameter(RebootFlags flags) { int r; diff --git a/src/shared/reboot-util.h b/src/shared/reboot-util.h index ac59b7d79c6..7bddc91ea60 100644 --- a/src/shared/reboot-util.h +++ b/src/shared/reboot-util.h @@ -9,4 +9,5 @@ typedef enum RebootFlags { REBOOT_FALLBACK = 1 << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */ } RebootFlags; +int read_reboot_parameter(char **parameter); int reboot_with_parameter(RebootFlags flags);