diff --git a/etc/security-misc/emerg-shutdown/30_security_misc.conf b/etc/security-misc/emerg-shutdown/30_security_misc.conf index 904610b..4ec6cbd 100644 --- a/etc/security-misc/emerg-shutdown/30_security_misc.conf +++ b/etc/security-misc/emerg-shutdown/30_security_misc.conf @@ -22,13 +22,13 @@ EMERG_SHUTDOWN_KEYS="KEY_LEFTCTRL|KEY_RIGHTCTRL,KEY_LEFTALT|KEY_RIGHTALT,KEY_DEL ## Set the maximum number of seconds shutdown can take. If shutdown gets stuck ## for longer than this, the system will forcibly power down. ## -## NOTE: This requires ensure-shutdown.service to be enabled, which is not -## done by default. Enabling ensure-shutdown.service will cause shutdown to -## always take at least as long as systemd's DefaultTimeoutStopSec (which by -## default is 90 seconds). If you are going to enable ensure-shutdown.service, -## it is highly recommended to set DefaultTimeoutStopSec to a much smaller -## value, such as 5 seconds. The maximum shutdown time set here should be at -## least 10 seconds *longer* than DefaultTimeoutStopSec, to give normal -## shutdown a chance to actually succeed before forcibly shutting down the -## system. +## NOTE: This requires ensure-shutdown.service and +## ensure-shutdown-trigger.service to be enabled, which is not done by +## default. Enabling ensure-shutdown.service will cause shutdown to always +## take at least as long as systemd's DefaultTimeoutStopSec (which by default +## is 90 seconds). If you are going to enable ensure-shutdown.service, it is +## highly recommended to set DefaultTimeoutStopSec to a much smaller value, +## such as 5 seconds. The maximum shutdown time set here should be at least 10 +## seconds *longer* than DefaultTimeoutStopSec, to give normal shutdown a +## chance to actually succeed before forcibly shutting down the system. ENSURE_SHUTDOWN_TIMEOUT=30 diff --git a/usr/lib/systemd/system-preset/50-security-misc.preset b/usr/lib/systemd/system-preset/50-security-misc.preset index 004563c..4b44458 100644 --- a/usr/lib/systemd/system-preset/50-security-misc.preset +++ b/usr/lib/systemd/system-preset/50-security-misc.preset @@ -21,3 +21,4 @@ disable harden-module-loading.service ## Disable due to timing difficulties. See: ## https://github.com/systemd/systemd/issues/38261#issuecomment-3134580852 disable ensure-shutdown.service +disable ensure-shutdown-trigger.service diff --git a/usr/lib/systemd/system/block-shutdown.service b/usr/lib/systemd/system/block-shutdown.service new file mode 100644 index 0000000..3d4be21 --- /dev/null +++ b/usr/lib/systemd/system/block-shutdown.service @@ -0,0 +1,29 @@ +## Copyright (C) 2019 - 2025 ENCRYPTED SUPPORT LLC +## See the file COPYING for copying conditions. + +## This unit, if uncommented and started, will prevent the system from ever +## shutting down unless ensure-shutdown.service is enabled and correctly +## configured. If you have enabled ensure-shutdown.service and tuned the +## ENSURE_SHUTDOWN_TIMEOUT and DefaultTimeoutStopSec variables (in +## /etc/security-misc/emerg-shutdown/30_security_misc.conf and +## /etc/systemd/system.conf respectively) and want to make sure +## ensure-shutdown.service actually works, you can uncomment this unit and +## start it with `sudo systemctl start block-shutdown.service`. If the systems +## successfully powers down even with this unit started, +## ensure-shutdown.service is working. + +# [Unit] +# Description=Blocks shutdown indefinitely unless ensure-shutdown.service is enabled +# +# [Service] +# Type=exec +# ExecStart=bash -c -- "trap '' SIGTERM; sleep infinity" +# KillSignal=SIGTERM +# FinalKillSignal=SIGTERM +# RestartKillSignal=SIGTERM +# WatchdogSignal=SIGTERM +# SendSIGHUP=no +# TimeoutStopSec=infinity +# +# [Install] +# WantedBy=multi-user.target diff --git a/usr/lib/systemd/system/emerg-shutdown.service b/usr/lib/systemd/system/emerg-shutdown.service index 0eb4258..fa0dd62 100644 --- a/usr/lib/systemd/system/emerg-shutdown.service +++ b/usr/lib/systemd/system/emerg-shutdown.service @@ -4,6 +4,12 @@ [Unit] Description=Emergency shutdown when boot media is removed Documentation=https://github.com/Kicksecure/security-misc +DefaultDependencies=no +Before=sysinit.target +Requires=udev.service +After=udev.service +Requires=local-fs.service +After=local-fs.service [Service] Type=notify @@ -11,4 +17,4 @@ ExecStart=/usr/libexec/security-misc/emerg-shutdown NotifyAccess=main [Install] -WantedBy=multi-user.target +WantedBy=sysinit.target diff --git a/usr/lib/systemd/system/ensure-shutdown-trigger.service b/usr/lib/systemd/system/ensure-shutdown-trigger.service new file mode 100644 index 0000000..0945e43 --- /dev/null +++ b/usr/lib/systemd/system/ensure-shutdown-trigger.service @@ -0,0 +1,18 @@ +## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC +## See the file COPYING for copying conditions. + +## NOTE: If enabling this unit, also enable ensure-shutdown.service, otherwise +## this will do nothing. + +[Unit] +Description=Forcibly shut down the system if normal shutdown gets stuck (alternate trigger unit) +Documentation=https://github.com/Kicksecure/security-misc + +[Service] +Type=oneshot +RemainAfterExit=true +ExecStart=true +ExecStop=bash -c -- 'echo "d" > /run/emerg-shutdown-trigger' + +[Install] +WantedBy=multi-user.target diff --git a/usr/lib/systemd/system/ensure-shutdown.service b/usr/lib/systemd/system/ensure-shutdown.service index 30bcc23..52eb487 100644 --- a/usr/lib/systemd/system/ensure-shutdown.service +++ b/usr/lib/systemd/system/ensure-shutdown.service @@ -1,9 +1,16 @@ ## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC ## See the file COPYING for copying conditions. +## NOTE: If enabling this unit, also enable ensure-shutdown-trigger.service, +## otherwise this will likely be unable to unstick a stuck shutdown. + [Unit] Description=Forcibly shut down the system if normal shutdown gets stuck Documentation=https://github.com/Kicksecure/security-misc +DefaultDependencies=no +Before=sysinit.target +Requires=udev.service +After=udev.service Wants=emerg-shutdown.service After=emerg-shutdown.service @@ -15,4 +22,4 @@ ExecStop=bash -c -- 'echo "d" > /run/emerg-shutdown-trigger' KillMode=process [Install] -WantedBy=multi-user.target +WantedBy=sysinit.target diff --git a/usr/libexec/security-misc/emerg-shutdown b/usr/libexec/security-misc/emerg-shutdown index fe982ca..1afebcb 100755 --- a/usr/libexec/security-misc/emerg-shutdown +++ b/usr/libexec/security-misc/emerg-shutdown @@ -13,8 +13,10 @@ export LC_ALL=C ## Read emergency shutdown key configuration for config_file in /etc/security-misc/emerg-shutdown/*.conf /usr/local/etc/security-misc/emerg-shutdown/*.conf; do - bash -n "${config_file}" - source "${config_file}" + if [ -f "${config_file}" ]; then + bash -n "${config_file}" + source "${config_file}" + fi done if [ -z "${EMERG_SHUTDOWN_KEYS}" ]; then ## Default to Ctrl+Alt+Delete if nothing else is set diff --git a/usr/libexec/security-misc/ensure-shutdown b/usr/libexec/security-misc/ensure-shutdown index 48643ea..85ab31d 100755 --- a/usr/libexec/security-misc/ensure-shutdown +++ b/usr/libexec/security-misc/ensure-shutdown @@ -15,8 +15,10 @@ export LC_ALL=C ## Read emergency shutdown key configuration for config_file in /etc/security-misc/emerg-shutdown/*.conf /usr/local/etc/security-misc/emerg-shutdown/*.conf; do - bash -n "${config_file}" - source "${config_file}" + if [ -f "${config_file}" ]; then + bash -n "${config_file}" + source "${config_file}" + fi done if [ -z "${ENSURE_SHUTDOWN_TIMEOUT}" ] \ || ! is_whole_number "${ENSURE_SHUTDOWN_TIMEOUT}"; then diff --git a/usr/share/lintian/overrides/security-misc b/usr/share/lintian/overrides/security-misc index 26c3c70..8351249 100644 --- a/usr/share/lintian/overrides/security-misc +++ b/usr/share/lintian/overrides/security-misc @@ -15,3 +15,6 @@ security-misc: uses-dpkg-database-directly [usr/bin/remount-secure] ## Special target to make sure this runs as non-parallelized as possible to avoid race conditions. security-misc: systemd-service-file-refers-to-unusual-wantedby-target sysinit-post.target [usr/lib/systemd/system/remount-secure.service] + +## False-positive. Unit is commented out by default. +security-misc: systemd-service-file-missing-install-key [usr/lib/systemd/system/block-shutdown.service]