From eb72efd81e0d5be6c836c5a084cc65b9734f544d Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Tue, 17 Jan 2012 10:33:10 +0100 Subject: libc: fix signal handling in system() When built without NPTL support (or for a sparc target), the system() function doesn't conform to its specification. Namely, it uses signal() to install/save/restore signal handlers, which may break applications using custom handlers installed with sigaction(). In addition, it resets the SIGCHLD handler to SIG_DFL instead of blocking the signal, which may result in "lost" signals if a custom handler was installed. Fix system() by replacing uses of signal() with appropriate calls to sigaction() and sigprocmask(). Signed-off-by: Richard Braun Signed-off-by: Mike Frysinger --- libc/stdlib/system.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'libc') diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c index a0ff726ad..a92c307c3 100644 --- a/libc/stdlib/system.c +++ b/libc/stdlib/system.c @@ -33,32 +33,34 @@ extern __typeof(system) __libc_system; int __libc_system(const char *command) { int wait_val, pid; - __sighandler_t save_quit, save_int, save_chld; + struct sigaction sa, save_quit, save_int; + sigset_t save_mask; if (command == 0) return 1; - save_quit = signal(SIGQUIT, SIG_IGN); - save_int = signal(SIGINT, SIG_IGN); - save_chld = signal(SIGCHLD, SIG_DFL); + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + /* __sigemptyset(&sa.sa_mask); - done by memset() */ + /* sa.sa_flags = 0; - done by memset() */ + + sigaction(SIGQUIT, &sa, &save_quit); + sigaction(SIGINT, &sa, &save_int); + __sigaddset(&sa.sa_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &sa.sa_mask, &save_mask); if ((pid = vfork()) < 0) { - signal(SIGQUIT, save_quit); - signal(SIGINT, save_int); - signal(SIGCHLD, save_chld); - return -1; + wait_val = -1; + goto out; } if (pid == 0) { - signal(SIGQUIT, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGCHLD, SIG_DFL); + sigaction(SIGQUIT, &save_quit, NULL); + sigaction(SIGINT, &save_int, NULL); + sigprocmask(SIG_SETMASK, &save_mask, NULL); execl("/bin/sh", "sh", "-c", command, (char *) 0); _exit(127); } - /* Signals are not absolutly guarenteed with vfork */ - signal(SIGQUIT, SIG_IGN); - signal(SIGINT, SIG_IGN); #if 0 __printf("Waiting for child %d\n", pid); @@ -67,9 +69,10 @@ int __libc_system(const char *command) if (wait4(pid, &wait_val, 0, 0) == -1) wait_val = -1; - signal(SIGQUIT, save_quit); - signal(SIGINT, save_int); - signal(SIGCHLD, save_chld); +out: + sigaction(SIGQUIT, &save_quit, NULL); + sigaction(SIGINT, &save_int, NULL); + sigprocmask(SIG_SETMASK, &save_mask, NULL); return wait_val; } #else -- cgit v1.2.3