| 1 | /* Copyright (C) 2002-2023 Free Software Foundation, Inc. | 
| 2 |    This file is part of the GNU C Library. | 
| 3 |  | 
| 4 |    The GNU C Library is free software; you can redistribute it and/or | 
| 5 |    modify it under the terms of the GNU Lesser General Public | 
| 6 |    License as published by the Free Software Foundation; either | 
| 7 |    version 2.1 of the License, or (at your option) any later version. | 
| 8 |  | 
| 9 |    The GNU C Library is distributed in the hope that it will be useful, | 
| 10 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
| 12 |    Lesser General Public License for more details. | 
| 13 |  | 
| 14 |    You should have received a copy of the GNU Lesser General Public | 
| 15 |    License along with the GNU C Library; if not, see | 
| 16 |    <https://www.gnu.org/licenses/>.  */ | 
| 17 |  | 
| 18 | #include <errno.h> | 
| 19 | #include <signal.h> | 
| 20 | #include <stdlib.h> | 
| 21 | #include "pthreadP.h" | 
| 22 | #include <atomic.h> | 
| 23 | #include <sysdep.h> | 
| 24 | #include <unistd.h> | 
| 25 | #include <unwind-link.h> | 
| 26 | #include <stdio.h> | 
| 27 | #include <gnu/lib-names.h> | 
| 28 | #include <sys/single_threaded.h> | 
| 29 |  | 
| 30 | /* For asynchronous cancellation we use a signal.  */ | 
| 31 | static void | 
| 32 | sigcancel_handler (int sig, siginfo_t *si, void *ctx) | 
| 33 | { | 
| 34 |   /* Safety check.  It would be possible to call this function for | 
| 35 |      other signals and send a signal from another process.  This is not | 
| 36 |      correct and might even be a security problem.  Try to catch as | 
| 37 |      many incorrect invocations as possible.  */ | 
| 38 |   if (sig != SIGCANCEL | 
| 39 |       || si->si_pid != __getpid() | 
| 40 |       || si->si_code != SI_TKILL) | 
| 41 |     return; | 
| 42 |  | 
| 43 |   struct pthread *self = THREAD_SELF; | 
| 44 |  | 
| 45 |   int oldval = atomic_load_relaxed (&self->cancelhandling); | 
| 46 |   while (1) | 
| 47 |     { | 
| 48 |       /* We are canceled now.  When canceled by another thread this flag | 
| 49 | 	 is already set but if the signal is directly send (internally or | 
| 50 | 	 from another process) is has to be done here.  */ | 
| 51 |       int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; | 
| 52 |  | 
| 53 |       if (oldval == newval || (oldval & EXITING_BITMASK) != 0) | 
| 54 | 	/* Already canceled or exiting.  */ | 
| 55 | 	break; | 
| 56 |  | 
| 57 |       if (atomic_compare_exchange_weak_acquire (&self->cancelhandling, | 
| 58 | 						&oldval, newval)) | 
| 59 | 	{ | 
| 60 | 	  self->result = PTHREAD_CANCELED; | 
| 61 |  | 
| 62 | 	  /* Make sure asynchronous cancellation is still enabled.  */ | 
| 63 | 	  if ((oldval & CANCELTYPE_BITMASK) != 0) | 
| 64 | 	    /* Run the registered destructors and terminate the thread.  */ | 
| 65 | 	    __do_cancel (); | 
| 66 | 	} | 
| 67 |     } | 
| 68 | } | 
| 69 |  | 
| 70 | int | 
| 71 | __pthread_cancel (pthread_t th) | 
| 72 | { | 
| 73 |   volatile struct pthread *pd = (volatile struct pthread *) th; | 
| 74 |  | 
| 75 |   if (pd->tid == 0) | 
| 76 |     /* The thread has already exited on the kernel side.  Its outcome | 
| 77 |        (regular exit, other cancelation) has already been | 
| 78 |        determined.  */ | 
| 79 |     return 0; | 
| 80 |  | 
| 81 |   static int init_sigcancel = 0; | 
| 82 |   if (atomic_load_relaxed (&init_sigcancel) == 0) | 
| 83 |     { | 
| 84 |       struct sigaction sa; | 
| 85 |       sa.sa_sigaction = sigcancel_handler; | 
| 86 |       /* The signal handle should be non-interruptible to avoid the risk of | 
| 87 | 	 spurious EINTR caused by SIGCANCEL sent to process or if | 
| 88 | 	 pthread_cancel() is called while cancellation is disabled in the | 
| 89 | 	 target thread.  */ | 
| 90 |       sa.sa_flags = SA_SIGINFO | SA_RESTART; | 
| 91 |       __sigemptyset (&sa.sa_mask); | 
| 92 |       __libc_sigaction (SIGCANCEL, &sa, NULL); | 
| 93 |       atomic_store_relaxed (&init_sigcancel, 1); | 
| 94 |     } | 
| 95 |  | 
| 96 | #ifdef SHARED | 
| 97 |   /* Trigger an error if libgcc_s cannot be loaded.  */ | 
| 98 |   { | 
| 99 |     struct unwind_link *unwind_link = __libc_unwind_link_get (); | 
| 100 |     if (unwind_link == NULL) | 
| 101 |       __libc_fatal (LIBGCC_S_SO | 
| 102 | 		    " must be installed for pthread_cancel to work\n" ); | 
| 103 |   } | 
| 104 | #endif | 
| 105 |  | 
| 106 |   /* Some syscalls are never restarted after being interrupted by a signal | 
| 107 |      handler, regardless of the use of SA_RESTART (they always fail with | 
| 108 |      EINTR).  So pthread_cancel cannot send SIGCANCEL unless the cancellation | 
| 109 |      is enabled and set as asynchronous (in this case the cancellation will | 
| 110 |      be acted in the cancellation handler instead by the syscall wrapper). | 
| 111 |      Otherwise the target thread is set as 'cancelling' (CANCELING_BITMASK) | 
| 112 |      by atomically setting 'cancelhandling' and the cancelation will be acted | 
| 113 |      upon on next cancellation entrypoing in the target thread. | 
| 114 |  | 
| 115 |      It also requires to atomically check if cancellation is enabled and | 
| 116 |      asynchronous, so both cancellation state and type are tracked on | 
| 117 |      'cancelhandling'.  */ | 
| 118 |  | 
| 119 |   int result = 0; | 
| 120 |   int oldval = atomic_load_relaxed (&pd->cancelhandling); | 
| 121 |   int newval; | 
| 122 |   do | 
| 123 |     { | 
| 124 |     again: | 
| 125 |       newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; | 
| 126 |       if (oldval == newval) | 
| 127 | 	break; | 
| 128 |  | 
| 129 |       /* If the cancellation is handled asynchronously just send a | 
| 130 | 	 signal.  We avoid this if possible since it's more | 
| 131 | 	 expensive.  */ | 
| 132 |       if (cancel_enabled_and_canceled_and_async (newval)) | 
| 133 | 	{ | 
| 134 | 	  /* Mark the cancellation as "in progress".  */ | 
| 135 | 	  int newval2 = oldval | CANCELING_BITMASK; | 
| 136 | 	  if (!atomic_compare_exchange_weak_acquire (&pd->cancelhandling, | 
| 137 | 						     &oldval, newval2)) | 
| 138 | 	    goto again; | 
| 139 |  | 
| 140 | 	  if (pd == THREAD_SELF) | 
| 141 | 	    /* This is not merely an optimization: An application may | 
| 142 | 	       call pthread_cancel (pthread_self ()) without calling | 
| 143 | 	       pthread_create, so the signal handler may not have been | 
| 144 | 	       set up for a self-cancel.  */ | 
| 145 | 	    { | 
| 146 | 	      pd->result = PTHREAD_CANCELED; | 
| 147 | 	      if ((newval & CANCELTYPE_BITMASK) != 0) | 
| 148 | 		__do_cancel (); | 
| 149 | 	    } | 
| 150 | 	  else | 
| 151 | 	    /* The cancellation handler will take care of marking the | 
| 152 | 	       thread as canceled.  */ | 
| 153 | 	    result = __pthread_kill_internal (th, SIGCANCEL); | 
| 154 |  | 
| 155 | 	  break; | 
| 156 | 	} | 
| 157 |  | 
| 158 | 	/* A single-threaded process should be able to kill itself, since | 
| 159 | 	   there is nothing in the POSIX specification that says that it | 
| 160 | 	   cannot.  So we set multiple_threads to true so that cancellation | 
| 161 | 	   points get executed.  */ | 
| 162 | 	THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); | 
| 163 | #ifndef TLS_MULTIPLE_THREADS_IN_TCB | 
| 164 | 	__libc_single_threaded_internal = 0; | 
| 165 | #endif | 
| 166 |     } | 
| 167 |   while (!atomic_compare_exchange_weak_acquire (&pd->cancelhandling, &oldval, | 
| 168 | 						newval)); | 
| 169 |  | 
| 170 |   return result; | 
| 171 | } | 
| 172 | versioned_symbol (libc, __pthread_cancel, pthread_cancel, GLIBC_2_34); | 
| 173 |  | 
| 174 | #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) | 
| 175 | compat_symbol (libpthread, __pthread_cancel, pthread_cancel, GLIBC_2_0); | 
| 176 | #endif | 
| 177 |  | 
| 178 | /* Ensure that the unwinder is always linked in (the __pthread_unwind | 
| 179 |    reference from __do_cancel is weak).  Use ___pthread_unwind_next | 
| 180 |    (three underscores) to produce a strong reference to the same | 
| 181 |    file.  */ | 
| 182 | PTHREAD_STATIC_FN_REQUIRE (___pthread_unwind_next) | 
| 183 |  |