diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 00492829bd..dc6a7b4b17 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -630,6 +630,14 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \ file (containing firmware measurement data) to read. This allows overriding the default of `/sys/kernel/security/tpm0/binary_bios_measurements`. +`systemd-sleep`: + +* `$SYSTEMD_SLEEP_FREEZE_USER_SESSIONS` - Takes a boolean. When true (the default), + `user.slice` will be frozen during sleep. When false it will not be. We recommend + against using this variable, because it can lead to undesired behavior, especially + for systems that use home directory encryption and for + `systemd-suspend-then-hibernate.service`. + Tools using the Varlink protocol (such as `varlinkctl`) or sd-bus (such as `busctl`): diff --git a/man/systemd-suspend.service.xml b/man/systemd-suspend.service.xml index d8ea8f5f81..9fbca6193f 100644 --- a/man/systemd-suspend.service.xml +++ b/man/systemd-suspend.service.xml @@ -66,7 +66,9 @@ same executables are run, but the first argument is now post. All executables in this directory are executed in parallel, and execution of the action is not continued - until all executables have finished. + until all executables have finished. Note that user.slice will + be frozen while the executables are running, so they should not attempt to + communicate with any user services expecting a reply. Note that scripts or binaries dropped in /usr/lib/systemd/system-sleep/ are intended @@ -90,6 +92,11 @@ sleep.conf.d file. See systemd-sleep.conf5. + + Note that by default these services freeze user.slice while they run. This prevents + the execution of any process in any of the user sessions while the system is entering into and resuming from + sleep. Thus, this prevents the hooks in /usr/lib/systemd/system-sleep/, or any other process + for that matter, from communicating with any user session process during sleep. diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index f1b6f1bcdc..16ad48b386 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -23,10 +23,12 @@ #include "build.h" #include "bus-error.h" #include "bus-locator.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "constants.h" #include "devnum-util.h" #include "efivars.h" +#include "env-util.h" #include "exec-util.h" #include "fd-util.h" #include "fileio.h" @@ -444,38 +446,11 @@ static int custom_timer_suspend(const SleepConfig *sleep_config) { return 1; } -/* Freeze when invoked and thaw on cleanup */ -static int freeze_thaw_user_slice(const char **method) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r; - - if (!method || !*method) - return 0; - - r = bus_connect_system_systemd(&bus); - if (r < 0) - return log_debug_errno(r, "Failed to open connection to systemd: %m"); - - (void) sd_bus_set_method_call_timeout(bus, FREEZE_TIMEOUT); - - r = bus_call_method(bus, bus_systemd_mgr, *method, &error, NULL, "s", SPECIAL_USER_SLICE); - if (r < 0) - return log_debug_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); - - return 1; -} - static int execute_s2h(const SleepConfig *sleep_config) { - _unused_ _cleanup_(freeze_thaw_user_slice) const char *auto_method_thaw = "ThawUnit"; int r; assert(sleep_config); - r = freeze_thaw_user_slice(&(const char*) { "FreezeUnit" }); - if (r < 0) - log_warning_errno(r, "Failed to freeze unit user.slice, ignoring: %m"); - /* Only check if we have automated battery alarms if HibernateDelaySec= is not set, as in that case * we'll busy poll for the configured interval instead */ if (!timestamp_is_set(sleep_config->hibernate_delay_usec)) { @@ -599,6 +574,7 @@ static int parse_argv(int argc, char *argv[]) { } static int run(int argc, char *argv[]) { + _cleanup_(unit_freezer_done_thaw) UnitFreezer user_slice_freezer = {}; _cleanup_(sleep_config_freep) SleepConfig *sleep_config = NULL; int r; @@ -617,6 +593,22 @@ static int run(int argc, char *argv[]) { "Sleep operation \"%s\" is disabled by configuration, refusing.", sleep_operation_to_string(arg_operation)); + /* Freeze the user sessions */ + r = getenv_bool("SYSTEMD_SLEEP_FREEZE_USER_SESSIONS"); + if (r < 0 && r != -ENXIO) + log_warning_errno(r, "Cannot parse value of $SYSTEMD_SLEEP_FREEZE_USER_SESSIONS, ignoring."); + if (r != 0) { + r = unit_freezer_new_freeze(SPECIAL_USER_SLICE, &user_slice_freezer); + if (r < 0) + log_warning_errno(r, "Failed to freeze user sessions, ignoring: %m"); + else + log_info("Froze user sessions"); + } else + log_notice("User sessions remain unfrozen on explicit request " + "($SYSTEMD_SLEEP_FREEZE_USER_SESSIONS is set to false). This is not recommended, " + "and might result in unexpected behavior, particularly in sysupend-then-hibernate " + "operations or setups with encrypted home directories."); + switch (arg_operation) { case SLEEP_SUSPEND_THEN_HIBERNATE: