summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-04-12 22:09:26 +0000
committerHauke Mehrtens2026-05-23 00:47:09 +0000
commit11ea1b3bdbea5ec5bd27fefff661a5f1b970d384 (patch)
tree0ccb9c46b5e63a5f26e3fc6f14156ced3fd4f160
parentf66d52ba983fc588f25d56c419a9101fe24a0e53 (diff)
downloadubus-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.c43
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':