diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2017-10-31 23:10:37 -0200 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2018-04-03 13:30:49 -0300 |
commit | d2dc5467c67bc8625a4fc8f285b6a5443bf43df4 (patch) | |
tree | 27ddabfd779bfcbcc92f095288be5778ec4370ca /sysdeps | |
parent | 511ed56f2e792bea5e7145e1d5d5c93b9f47c41f (diff) | |
download | glibc-d2dc5467c67bc8625a4fc8f285b6a5443bf43df4.tar glibc-d2dc5467c67bc8625a4fc8f285b6a5443bf43df4.tar.gz glibc-d2dc5467c67bc8625a4fc8f285b6a5443bf43df4.tar.bz2 glibc-d2dc5467c67bc8625a4fc8f285b6a5443bf43df4.zip |
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 'sysdeps')
-rw-r--r-- | sysdeps/generic/internal-signals.h | 36 | ||||
-rw-r--r-- | sysdeps/nptl/sigfillset.c | 20 | ||||
-rw-r--r-- | sysdeps/posix/signal.c | 5 | ||||
-rw-r--r-- | sysdeps/posix/sigset.c | 10 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/internal-signals.h | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/sigtimedwait.c | 17 |
6 files changed, 46 insertions, 46 deletions
diff --git a/sysdeps/generic/internal-signals.h b/sysdeps/generic/internal-signals.h index 01e5b75b6b..17ed48c5bf 100644 --- a/sysdeps/generic/internal-signals.h +++ b/sysdeps/generic/internal-signals.h @@ -15,3 +15,39 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ + +#ifndef __INTERNAL_SIGNALS_H +# define __INTERNAL_SIGNALS_H + +static inline bool +__is_internal_signal (int sig) +{ + return false; +} + +static inline void +__clear_internal_signals (sigset_t *set) +{ +} + +static inline int +__libc_signal_block_all (sigset_t *set) +{ + return 0; +} + +static inline int +__libc_signal_block_app (sigset_t *set) +{ + return 0; +} + +/* Restore current process signal mask. */ +static inline int +__libc_signal_restore_set (const sigset_t *set) +{ + return 0; +} + + +#endif /* __INTERNAL_SIGNALS_H */ diff --git a/sysdeps/nptl/sigfillset.c b/sysdeps/nptl/sigfillset.c deleted file mode 100644 index 94a7680aa3..0000000000 --- a/sysdeps/nptl/sigfillset.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (C) 2003-2018 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <http://www.gnu.org/licenses/>. */ - -#include <nptl/pthreadP.h> - -#include <signal/sigfillset.c> diff --git a/sysdeps/posix/signal.c b/sysdeps/posix/signal.c index a4a0875ae5..8a135c7b0e 100644 --- a/sysdeps/posix/signal.c +++ b/sysdeps/posix/signal.c @@ -18,8 +18,8 @@ #include <errno.h> #include <signal.h> -#include <string.h> /* For the real memset prototype. */ #include <sigsetops.h> +#include <internal-signals.h> sigset_t _sigintr attribute_hidden; /* Set by siginterrupt. */ @@ -31,7 +31,8 @@ __bsd_signal (int sig, __sighandler_t handler) struct sigaction act, oact; /* Check signal extents to protect __sigismember. */ - if (handler == SIG_ERR || sig < 1 || sig >= NSIG) + if (handler == SIG_ERR || sig < 1 || sig >= NSIG + || __is_internal_signal (sig)) { __set_errno (EINVAL); return SIG_ERR; diff --git a/sysdeps/posix/sigset.c b/sysdeps/posix/sigset.c index b62aa3cc84..6ab4a48767 100644 --- a/sysdeps/posix/sigset.c +++ b/sysdeps/posix/sigset.c @@ -31,15 +31,9 @@ sigset (int sig, __sighandler_t disp) sigset_t set; sigset_t oset; - /* Check signal extents to protect __sigismember. */ - if (disp == SIG_ERR || sig < 1 || sig >= NSIG) - { - __set_errno (EINVAL); - return SIG_ERR; - } - __sigemptyset (&set); - __sigaddset (&set, sig); + if (sigaddset (&set, sig) < 0) + return SIG_ERR; if (disp == SIG_HOLD) { diff --git a/sysdeps/unix/sysv/linux/internal-signals.h b/sysdeps/unix/sysv/linux/internal-signals.h index e007372f21..5ff4cf83d5 100644 --- a/sysdeps/unix/sysv/linux/internal-signals.h +++ b/sysdeps/unix/sysv/linux/internal-signals.h @@ -21,6 +21,8 @@ #include <signal.h> #include <sigsetops.h> +#include <stdbool.h> +#include <sysdep.h> /* The signal used for asynchronous cancelation. */ #define SIGCANCEL __SIGRTMIN @@ -37,7 +39,7 @@ /* Return is sig is used internally. */ -static inline int +static inline bool __is_internal_signal (int sig) { return (sig == SIGCANCEL) || (sig == SIGSETXID); diff --git a/sysdeps/unix/sysv/linux/sigtimedwait.c b/sysdeps/unix/sysv/linux/sigtimedwait.c index 051a28575f..b4de8856dd 100644 --- a/sysdeps/unix/sysv/linux/sigtimedwait.c +++ b/sysdeps/unix/sysv/linux/sigtimedwait.c @@ -24,21 +24,8 @@ int __sigtimedwait (const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { - sigset_t tmpset; - if (set != NULL - && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) - || __builtin_expect (__sigismember (set, SIGSETXID), 0))) - { - /* Create a temporary mask without the bit for SIGCANCEL set. */ - // We are not copying more than we have to. - memcpy (&tmpset, set, _NSIG / 8); - __sigdelset (&tmpset, SIGCANCEL); - __sigdelset (&tmpset, SIGSETXID); - set = &tmpset; - } - - /* XXX The size argument hopefully will have to be changed to the - real size of the user-level sigset_t. */ + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ int result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, timeout, _NSIG / 8); /* The kernel generates a SI_TKILL code in si_code in case tkill is |