diff options
| author | Hauke Mehrtens | 2026-04-12 22:09:26 +0000 |
|---|---|---|
| committer | Hauke Mehrtens | 2026-05-23 00:47:09 +0000 |
| commit | 11ea1b3bdbea5ec5bd27fefff661a5f1b970d384 (patch) | |
| tree | 0ccb9c46b5e63a5f26e3fc6f14156ced3fd4f160 | |
| parent | f66d52ba983fc588f25d56c419a9101fe24a0e53 (diff) | |
| download | ubus-11ea1b3bdbea5ec5bd27fefff661a5f1b970d384.tar.gz | |
ubusd_main: fix async-signal-unsafe SIGHUP handler
The SIGHUP handler called ubusd_acl_load() directly, which in turn calls
malloc, fopen, glob, syslog, and avl_insert — none of which are
async-signal-safe. Invoking them from a signal handler that interrupted
any of those same functions in the main loop can cause heap corruption,
deadlock, or a crash.
Replace with a self-pipe: the signal handler writes a single byte
(write() is async-signal-safe) to a pipe, and a uloop fd watcher drains
the pipe and calls ubusd_acl_load() safely from the event loop context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
| -rw-r--r-- | ubusd_main.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/ubusd_main.c b/ubusd_main.c index 0e4c6d8..19c2ad1 100644 --- a/ubusd_main.c +++ b/ubusd_main.c @@ -4,12 +4,15 @@ * SPDX-License-Identifier: LGPL-2.1-only */ +#define _GNU_SOURCE + #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #ifdef FreeBSD #include <sys/param.h> #endif +#include <fcntl.h> #include <string.h> #include <syslog.h> @@ -245,11 +248,29 @@ static int usage(const char *progname) return 1; } +static int sighup_pipe[2] = { -1, -1 }; + static void sighup_handler(int sig) { + int saved_errno = errno; + char c = 0; + ssize_t r = write(sighup_pipe[1], &c, sizeof(c)); + (void)r; + errno = saved_errno; +} + +static void sighup_fd_cb(struct uloop_fd *ufd, unsigned int events) +{ + char buf[16]; + while (read(ufd->fd, buf, sizeof(buf)) > 0) + ; ubusd_acl_load(); } +static struct uloop_fd sighup_ufd = { + .cb = sighup_fd_cb, +}; + static void mkdir_sockdir() { char *ubus_sock_dir, *tmp; @@ -272,12 +293,32 @@ int main(int argc, char **argv) int ch; signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, sighup_handler); + +#ifdef __linux__ + ret = pipe2(sighup_pipe, O_NONBLOCK | O_CLOEXEC); +#else + ret = pipe(sighup_pipe); + if (ret == 0) { + fcntl(sighup_pipe[0], F_SETFL, O_NONBLOCK); + fcntl(sighup_pipe[0], F_SETFD, FD_CLOEXEC); + fcntl(sighup_pipe[1], F_SETFL, O_NONBLOCK); + fcntl(sighup_pipe[1], F_SETFD, FD_CLOEXEC); + } +#endif + if (ret == 0) + signal(SIGHUP, sighup_handler); + else + signal(SIGHUP, SIG_IGN); ulog_open(ULOG_KMSG | ULOG_SYSLOG, LOG_DAEMON, "ubusd"); openlog("ubusd", LOG_PID, LOG_DAEMON); uloop_init(); + if (sighup_pipe[0] >= 0) { + sighup_ufd.fd = sighup_pipe[0]; + uloop_fd_add(&sighup_ufd, ULOOP_READ); + } + while ((ch = getopt(argc, argv, "A:s:")) != -1) { switch (ch) { case 's': |