Additional hardening on emerg-shutdown

This commit is contained in:
Aaron Rainbolt 2025-09-25 23:55:03 -05:00
parent 590aaec73d
commit 58cc6731f2
No known key found for this signature in database
GPG key ID: A709160D73C79109
2 changed files with 77 additions and 34 deletions

View file

@ -19,15 +19,37 @@ binary_prefix='/run'
EMERG_SHUTDOWN_KEYS=''
root_devices[0]=''
## Taken from kloak/Makefile, see it for more information
gcc_hardening_options=(
"-Wall" "-Wformat" "-Wformat=2" "-Wconversion"
"-O2" "-Wall" "-Wextra" "-Wformat" "-Wformat=2" "-Wconversion"
"-Wimplicit-fallthrough" "-Werror=format-security" "-Werror=implicit"
"-Werror=int-conversion" "-Werror=incompatible-pointer-types"
"-Wtrampolines" "-Wbidi-chars=any" "-U_FORTIFY_SOURCE" "-D_FORTIFY_SOURCE=3"
"-fstack-clash-protection" "-fstack-protector-strong"
"-fno-delete-null-pointer-checks" "-fno-strict-overflow"
"-fno-strict-aliasing" "-fsanitize=undefined" "-fcf-protection=full"
"-Wformat-overflow" "-Wformat-signedness" "-Wnull-dereference" "-Winit-self"
"-Wmissing-include-dirs" "-Wshift-negative-value" "-Wshift-overflow"
"-Wswitch-default" "-Wuninitialized" "-Walloca" "-Warray-bounds"
"-Wfloat-equal" "-Wshadow" "-Wpointer-arith" "-Wundef" "-Wunused-macros"
"-Wbad-function-cast" "-Wcast-qual" "-Wcast-align" "-Wwrite-strings"
"-Wdate-time" "-Wstrict-prototypes" "-Wold-style-definition"
"-Wredundant-decls" "-Winvalid-utf8" "-Wvla" "-Wdisabled-optimization"
"-Wstack-protector" "-Wdeclaration-after-statement" "-Wtrampolines"
"-Wbidi-chars=any,ucn" "-Wformat-overflow=2" "-Wformat-truncation=2"
"-Wshift-overflow=2" "-Wtrivial-auto-var-init" "-Wstringop-overflow=3"
"-Wstrict-flex-arrays" "-Walloc-zero" "-Warray-bounds=2"
"-Wattribute-alias=2" "-Wduplicated-branches" "-Wduplicated-cond"
"-Wcast-align=strict" "-Wjump-misses-init" "-Wlogical-op" "-U_FORTIFY_SOURCE"
"-D_FORTIFY_SOURCE=3" "-fstack-clash-protection" "-fstack-protector-all"
"-fno-delete-null-pointer-checks" "-fno-strict-aliasing"
"-fsanitize=address,undefined" "-fno-sanitize-recover=all"
"-fstrict-flex-arrays=3" "-ftrivial-auto-var-init=pattern" "-fPIE"
)
gcc_machine="$(gcc -dumpmachine)"
if [ "${gcc_machine}" = 'x86_64-linux-gnu' ]; then
gcc_hardening_options+=( '-fcf-protection=full' )
elif [ "${gcc_machine}" = 'aarch64-linux-gnu' ]; then
gcc_hardening_options+=( '-mbranch-protection=standard' )
fi
gcc_hardening_options+=(
"-Wl,-z,nodlopen" "-Wl,-z,noexecstack" "-Wl,-z,relro" "-Wl,-z,now"
"-Wl,--as-needed" "-Wl,--no-copy-dt-needed-entries" "-pie"
)
@ -56,11 +78,12 @@ else
## Build the actual emerg-shutdown executable
if [ ! -f '/run/emerg-shutdown' ]; then
gcc \
-g
/usr/src/security-misc/emerg-shutdown.c \
-o \
/run/emerg-shutdown \
-static \
"${gcc_hardening_options[@]}" \
/usr/src/security-misc/emerg-shutdown.c \
|| {
printf "%s\n" 'Could not compile force-shutdown executable!'
exit 1
@ -74,6 +97,5 @@ fi
systemd-notify --ready
## Launch emerg-shutdown
OLDIFS="$IFS"
IFS=','
"${binary_prefix}/emerg-shutdown" "--devices=${root_devices[*]}" "--keys=${EMERG_SHUTDOWN_KEYS}"

View file

@ -95,9 +95,10 @@
#include <signal.h>
#include <errno.h>
#include <limits.h>
#include <assert.h>
#define fd_stdin 0
#define fd_stdout 1
//#define fd_stdin 0
//#define fd_stdout 1
#define fd_stderr 2
#define max_inputs 255
@ -275,7 +276,7 @@ bool bitset_get(const uint64_t *bits, uint32_t i) {
return (bits[i / 64] >> (i % 64)) & 1UL;
}
void print(int fd, char *str) {
void print(int fd, const char *str) {
size_t len = strlen(str) + 1;
while (true) {
ssize_t write_len = write(fd, str, len);
@ -291,7 +292,7 @@ void print(int fd, char *str) {
}
}
void print_usage() {
void print_usage(void) {
print(fd_stderr, "Usage:\n");
print(fd_stderr, " emerg-shutdown [OPTIONS...]\n");
print(fd_stderr, "Options:\n");
@ -343,7 +344,7 @@ void *safe_reallocarray(void *ptr, size_t nmemb, size_t size) {
/* Inspired by https://www.strudel.org.uk/itoa/ */
char *int_to_str(uint32_t val) {
static char buf[11];
uint8_t i;
int8_t i;
char *rslt = NULL;
const char *digits = "0123456789";
@ -356,9 +357,10 @@ char *int_to_str(uint32_t val) {
break;
}
}
assert(i >= 0);
rslt = safe_calloc(1, 11 - i);
memcpy(rslt, buf + i, 11 - i);
rslt = safe_calloc(1, 11 - (uint8_t)(i));
memcpy(rslt, buf + i, 11 - (uint8_t)(i));
return rslt;
}
@ -397,7 +399,7 @@ void load_list(const char *arg, size_t *result_list_len_ref, char ***result_list
free(arg_copy);
}
long int kill_system() {
long int kill_system(void) {
/*
* 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
@ -437,14 +439,22 @@ long int kill_system() {
/* Turn off panic_on_oops. */
sysctl_fd = open(panic_on_oops_path, O_WRONLY);
if (sysctl_fd != -1) {
/* We intentionally ignore the return from `write` here. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
write(sysctl_fd, "0", 1);
#pragma GCC diagnostic pop
close(sysctl_fd);
}
/* Turn off panic_on_warn. */
sysctl_fd = open(panic_on_warn_path, O_WRONLY);
if (sysctl_fd != -1) {
/* We intentionally ignore the return from `write` here. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
write(sysctl_fd, "0", 1);
#pragma GCC diagnostic pop
close(sysctl_fd);
}
@ -495,6 +505,11 @@ void hw_monitor(int argc, char **argv) {
int ie_idx = 0;
size_t kg_idx = 0;
/* Socket management */
struct sockaddr_nl sa = { 0 };
int ns = 0;
int ret = 0;
for (arg_idx = 1; arg_idx < argc; arg_idx++) {
if (strncmp(argv[arg_idx], "--devices=", strlen("--devices=")) == 0) {
if (target_dev_name_raw_list != NULL) {
@ -599,8 +614,10 @@ void hw_monitor(int argc, char **argv) {
for (pkl_idx = 0; pkl_idx < panic_key_list_len; pkl_idx++) {
size_t keygroup_str_list_len = 0;
char **keygroup_str_list = NULL;
uint32_t *pkl_element = NULL;
load_list(panic_key_str_list[pkl_idx], &keygroup_str_list_len, &keygroup_str_list, "|", false);
uint32_t *pkl_element = safe_calloc(keygroup_str_list_len + 1, sizeof(uint32_t));
pkl_element = safe_calloc(keygroup_str_list_len + 1, sizeof(uint32_t));
pkl_element[keygroup_str_list_len] = 0;
for (kg_idx = 0; kg_idx < keygroup_str_list_len; kg_idx++) {
@ -621,18 +638,16 @@ void hw_monitor(int argc, char **argv) {
}
/* Device event listener setup */
struct sockaddr_nl sa = {
.nl_family = AF_NETLINK,
.nl_pad = 0,
.nl_pid = (uint32_t)getpid(),
.nl_groups = NETLINK_KOBJECT_UEVENT,
};
int ns = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
sa.nl_family = AF_NETLINK;
sa.nl_pad = 0;
sa.nl_pid = (uint32_t)getpid();
sa.nl_groups = NETLINK_KOBJECT_UEVENT;
ns = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (ns < 0) {
print(fd_stderr, "Failed to create netlink socket!\n");
exit(1);
}
int ret = bind(ns, (struct sockaddr *) &sa, sizeof(sa));
ret = bind(ns, (struct sockaddr *) &sa, sizeof(sa));
if (ret < 0) {
print(fd_stderr, "Failed to bind netlink socket!\n");
exit(1);
@ -711,13 +726,17 @@ void hw_monitor(int argc, char **argv) {
/* Event loop */
while (poll(pollfd_list, event_fd_list_len + 1, -1) != -1) {
size_t ie_max_idx = 0;
/* Panic key handler */
for (efl_idx = 0; efl_idx < event_fd_list_len; efl_idx++) {
ssize_t ieread_bytes = 0;
if (!(pollfd_list[efl_idx].revents & POLLIN)) {
continue;
}
ssize_t ieread_bytes = read(event_fd_list[efl_idx], ie_buf, sizeof(struct input_event) * 64);
ieread_bytes = read(event_fd_list[efl_idx], ie_buf,
sizeof(struct input_event) * 64);
if (ieread_bytes <= 0
|| ((size_t)ieread_bytes % sizeof(struct input_event)) != 0) {
@ -729,8 +748,9 @@ void hw_monitor(int argc, char **argv) {
exit(1);
}
for (ie_idx = 0; ie_idx < (size_t)ieread_bytes / sizeof(struct input_event);
ie_idx++) {
ie_max_idx = (size_t)ieread_bytes / sizeof(struct input_event);
assert(ie_max_idx < INT_MAX);
for (ie_idx = 0; ie_idx < (int)(ie_max_idx); ie_idx++) {
if (ie_buf[ie_idx].type != EV_KEY) {
continue;
}
@ -783,6 +803,11 @@ void hw_monitor(int argc, char **argv) {
struct iovec iov = { buf, sizeof(buf) };
struct sockaddr_nl sa2;
struct msghdr msg = { 0 };
char *tmpbuf = NULL;
bool device_removed = false;
bool device_changed = false;
bool disk_media_changed = false;
msg.msg_name = &sa2;
msg.msg_namelen = sizeof(sa2);
msg.msg_iov = &iov;
@ -790,10 +815,6 @@ void hw_monitor(int argc, char **argv) {
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
char *tmpbuf = NULL;
bool device_removed = false;
bool device_changed = false;
bool disk_media_changed = false;
len = recvmsg(ns, &msg, 0);
if (len == -1) {
@ -906,7 +927,7 @@ next_str:
* - 'd': Wait 15 seconds, then kill the system. This is used to keep systemd
* from delaying shutdown excessively.
*/
void fifo_monitor(int argc, char **argv) {
void fifo_monitor(char **argv) {
long monitor_fifo_timeout = 0;
char *arg_copy = NULL;
char *arg_part = NULL;
@ -1046,7 +1067,7 @@ int main(int argc, char **argv) {
hw_monitor(argc, argv);
} else if (monitor_mode == fifo_monitor_val) {
/* fifo_monitor handles its own argument parsing */
fifo_monitor(argc, argv);
fifo_monitor(argv);
} else {
print(fd_stderr, "Unknown monitor mode chosen!\n");
print_usage();