From d2dc5467c67bc8625a4fc8f285b6a5443bf43df4 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 31 Oct 2017 23:10:37 -0200 Subject: Filter out NPTL internal signals (BZ #22391) This patch filters out the internal NPTL signals (SIGCANCEL/SIGTIMER and SIGSETXID) from signal functions. GLIBC on Linux requires both signals to proper implement pthread cancellation, posix timers, and set*id posix thread synchronization. And not filtering out the internal signal is troublesome: - A conformant program on a architecture that does not filter out the signals might inadvertently disable pthread asynchronous cancellation, set*id synchronization or posix timers. - It might also to security issues if SIGSETXID is masked and set*id functions are called (some threads might have effective user or group id different from the rest). The changes are basically: - Change __is_internal_signal to bool and used on all signal function that has a signal number as input. Also for signal function which accepts signals sets (sigset_t) it assumes that canonical function were used to add/remove signals which lead to some input simplification. - Fix tst-sigset.c to avoid check for SIGCANCEL/SIGTIMER and SIGSETXID. It is rewritten to check each signal indidually and to check realtime signals using canonical macros. - Add generic __clear_internal_signals and __is_internal_signal version since both symbols are used on generic implementations. - Remove superflous sysdeps/nptl/sigfillset.c. - Remove superflous SIGTIMER handling on Linux __is_internal_signal since it is the same of SIGCANCEL. - Remove dangling define and obvious comment on nptl/sigaction.c. Checked on x86_64-linux-gnu. [BZ #22391] * nptl/sigaction.c (__sigaction): Use __is_internal_signal to check for internal nptl signals. * nptl/sigaction.c (__sigaction): Likewise. * signal/sigaddset.c (sigaddset): Likewise. * signal/sigdelset.c (sigdelset): Likewise. * sysdeps/posix/signal.c (__bsd_signal): Likewise. * sysdeps/posix/sigset.c (sigset): Call and check sigaddset return value. * signal/sigfillset.c (sigfillset): User __clear_internal_signals to filter out internal nptl signals. * signal/tst-sigset.c (do_test): Check ech signal indidually and also check realtime signals using standard macros. * sysdeps/generic/internal-signals.h (__clear_internal_signals, __is_internal_signal, __libc_signal_block_all, __libc_signal_block_app, __libc_signal_restore_set): New functions. * sysdeps/nptl/sigfillset.c: Remove file. * sysdeps/unix/sysv/linux/internal-signals.h (__is_internal_signal): Change return to bool. (__clear_internal_signals): Remove SIGTIMER clean since it is equal to SIGCANEL on Linux. * sysdeps/unix/sysv/linux/sigtimedwait.c (__sigtimedwait): Assume signal set was constructed using standard functions. Reported-by: Yury Norov --- signal/sigaction.c | 2 +- signal/sigaddset.c | 5 +-- signal/sigdelset.c | 5 +-- signal/sigfillset.c | 10 ++---- signal/tst-sigset.c | 92 ++++++++++++++++++++++++++++++++++++++--------------- 5 files changed, 76 insertions(+), 38 deletions(-) (limited to 'signal') diff --git a/signal/sigaction.c b/signal/sigaction.c index f761ca2..c99001a 100644 --- a/signal/sigaction.c +++ b/signal/sigaction.c @@ -24,7 +24,7 @@ int __sigaction (int sig, const struct sigaction *act, struct sigaction *oact) { - if (sig <= 0 || sig >= NSIG) + if (sig <= 0 || sig >= NSIG || __is_internal_signal (sig)) { __set_errno (EINVAL); return -1; diff --git a/signal/sigaddset.c b/signal/sigaddset.c index d310890..7238df4 100644 --- a/signal/sigaddset.c +++ b/signal/sigaddset.c @@ -17,13 +17,14 @@ #include #include -#include +#include /* Add SIGNO to SET. */ int sigaddset (sigset_t *set, int signo) { - if (set == NULL || signo <= 0 || signo >= NSIG) + if (set == NULL || signo <= 0 || signo >= NSIG + || __is_internal_signal (signo)) { __set_errno (EINVAL); return -1; diff --git a/signal/sigdelset.c b/signal/sigdelset.c index cd83dda..011978c 100644 --- a/signal/sigdelset.c +++ b/signal/sigdelset.c @@ -17,13 +17,14 @@ #include #include -#include +#include /* Add SIGNO to SET. */ int sigdelset (sigset_t *set, int signo) { - if (set == NULL || signo <= 0 || signo >= NSIG) + if (set == NULL || signo <= 0 || signo >= NSIG + || __is_internal_signal (signo)) { __set_errno (EINVAL); return -1; diff --git a/signal/sigfillset.c b/signal/sigfillset.c index e586fd9..83dd583 100644 --- a/signal/sigfillset.c +++ b/signal/sigfillset.c @@ -18,6 +18,7 @@ #include #include #include +#include /* Set all signals in SET. */ int @@ -31,14 +32,7 @@ sigfillset (sigset_t *set) memset (set, 0xff, sizeof (sigset_t)); - /* If the implementation uses a cancellation signal don't set the bit. */ -#ifdef SIGCANCEL - __sigdelset (set, SIGCANCEL); -#endif - /* Likewise for the signal to implement setxid. */ -#ifdef SIGSETXID - __sigdelset (set, SIGSETXID); -#endif + __clear_internal_signals (set); return 0; } diff --git a/signal/tst-sigset.c b/signal/tst-sigset.c index d47adcc..a2b764d 100644 --- a/signal/tst-sigset.c +++ b/signal/tst-sigset.c @@ -1,43 +1,85 @@ /* Test sig*set functions. */ #include -#include -#define TEST_FUNCTION do_test () +#include + static int do_test (void) { - int result = 0; - int sig = -1; + sigset_t set; + TEST_VERIFY (sigemptyset (&set) == 0); -#define TRY(call) \ - if (call) \ - { \ - printf ("%s (sig = %d): %m\n", #call, sig); \ - result = 1; \ - } \ - else +#define VERIFY(set, sig) \ + TEST_VERIFY (sigismember (&set, sig) == 0); \ + TEST_VERIFY (sigaddset (&set, sig) == 0); \ + TEST_VERIFY (sigismember (&set, sig) != 0); \ + TEST_VERIFY (sigdelset (&set, sig) == 0); \ + TEST_VERIFY (sigismember (&set, sig) == 0) + /* ISO C99 signals. */ + VERIFY (set, SIGINT); + VERIFY (set, SIGILL); + VERIFY (set, SIGABRT); + VERIFY (set, SIGFPE); + VERIFY (set, SIGSEGV); + VERIFY (set, SIGTERM); - sigset_t set; - TRY (sigemptyset (&set) != 0); + /* Historical signals specified by POSIX. */ + VERIFY (set, SIGHUP); + VERIFY (set, SIGQUIT); + VERIFY (set, SIGTRAP); + VERIFY (set, SIGKILL); + VERIFY (set, SIGBUS); + VERIFY (set, SIGSYS); + VERIFY (set, SIGPIPE); + VERIFY (set, SIGALRM); + + /* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */ + VERIFY (set, SIGURG); + VERIFY (set, SIGSTOP); + VERIFY (set, SIGTSTP); + VERIFY (set, SIGCONT); + VERIFY (set, SIGCHLD); + VERIFY (set, SIGTTIN); + VERIFY (set, SIGTTOU); + VERIFY (set, SIGPOLL); + VERIFY (set, SIGXCPU); + VERIFY (set, SIGXFSZ); + VERIFY (set, SIGVTALRM); + VERIFY (set, SIGPROF); + VERIFY (set, SIGUSR1); + VERIFY (set, SIGUSR2); + + /* Nonstandard signals found in all modern POSIX systems + (including both BSD and Linux). */ + VERIFY (set, SIGWINCH); -#ifdef SIGRTMAX - int max_sig = SIGRTMAX; -#else - int max_sig = NSIG - 1; + /* Arch-specific signals. */ +#ifdef SIGEMT + VERIFY (set, SIGEMT); +#endif +#ifdef SIGLOST + VERIFY (set, SIGLOST); +#endif +#ifdef SIGINFO + VERIFY (set, SIGINFO); +#endif +#ifdef SIGSTKFLT + VERIFY (set, SIGSTKFLT); +#endif +#ifdef SIGPWR + VERIFY (set, SIGPWR); #endif - for (sig = 1; sig <= max_sig; ++sig) + /* Read-time signals (POSIX.1b real-time extensions). If they are + supported SIGRTMAX value is greater than SIGRTMIN. */ + for (int rtsig = SIGRTMIN; rtsig <= SIGRTMAX; rtsig++) { - TRY (sigismember (&set, sig) != 0); - TRY (sigaddset (&set, sig) != 0); - TRY (sigismember (&set, sig) == 0); - TRY (sigdelset (&set, sig) != 0); - TRY (sigismember (&set, sig) != 0); + VERIFY (set, rtsig); } - return result; + return 0; } -#include "../test-skeleton.c" +#include -- cgit v1.1