summaryrefslogtreecommitdiff
path: root/signal
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2017-10-31 23:10:37 -0200
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2018-04-03 13:30:49 -0300
commitd2dc5467c67bc8625a4fc8f285b6a5443bf43df4 (patch)
tree27ddabfd779bfcbcc92f095288be5778ec4370ca /signal
parent511ed56f2e792bea5e7145e1d5d5c93b9f47c41f (diff)
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 <ynorov@caviumnetworks.com>
Diffstat (limited to 'signal')
-rw-r--r--signal/sigaction.c2
-rw-r--r--signal/sigaddset.c5
-rw-r--r--signal/sigdelset.c5
-rw-r--r--signal/sigfillset.c10
-rw-r--r--signal/tst-sigset.c92
5 files changed, 76 insertions, 38 deletions
diff --git a/signal/sigaction.c b/signal/sigaction.c
index f761ca2612..c99001af42 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 d310890ec3..7238df4738 100644
--- a/signal/sigaddset.c
+++ b/signal/sigaddset.c
@@ -17,13 +17,14 @@
#include <errno.h>
#include <signal.h>
-#include <sigsetops.h>
+#include <internal-signals.h>
/* 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 cd83dda57b..011978cf33 100644
--- a/signal/sigdelset.c
+++ b/signal/sigdelset.c
@@ -17,13 +17,14 @@
#include <errno.h>
#include <signal.h>
-#include <sigsetops.h>
+#include <internal-signals.h>
/* 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 e586fd9295..83dd583b7b 100644
--- a/signal/sigfillset.c
+++ b/signal/sigfillset.c
@@ -18,6 +18,7 @@
#include <errno.h>
#include <signal.h>
#include <string.h>
+#include <internal-signals.h>
/* 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 d47adcc0d4..a2b764de5a 100644
--- a/signal/tst-sigset.c
+++ b/signal/tst-sigset.c
@@ -1,43 +1,85 @@
/* Test sig*set functions. */
#include <signal.h>
-#include <stdio.h>
-#define TEST_FUNCTION do_test ()
+#include <support/check.h>
+
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 <support/test-driver.c>