1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #pragma weak _atexit = atexit
  31 
  32 #include "lint.h"
  33 #include "thr_uberdata.h"
  34 #include "libc_int.h"
  35 #include "atexit.h"
  36 #include "stdiom.h"
  37 
  38 /*
  39  * Note that memory is managed by lmalloc()/lfree().
  40  *
  41  * Among other reasons, this is occasioned by the insistence of our
  42  * brothers sh(1) and csh(1) that they can do malloc, etc., better than
  43  * libc can.  Those programs define their own malloc routines, and
  44  * initialize the underlying mechanism in main().  This means that calls
  45  * to malloc occuring before main will crash.  The loader calls atexit(3C)
  46  * before calling main, so we'd better avoid malloc() when it does.
  47  *
  48  * Another reason for using lmalloc()/lfree() is that the atexit()
  49  * list must transcend all link maps.  See the Linker and Libraries
  50  * Guide for information on alternate link maps.
  51  *
  52  * See "thr_uberdata.h" for the definitions of structures used here.
  53  */
  54 
  55 static int in_range(_exithdlr_func_t, Lc_addr_range_t[], uint_t count);
  56 
  57 extern  caddr_t _getfp(void);
  58 
  59 /*
  60  * exitfns_lock is declared to be a recursive mutex so that we
  61  * can hold it while calling out to the registered functions.
  62  * If they call back to us, we are self-consistent and everything
  63  * works, even the case of calling exit() from functions called
  64  * by _exithandle() (recursive exit()).  All that is required is
  65  * that the registered functions actually return (no longjmp()s).
  66  *
  67  * Because exitfns_lock is declared to be a recursive mutex, we
  68  * cannot use it with lmutex_lock()/lmutex_unlock() and we must
  69  * use mutex_lock()/mutex_unlock().  This means that atexit()
  70  * and exit() are not async-signal-safe.  We make them fork1-safe
  71  * via the atexit_locks()/atexit_unlocks() functions, called from
  72  * libc_prepare_atfork()/libc_child_atfork()/libc_parent_atfork()
  73  */
  74 
  75 /*
  76  * atexit_locks() and atexit_unlocks() are called on every link map.
  77  * Do not use curthread->ul_uberdata->atexit_root for these.
  78  */
  79 void
  80 atexit_locks()
  81 {
  82         (void) mutex_lock(&__uberdata.atexit_root.exitfns_lock);
  83 }
  84 
  85 void
  86 atexit_unlocks()
  87 {
  88         (void) mutex_unlock(&__uberdata.atexit_root.exitfns_lock);
  89 }
  90 
  91 /*
  92  * atexit() is called before the primordial thread is fully set up.
  93  * Be careful about dereferencing self->ul_uberdata->atexit_root.
  94  */
  95 int
  96 atexit(void (*func)(void))
  97 {
  98         ulwp_t *self;
  99         atexit_root_t *arp;
 100         _exthdlr_t *p;
 101 
 102         if ((p = lmalloc(sizeof (_exthdlr_t))) == NULL)
 103                 return (-1);
 104 
 105         if ((self = __curthread()) == NULL)
 106                 arp = &__uberdata.atexit_root;
 107         else {
 108                 arp = &self->ul_uberdata->atexit_root;
 109                 (void) mutex_lock(&arp->exitfns_lock);
 110         }
 111         p->hdlr = func;
 112         p->next = arp->head;
 113         arp->head = p;
 114         if (self != NULL)
 115                 (void) mutex_unlock(&arp->exitfns_lock);
 116         return (0);
 117 }
 118 
 119 void
 120 _exithandle(void)
 121 {
 122         atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
 123         _exthdlr_t *p;
 124         int cancel_state;
 125 
 126         /* disable cancellation while running atexit handlers */
 127         (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 128         (void) mutex_lock(&arp->exitfns_lock);
 129         arp->exit_frame_monitor = _getfp() + STACK_BIAS;
 130         p = arp->head;
 131         while (p != NULL) {
 132                 arp->head = p->next;
 133                 p->hdlr();
 134                 lfree(p, sizeof (_exthdlr_t));
 135                 p = arp->head;
 136         }
 137         (void) mutex_unlock(&arp->exitfns_lock);
 138         (void) pthread_setcancelstate(cancel_state, NULL);
 139 }
 140 
 141 /*
 142  * _get_exit_frame_monitor is called by the C++ runtimes.
 143  */
 144 void *
 145 _get_exit_frame_monitor(void)
 146 {
 147         atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
 148         return (&arp->exit_frame_monitor);
 149 }
 150 
 151 /*
 152  * The following is a routine which the loader (ld.so.1) calls when it
 153  * processes a dlclose call on an object.  It resets all signal handlers
 154  * which fall within the union of the ranges specified by the elements
 155  * of the array range to SIG_DFL.
 156  */
 157 static void
 158 _preexec_sig_unload(Lc_addr_range_t range[], uint_t count)
 159 {
 160         uberdata_t *udp = curthread->ul_uberdata;
 161         int sig;
 162         rwlock_t *rwlp;
 163         struct sigaction *sap;
 164         struct sigaction oact;
 165         void (*handler)();
 166 
 167         for (sig = 1; sig < NSIG; sig++) {
 168                 sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction;
 169 again:
 170                 handler = sap->sa_handler;
 171                 if (handler != SIG_DFL && handler != SIG_IGN &&
 172                     in_range(handler, range, count)) {
 173                         rwlp = &udp->siguaction[sig].sig_lock;
 174                         lrw_wrlock(rwlp);
 175                         if (handler != sap->sa_handler) {
 176                                 lrw_unlock(rwlp);
 177                                 goto again;
 178                         }
 179                         sap->sa_handler = SIG_DFL;
 180                         sap->sa_flags = SA_SIGINFO;
 181                         (void) sigemptyset(&sap->sa_mask);
 182                         if (__sigaction(sig, NULL, &oact) == 0 &&
 183                             oact.sa_handler != SIG_DFL &&
 184                             oact.sa_handler != SIG_IGN)
 185                                 (void) __sigaction(sig, sap, NULL);
 186                         lrw_unlock(rwlp);
 187                 }
 188         }
 189 }
 190 
 191 /*
 192  * The following is a routine which the loader (ld.so.1) calls when it
 193  * processes a dlclose call on an object.  It cancels all atfork() entries
 194  * whose prefork, parent postfork, or child postfork functions fall within
 195  * the union of the ranges specified by the elements of the array range.
 196  */
 197 static void
 198 _preexec_atfork_unload(Lc_addr_range_t range[], uint_t count)
 199 {
 200         ulwp_t *self = curthread;
 201         uberdata_t *udp = self->ul_uberdata;
 202         atfork_t *atfork_q;
 203         atfork_t *atfp;
 204         atfork_t *next;
 205         void (*func)(void);
 206         int start_again;
 207 
 208         (void) mutex_lock(&udp->atfork_lock);
 209         if ((atfork_q = udp->atforklist) != NULL) {
 210                 atfp = atfork_q;
 211                 do {
 212                         next = atfp->forw;
 213                         start_again = 0;
 214 
 215                         if (((func = atfp->prepare) != NULL &&
 216                             in_range(func, range, count)) ||
 217                             ((func = atfp->parent) != NULL &&
 218                             in_range(func, range, count)) ||
 219                             ((func = atfp->child) != NULL &&
 220                             in_range(func, range, count))) {
 221                                 if (self->ul_fork) {
 222                                         /*
 223                                          * dlclose() called from a fork handler.
 224                                          * Deleting the entry would wreak havoc.
 225                                          * Just null out the function pointers
 226                                          * and leave the entry in place.
 227                                          */
 228                                         atfp->prepare = NULL;
 229                                         atfp->parent = NULL;
 230                                         atfp->child = NULL;
 231                                         continue;
 232                                 }
 233                                 if (atfp == atfork_q) {
 234                                         /* deleting the list head member */
 235                                         udp->atforklist = atfork_q = next;
 236                                         start_again = 1;
 237                                 }
 238                                 atfp->forw->back = atfp->back;
 239                                 atfp->back->forw = atfp->forw;
 240                                 lfree(atfp, sizeof (atfork_t));
 241                                 if (atfp == atfork_q) {
 242                                         /* we deleted the whole list */
 243                                         udp->atforklist = NULL;
 244                                         break;
 245                                 }
 246                         }
 247                 } while ((atfp = next) != atfork_q || start_again);
 248         }
 249         (void) mutex_unlock(&udp->atfork_lock);
 250 }
 251 
 252 /*
 253  * The following is a routine which the loader (ld.so.1) calls when it
 254  * processes a dlclose call on an object.  It sets the destructor
 255  * function pointer to NULL for all keys whose destructors fall within
 256  * the union of the ranges specified by the elements of the array range.
 257  * We don't assign TSD_UNALLOCATED (the equivalent of pthread_key_destroy())
 258  * because the thread may use the key's TSD further on in fini processing.
 259  */
 260 static void
 261 _preexec_tsd_unload(Lc_addr_range_t range[], uint_t count)
 262 {
 263         tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
 264         void (*func)(void *);
 265         int key;
 266 
 267         lmutex_lock(&tsdm->tsdm_lock);
 268         for (key = 1; key < tsdm->tsdm_nused; key++) {
 269                 if ((func = tsdm->tsdm_destro[key]) != NULL &&
 270                     func != TSD_UNALLOCATED &&
 271                     in_range((_exithdlr_func_t)func, range, count))
 272                         tsdm->tsdm_destro[key] = NULL;
 273         }
 274         lmutex_unlock(&tsdm->tsdm_lock);
 275 }
 276 
 277 /*
 278  * The following is a routine which the loader (ld.so.1) calls when it
 279  * processes dlclose calls on objects with atexit registrations.  It
 280  * executes the exit handlers that fall within the union of the ranges
 281  * specified by the elements of the array range in the REVERSE ORDER of
 282  * their registration.  Do not change this characteristic; it is REQUIRED
 283  * BEHAVIOR.
 284  */
 285 int
 286 _preexec_exit_handlers(Lc_addr_range_t range[], uint_t count)
 287 {
 288         atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
 289         _exthdlr_t *o;          /* previous node */
 290         _exthdlr_t *p;          /* this node */
 291         int cancel_state;
 292 
 293         /* disable cancellation while running atexit handlers */
 294         (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 295         (void) mutex_lock(&arp->exitfns_lock);
 296         o = NULL;
 297         p = arp->head;
 298         while (p != NULL) {
 299                 if (in_range(p->hdlr, range, count)) {
 300                         /* We need to execute this one */
 301                         if (o != NULL)
 302                                 o->next = p->next;
 303                         else
 304                                 arp->head = p->next;
 305                         p->hdlr();
 306                         lfree(p, sizeof (_exthdlr_t));
 307                         o = NULL;
 308                         p = arp->head;
 309                 } else {
 310                         o = p;
 311                         p = p->next;
 312                 }
 313         }
 314         (void) mutex_unlock(&arp->exitfns_lock);
 315         (void) pthread_setcancelstate(cancel_state, NULL);
 316 
 317         _preexec_tsd_unload(range, count);
 318         _preexec_atfork_unload(range, count);
 319         _preexec_sig_unload(range, count);
 320 
 321         return (0);
 322 }
 323 
 324 static int
 325 in_range(_exithdlr_func_t addr, Lc_addr_range_t ranges[], uint_t count)
 326 {
 327         uint_t idx;
 328 
 329         for (idx = 0; idx < count; idx++) {
 330                 if ((void *)addr >= ranges[idx].lb &&
 331                     (void *)addr < ranges[idx].ub) {
 332                         return (1);
 333                 }
 334         }
 335 
 336         return (0);
 337 }