nptl: Install cancellation handler on pthread_cancel

Now that cancellation is not used anymore to handle thread setup
creation failure, the sighandle can be installed only when
pthread_cancel is actually used.

Checked on x86_64-linux-gnu and aarch64-linux-gnu.
This commit is contained in:
Adhemerval Zanella 2021-05-24 18:56:59 -03:00
parent 02189e8fb0
commit 41c7295617
4 changed files with 28 additions and 45 deletions

View File

@ -403,7 +403,6 @@ libc {
__nptl_free_tcb; __nptl_free_tcb;
__nptl_nthreads; __nptl_nthreads;
__nptl_setxid_sighandler; __nptl_setxid_sighandler;
__nptl_sigcancel_handler;
__nptl_stack_list_add; __nptl_stack_list_add;
__nptl_stack_list_del; __nptl_stack_list_del;
__pthread_attr_copy; __pthread_attr_copy;
@ -522,4 +521,4 @@ ld {
__nptl_initial_report_events; __nptl_initial_report_events;
__nptl_set_robust_list_avail; __nptl_set_robust_list_avail;
} }
} }

View File

@ -569,12 +569,6 @@ libc_hidden_proto (__pthread_attr_setsigmask_internal)
extern __typeof (pthread_attr_getsigmask_np) __pthread_attr_getsigmask_np; extern __typeof (pthread_attr_getsigmask_np) __pthread_attr_getsigmask_np;
libc_hidden_proto (__pthread_attr_getsigmask_np) libc_hidden_proto (__pthread_attr_getsigmask_np)
/* The cancellation signal handler defined alongside with
pthread_cancel. This is included in statically linked binaries
only if pthread_cancel is linked in. */
void __nptl_sigcancel_handler (int sig, siginfo_t *si, void *ctx);
libc_hidden_proto (__nptl_sigcancel_handler)
/* Special versions which use non-exported functions. */ /* Special versions which use non-exported functions. */
extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
void (*routine) (void *), void *arg); void (*routine) (void *), void *arg);

View File

@ -28,11 +28,19 @@
#include <gnu/lib-names.h> #include <gnu/lib-names.h>
#include <sys/single_threaded.h> #include <sys/single_threaded.h>
/* For asynchronous cancellation we use a signal. This is the core /* For asynchronous cancellation we use a signal. */
logic of the signal handler. */
static void static void
sigcancel_handler (void) sigcancel_handler (int sig, siginfo_t *si, void *ctx)
{ {
/* Safety check. It would be possible to call this function for
other signals and send a signal from another process. This is not
correct and might even be a security problem. Try to catch as
many incorrect invocations as possible. */
if (sig != SIGCANCEL
|| si->si_pid != __getpid()
|| si->si_code != SI_TKILL)
return;
struct pthread *self = THREAD_SELF; struct pthread *self = THREAD_SELF;
int oldval = THREAD_GETMEM (self, cancelhandling); int oldval = THREAD_GETMEM (self, cancelhandling);
@ -66,24 +74,6 @@ sigcancel_handler (void)
} }
} }
/* This is the actually installed SIGCANCEL handler. It adds some
safety checks before performing the cancellation. */
void
__nptl_sigcancel_handler (int sig, siginfo_t *si, void *ctx)
{
/* Safety check. It would be possible to call this function for
other signals and send a signal from another process. This is not
correct and might even be a security problem. Try to catch as
many incorrect invocations as possible. */
if (sig != SIGCANCEL
|| si->si_pid != __getpid()
|| si->si_code != SI_TKILL)
return;
sigcancel_handler ();
}
libc_hidden_def (__nptl_sigcancel_handler)
int int
__pthread_cancel (pthread_t th) __pthread_cancel (pthread_t th)
{ {
@ -94,6 +84,17 @@ __pthread_cancel (pthread_t th)
/* Not a valid thread handle. */ /* Not a valid thread handle. */
return ESRCH; return ESRCH;
static int init_sigcancel = 0;
if (atomic_load_relaxed (&init_sigcancel) == 0)
{
struct sigaction sa;
sa.sa_sigaction = sigcancel_handler;
sa.sa_flags = SA_SIGINFO;
__sigemptyset (&sa.sa_mask);
__libc_sigaction (SIGCANCEL, &sa, NULL);
atomic_store_relaxed (&init_sigcancel, 1);
}
#ifdef SHARED #ifdef SHARED
/* Trigger an error if libgcc_s cannot be loaded. */ /* Trigger an error if libgcc_s cannot be loaded. */
{ {
@ -134,7 +135,11 @@ __pthread_cancel (pthread_t th)
call pthread_cancel (pthread_self ()) without calling call pthread_cancel (pthread_self ()) without calling
pthread_create, so the signal handler may not have been pthread_create, so the signal handler may not have been
set up for a self-cancel. */ set up for a self-cancel. */
sigcancel_handler (); {
THREAD_SETMEM (pd, result, PTHREAD_CANCELED);
if ((newval & CANCELTYPE_BITMASK) != 0)
__do_cancel ();
}
else else
{ {
/* The cancellation handler will take care of marking the /* The cancellation handler will take care of marking the

View File

@ -67,21 +67,6 @@ late_init (void)
struct sigaction sa; struct sigaction sa;
__sigemptyset (&sa.sa_mask); __sigemptyset (&sa.sa_mask);
/* Install the cancellation signal handler (in static builds only if
pthread_cancel has been linked in). If for some reason we cannot
install the handler we do not abort. Maybe we should, but it is
only asynchronous cancellation which is affected. */
#ifndef SHARED
extern __typeof (__nptl_sigcancel_handler) __nptl_sigcancel_handler
__attribute__ ((weak));
if (__nptl_sigcancel_handler != NULL)
#endif
{
sa.sa_sigaction = __nptl_sigcancel_handler;
sa.sa_flags = SA_SIGINFO;
(void) __libc_sigaction (SIGCANCEL, &sa, NULL);
}
/* Install the handle to change the threads' uid/gid. Use /* Install the handle to change the threads' uid/gid. Use
SA_ONSTACK because the signal may be sent to threads that are SA_ONSTACK because the signal may be sent to threads that are
running with custom stacks. (This is less likely for running with custom stacks. (This is less likely for