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.
This commit is contained in:
Tim Ledbetter 2023-05-30 18:12:06 +01:00 committed by Jelle Raaijmakers
parent f0edf00dc0
commit a041f1671c
Notes: sideshowbarker 2024-07-17 05:05:51 +09:00
2 changed files with 58 additions and 73 deletions

View file

@ -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;
}
}

View file

@ -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<char*>("Unknown signal");
}