diff --git a/usr/libexec/security-misc/emerg-shutdown#security-misc-shared b/usr/libexec/security-misc/emerg-shutdown#security-misc-shared index 3016088..9c79237 100755 --- a/usr/libexec/security-misc/emerg-shutdown#security-misc-shared +++ b/usr/libexec/security-misc/emerg-shutdown#security-misc-shared @@ -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}" diff --git a/usr/src/security-misc/emerg-shutdown.c#security-misc-shared b/usr/src/security-misc/emerg-shutdown.c#security-misc-shared index faa78aa..e1ef981 100644 --- a/usr/src/security-misc/emerg-shutdown.c#security-misc-shared +++ b/usr/src/security-misc/emerg-shutdown.c#security-misc-shared @@ -95,9 +95,10 @@ #include #include #include +#include -#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();