mirror of
https://github.com/Kicksecure/security-misc.git
synced 2025-08-06 08:44:14 -04:00
emerg-shutdown: fix the hang-on-shutdown bug, add autodetection of new keyboards, shutdown key configuration, and instant shutdown option
This commit is contained in:
parent
a1d1c56033
commit
e42078e90d
5 changed files with 153 additions and 20 deletions
19
etc/security-misc/emerg-shutdown/30_security_misc.conf
Normal file
19
etc/security-misc/emerg-shutdown/30_security_misc.conf
Normal file
|
@ -0,0 +1,19 @@
|
|||
## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
|
||||
## See the file COPYING for copying conditions.
|
||||
|
||||
## Please use "/etc/security-misc/emerg-shutdown/50_user.conf" for your custom
|
||||
## configuration, which will override the defaults found here.
|
||||
## When Kicksecure is updated, this file may be overwritten.
|
||||
|
||||
## Set the key combo for forcing immediate shutdown. See the "Keys and
|
||||
## buttons" section of "/usr/include/linux/input-event-codes.h" for possibly
|
||||
## supported values. Not all keys are supported.
|
||||
##
|
||||
## All specified keys must be depressed at the same time to trigger a
|
||||
## shutdown. Use a comma (",") to separate keys. If you want to alias certain
|
||||
## keys to each other from emerg-shutdown's standpoint, use a pipe
|
||||
## character("|").
|
||||
##
|
||||
## The default key sequence triggers a shutdown when Ctrl+Alt+Delete is
|
||||
## pressed, allowing the use of either the left or right Ctrl and Alt keys.
|
||||
EMERG_SHUTDOWN_KEYS="KEY_LEFTCTRL|KEY_RIGHTCTRL,KEY_LEFTALT|KEY_RIGHTALT,KEY_DELETE"
|
|
@ -6,9 +6,8 @@ Description=Emergency shutdown when boot media is removed
|
|||
Documentation=https://github.com/Kicksecure/security-misc
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Type=exec
|
||||
ExecStart=/usr/libexec/security-misc/emerg-shutdown
|
||||
RemainAfterExit=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
9
usr/lib/udev/rules.d/95-emerg-shutdown.rules
Normal file
9
usr/lib/udev/rules.d/95-emerg-shutdown.rules
Normal file
|
@ -0,0 +1,9 @@
|
|||
SUBSYSTEM!="input", GOTO="end"
|
||||
|
||||
# new keyboard or mouse attached or removed, restart emerg-shutdown
|
||||
KERNEL=="event*", ACTION=="add", ENV{ID_INPUT_KEYBOARD}=="1", RUN+="/usr/bin/systemctl restart emerg-shutdown.service"
|
||||
KERNEL=="event*", ACTION=="add", ENV{ID_INPUT_KEYBOARD}=="1", GOTO="end"
|
||||
KERNEL=="event*", ACTION=="remove", ENV{ID_INPUT_KEYBOARD}=="1", RUN+="/usr/bin/systemctl restart emerg-shutdown.service"
|
||||
KERNEL=="event*", ACTION=="remove", ENV{ID_INPUT_KEYBOARD}=="1", GOTO="end"
|
||||
|
||||
LABEL="end"
|
|
@ -3,25 +3,49 @@
|
|||
# Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
|
||||
# See the file COPYING for copying conditions.
|
||||
|
||||
gcc \
|
||||
-o \
|
||||
/run/emerg-shutdown \
|
||||
-static \
|
||||
/usr/src/security-misc/emerg-shutdown.c \
|
||||
|| {
|
||||
printf "%s\n" 'Could not compile force-shutdown executable!'
|
||||
exit 1;
|
||||
}
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o errtrace
|
||||
set -o pipefail
|
||||
|
||||
readarray -t root_devices < <(/usr/libexec/helper-scripts/get-backing-devices-for-mountpoint '/');
|
||||
## Make sure globs sort in a predictable, reproducible fashion
|
||||
export LC_ALL=C
|
||||
|
||||
## memlockd daemonizes itself, so no need to background it
|
||||
memlockd -c /usr/share/security-misc/security-misc-memlockd.cfg
|
||||
## Read emergency shutdown key configuration
|
||||
for config_file in /etc/security-misc/emerg-shutdown/*.conf; do
|
||||
source "${config_file}"
|
||||
done
|
||||
if [ -z "${EMERG_SHUTDOWN_KEYS}" ]; then
|
||||
## Default to Ctrl+Alt+Delete if nothing else is set
|
||||
EMERG_SHUTDOWN_KEYS="KEY_LEFTCTRL|KEY_RIGHTCTRL,KEY_LEFTALT|KEY_RIGHTALT,KEY_DELETE"
|
||||
fi
|
||||
|
||||
## Find the devices that make up the root device
|
||||
readarray -t root_devices < <(/usr/libexec/helper-scripts/get-backing-devices-for-mountpoint '/') || true;
|
||||
if [ "${#root_devices[@]}" = '0' ] \
|
||||
|| [ "${root_devices[0]}" == '' ]; then
|
||||
## /dev/sda1 might be the right one...
|
||||
root_devices[0]='/dev/sda1'
|
||||
fi
|
||||
|
||||
## Build the actual emerg-shutdown executable
|
||||
if [ ! -f '/run/emerg-shutdown' ]; then
|
||||
gcc \
|
||||
-o \
|
||||
/run/emerg-shutdown \
|
||||
-static \
|
||||
/usr/src/security-misc/emerg-shutdown.c \
|
||||
|| {
|
||||
printf "%s\n" 'Could not compile force-shutdown executable!'
|
||||
exit 1;
|
||||
}
|
||||
|
||||
fi
|
||||
|
||||
## memlockd daemonizes itself, so no need to background it.
|
||||
memlockd -c /usr/share/security-misc/security-misc-memlockd.cfg || true
|
||||
|
||||
## Launch emerg-shutdown
|
||||
OLDIFS="$IFS"
|
||||
IFS=','
|
||||
/run/emerg-shutdown "--devices=${root_devices[*]}" '--keys=KEY_LEFTCTRL|KEY_RIGHTCTRL,KEY_LEFTALT|KEY_RIGHTALT,KEY_DELETE' &
|
||||
IFS="$OLDIFS"
|
||||
sleep 1
|
||||
disown
|
||||
exit 0
|
||||
/run/emerg-shutdown "--devices=${root_devices[*]}" "--keys=${EMERG_SHUTDOWN_KEYS}"
|
||||
|
|
|
@ -94,6 +94,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <poll.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/vt.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define fd_stdin 0
|
||||
|
@ -104,6 +106,8 @@
|
|||
#define input_path_size 20
|
||||
#define key_flags_len 12
|
||||
|
||||
int console_fd = 0;
|
||||
|
||||
/* Adapted from kloak/src/keycodes.c */
|
||||
struct name_value {
|
||||
const char *name;
|
||||
|
@ -283,6 +287,8 @@ void print(int fd, char *str) {
|
|||
void print_usage() {
|
||||
print(fd_stderr, "Usage:\n");
|
||||
print(fd_stderr, " emerg-shutdown --devices=DEVICE1[,DEVICE2...] --keys=KEY_1[,KEY_2|KEY_3...]\n");
|
||||
print(fd_stderr, "Or:\n");
|
||||
print(fd_stderr, " emerg-shutdown --instant-shutdown\n");
|
||||
print(fd_stderr, "Example:\n");
|
||||
print(fd_stderr, " emerg-shutdown --devices=/dev/sda3 --keys=KEY_POWER\n");
|
||||
}
|
||||
|
@ -363,7 +369,74 @@ void load_list(const char *arg, size_t *result_list_len_ref, char ***result_list
|
|||
}
|
||||
|
||||
int kill_system() {
|
||||
return syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
|
||||
/*
|
||||
* It isn't safe to simply call the reboot syscall here - there is a
|
||||
* graphics driver bug in the i915 driver on Bookworm that will throw a
|
||||
* kernel warning during shutdown. Kicksecure sets panic_on_oops and
|
||||
* panic_on_warn to 1 during bootup, which means this bug will cause a
|
||||
* kernel panic and thus hang the system rather than shutting down.
|
||||
*
|
||||
* To mitigate this, we do two things:
|
||||
*
|
||||
* - We disable the panic_on_oops and panic_on_warn kernel settings before
|
||||
* calling the reboot syscall. This way if a warn or oops does occur, at
|
||||
* least it isn't as likely to block shutdown.
|
||||
* - We switch virtual terminals before initiating the shutdown. This should
|
||||
* hopefully keep whatever is going wrong from going wrong in the first
|
||||
* place.
|
||||
*
|
||||
* This is probably a good idea for any system, because switching TTYs is a
|
||||
* rather basic operation that is likely to work, while forcibly shutting
|
||||
* down while X11 or Wayland still has control of the display is probably
|
||||
* not as well tested (if it's been tested at all).
|
||||
*
|
||||
* Above all else though, we want to at least *try* to shutdown. Even if all
|
||||
* our attempts to switch VTs fail and /proc isn't available for us to tweak
|
||||
* kernel settings, we still need to try. Therefore we absolutely do not
|
||||
* crash or block, except when waiting for a VT to become activated. (If VT
|
||||
* activation blocks forever, the kernel is probably horribly broken and
|
||||
* would probably panic imminently anyway.)
|
||||
*/
|
||||
|
||||
const char *panic_on_oops_path = "/proc/sys/kernel/panic_on_oops";
|
||||
const char *panic_on_warn_path = "/proc/sys/kernel/panic_on_warn";
|
||||
|
||||
int ret = 0;
|
||||
int tgt_vt = 0;
|
||||
int sysctl_fd = 0;
|
||||
|
||||
/* Turn off panic_on_oops. */
|
||||
sysctl_fd = open(panic_on_oops_path, O_WRONLY);
|
||||
if (sysctl_fd != -1) {
|
||||
write(sysctl_fd, "0", 1);
|
||||
close(sysctl_fd);
|
||||
}
|
||||
|
||||
/* Turn off panic_on_warn. */
|
||||
sysctl_fd = open(panic_on_warn_path, O_WRONLY);
|
||||
if (sysctl_fd != -1) {
|
||||
write(sysctl_fd, "0", 1);
|
||||
close(sysctl_fd);
|
||||
}
|
||||
|
||||
/* Determine which VT to switch to. Anything that isn't open yet will do. */
|
||||
ret = ioctl(console_fd, VT_OPENQRY, &tgt_vt);
|
||||
if (ret == -1) {
|
||||
goto trykill;
|
||||
}
|
||||
|
||||
/* Try to switch to it. */
|
||||
ret = ioctl(console_fd, VT_ACTIVATE, tgt_vt);
|
||||
if (ret == -1) {
|
||||
goto trykill;
|
||||
}
|
||||
|
||||
/* Wait for it to become active. */
|
||||
ioctl(console_fd, VT_WAITACTIVE, tgt_vt);
|
||||
|
||||
trykill:
|
||||
return syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
|
||||
LINUX_REBOOT_CMD_POWER_OFF, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -405,6 +478,9 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
for (arg_idx = 1; arg_idx < argc; arg_idx++) {
|
||||
if (strncmp(argv[arg_idx], "--instant-shutdown", strlen("--instant-shutdown")) == 0) {
|
||||
kill_system();
|
||||
}
|
||||
if (strncmp(argv[arg_idx], "--devices=", strlen("--devices=")) == 0) {
|
||||
if (target_dev_name_raw_list != NULL) {
|
||||
print(fd_stderr, "--devices cannot be passed more than once!\n");
|
||||
|
@ -422,6 +498,12 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
console_fd = open("/dev/console", O_RDWR);
|
||||
if (console_fd == -1) {
|
||||
print(fd_stderr, "Could not open /dev/console!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
target_dev_list = safe_calloc(target_dev_list_len, sizeof(char *));
|
||||
panic_key_list = safe_calloc(panic_key_list_len, sizeof(int *));
|
||||
panic_key_active_list = safe_calloc(panic_key_list_len, sizeof(bool));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue