From a041f1671c8d2d136a032b239933c1968fb3498e Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Tue, 30 May 2023 18:12:06 +0100 Subject: [PATCH] LibC: Ignore signals that don't have a name in `getsignalbyname()` This prevents a segfault in `kill` and `killall` when an invalid signal name is given. --- Userland/Libraries/LibC/signal.cpp | 129 +++++++++++++---------------- Userland/Libraries/LibC/string.cpp | 2 +- 2 files changed, 58 insertions(+), 73 deletions(-) diff --git a/Userland/Libraries/LibC/signal.cpp b/Userland/Libraries/LibC/signal.cpp index e61781a87af..f13e0941137 100644 --- a/Userland/Libraries/LibC/signal.cpp +++ b/Userland/Libraries/LibC/signal.cpp @@ -128,39 +128,53 @@ int sigpending(sigset_t* set) __RETURN_WITH_ERRNO(rc, rc, -1); } +// Signal 0 (the null signal) and Signal 32 (SIGCANCEL) are deliberately set to null here. +// They are not intended to be resolved by strsignal(), getsignalname() or getsignalbyname(). +#define ENUMERATE_SIGNALS \ + __ENUMERATE_SIGNAL(nullptr, nullptr) \ + __ENUMERATE_SIGNAL("HUP", "Hangup") \ + __ENUMERATE_SIGNAL("INT", "Interrupt") \ + __ENUMERATE_SIGNAL("QUIT", "Quit") \ + __ENUMERATE_SIGNAL("ILL", "Illegal instruction") \ + __ENUMERATE_SIGNAL("TRAP", "Trap") \ + __ENUMERATE_SIGNAL("ABRT", "Aborted") \ + __ENUMERATE_SIGNAL("BUS", "Bus error") \ + __ENUMERATE_SIGNAL("FPE", "Division by zero") \ + __ENUMERATE_SIGNAL("KILL", "Killed") \ + __ENUMERATE_SIGNAL("USR1", "User signal 1") \ + __ENUMERATE_SIGNAL("SEGV", "Segmentation violation") \ + __ENUMERATE_SIGNAL("USR2", "User signal 2") \ + __ENUMERATE_SIGNAL("PIPE", "Broken pipe") \ + __ENUMERATE_SIGNAL("ALRM", "Alarm clock") \ + __ENUMERATE_SIGNAL("TERM", "Terminated") \ + __ENUMERATE_SIGNAL("STKFLT", "Stack fault") \ + __ENUMERATE_SIGNAL("CHLD", "Child exited") \ + __ENUMERATE_SIGNAL("CONT", "Continued") \ + __ENUMERATE_SIGNAL("STOP", "Stopped (signal)") \ + __ENUMERATE_SIGNAL("TSTP", "Stopped") \ + __ENUMERATE_SIGNAL("TTIN", "Stopped (tty input)") \ + __ENUMERATE_SIGNAL("TTOU", "Stopped (tty output)") \ + __ENUMERATE_SIGNAL("URG", "Urgent I/O condition)") \ + __ENUMERATE_SIGNAL("XCPU", "CPU limit exceeded") \ + __ENUMERATE_SIGNAL("XFSZ", "File size limit exceeded") \ + __ENUMERATE_SIGNAL("VTALRM", "Virtual timer expired") \ + __ENUMERATE_SIGNAL("PROF", "Profiling timer expired") \ + __ENUMERATE_SIGNAL("WINCH", "Window changed") \ + __ENUMERATE_SIGNAL("IO", "I/O possible") \ + __ENUMERATE_SIGNAL("INFO", "Power failure") \ + __ENUMERATE_SIGNAL("SYS", "Bad system call") \ + __ENUMERATE_SIGNAL(nullptr, nullptr) + char const* sys_siglist[NSIG] = { - "Invalid signal number", - "Hangup", - "Interrupt", - "Quit", - "Illegal instruction", - "Trap", - "Aborted", - "Bus error", - "Division by zero", - "Killed", - "User signal 1", - "Segmentation violation", - "User signal 2", - "Broken pipe", - "Alarm clock", - "Terminated", - "Stack fault", - "Child exited", - "Continued", - "Stopped (signal)", - "Stopped", - "Stopped (tty input)", - "Stopped (tty output)", - "Urgent I/O condition)", - "CPU limit exceeded", - "File size limit exceeded", - "Virtual timer expired", - "Profiling timer expired", - "Window changed", - "I/O possible", - "Power failure", - "Bad system call", +#define __ENUMERATE_SIGNAL(name, description) description, + ENUMERATE_SIGNALS +#undef __ENUMERATE_SIGNAL +}; + +char const* sys_signame[NSIG] = { +#define __ENUMERATE_SIGNAL(name, description) name, + ENUMERATE_SIGNALS +#undef __ENUMERATE_SIGNAL }; // https://pubs.opengroup.org/onlinepubs/9699919799/functions/siglongjmp.html @@ -210,48 +224,14 @@ int sigtimedwait(sigset_t const* set, siginfo_t* info, struct timespec const* ti __RETURN_WITH_ERRNO(rc, rc, -1); } -char const* sys_signame[] = { - "INVAL", - "HUP", - "INT", - "QUIT", - "ILL", - "TRAP", - "ABRT", - "BUS", - "FPE", - "KILL", - "USR1", - "SEGV", - "USR2", - "PIPE", - "ALRM", - "TERM", - "STKFLT", - "CHLD", - "CONT", - "STOP", - "TSTP", - "TTIN", - "TTOU", - "URG", - "XCPU", - "XFSZ", - "VTALRM", - "PROF", - "WINCH", - "IO", - "INFO", - "SYS", -}; - -static_assert(sizeof(sys_signame) == sizeof(char const*) * NSIG); - int getsignalbyname(char const* name) { VERIFY(name); StringView name_sv { name, strlen(name) }; - for (size_t i = 0; i < NSIG; ++i) { + for (size_t i = 1; i < NSIG; ++i) { + if (!sys_signame[i]) + continue; + StringView signal_name { sys_signame[i], strlen(sys_signame[i]) }; if (signal_name == name_sv || (name_sv.starts_with("SIG"sv) && signal_name == name_sv.substring_view(3))) return i; @@ -262,10 +242,15 @@ int getsignalbyname(char const* name) char const* getsignalname(int signal) { - if (signal < 0 || signal >= NSIG) { + if (signal <= 0 || signal >= NSIG) { errno = EINVAL; return nullptr; } - return sys_signame[signal]; + + auto const* result = sys_signame[signal]; + if (!result) + errno = EINVAL; + + return result; } } diff --git a/Userland/Libraries/LibC/string.cpp b/Userland/Libraries/LibC/string.cpp index a1753b5c81c..c923c009c29 100644 --- a/Userland/Libraries/LibC/string.cpp +++ b/Userland/Libraries/LibC/string.cpp @@ -340,7 +340,7 @@ char* strerror(int errnum) // https://pubs.opengroup.org/onlinepubs/9699919799/functions/strsignal.html char* strsignal(int signum) { - if (signum >= NSIG) { + if (signum <= 0 || signum >= NSIG || !sys_siglist[signum]) { dbgln("strsignal() missing string for signum={}", signum); return const_cast("Unknown signal"); }