1 /* $OpenBSD: atexit.c,v 1.20 2014/07/11 09:51:37 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2002 Daniel Hartmeier 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * - Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * - Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials provided 15 * with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/types.h> 33 #include <sys/mman.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include "atexit.h" 38 #include "private/thread_private.h" 39 40 /* BEGIN android-changed */ 41 #include "private/bionic_prctl.h" 42 /* END android-changed */ 43 44 struct atexit { 45 struct atexit *next; /* next in list */ 46 int ind; /* next index in this table */ 47 int max; /* max entries >= ATEXIT_SIZE */ 48 struct atexit_fn { 49 void (*fn_ptr)(void *); 50 void *fn_arg; /* argument for CXA callback */ 51 void *fn_dso; /* shared module handle */ 52 } fns[1]; /* the table itself */ 53 }; 54 55 static struct atexit *__atexit; 56 static int restartloop; 57 58 /* BEGIN android-changed: __unregister_atfork is used by __cxa_finalize */ 59 extern void __unregister_atfork(void* dso); 60 /* END android-changed */ 61 62 /* 63 * Function pointers are stored in a linked list of pages. The list 64 * is initially empty, and pages are allocated on demand. The first 65 * function pointer in the first allocated page (the last one in 66 * the linked list) is reserved for the cleanup function. 67 * 68 * Outside the following functions, all pages are mprotect()'ed 69 * to prevent unintentional/malicious corruption. 70 */ 71 72 /* 73 * Register a function to be performed at exit or when a shared object 74 * with the given dso handle is unloaded dynamically. Also used as 75 * the backend for atexit(). For more info on this API, see: 76 * 77 * http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor 78 */ 79 int 80 __cxa_atexit(void (*func)(void *), void *arg, void *dso) 81 { 82 struct atexit *p = __atexit; 83 struct atexit_fn *fnp; 84 size_t pgsize = getpagesize(); 85 int ret = -1; 86 87 if (pgsize < sizeof(*p)) 88 return (-1); 89 _ATEXIT_LOCK(); 90 p = __atexit; 91 if (p != NULL) { 92 if (p->ind + 1 >= p->max) 93 p = NULL; 94 else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) 95 goto unlock; 96 } 97 if (p == NULL) { 98 p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, 99 MAP_ANON | MAP_PRIVATE, -1, 0); 100 if (p == MAP_FAILED) 101 goto unlock; 102 /* BEGIN android-changed */ 103 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize, 104 "atexit handlers"); 105 /* END android-changed */ 106 if (__atexit == NULL) { 107 memset(&p->fns[0], 0, sizeof(p->fns[0])); 108 p->ind = 1; 109 } else 110 p->ind = 0; 111 p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) / 112 sizeof(p->fns[0]); 113 p->next = __atexit; 114 __atexit = p; 115 } 116 fnp = &p->fns[p->ind++]; 117 fnp->fn_ptr = func; 118 fnp->fn_arg = arg; 119 fnp->fn_dso = dso; 120 if (mprotect(p, pgsize, PROT_READ)) 121 goto unlock; 122 restartloop = 1; 123 ret = 0; 124 unlock: 125 _ATEXIT_UNLOCK(); 126 return (ret); 127 } 128 129 /* 130 * Call all handlers registered with __cxa_atexit() for the shared 131 * object owning 'dso'. 132 * Note: if 'dso' is NULL, then all remaining handlers are called. 133 */ 134 void 135 __cxa_finalize(void *dso) 136 { 137 struct atexit *p, *q; 138 struct atexit_fn fn; 139 int n, pgsize = getpagesize(); 140 static int call_depth; 141 142 _ATEXIT_LOCK(); 143 call_depth++; 144 145 restart: 146 restartloop = 0; 147 for (p = __atexit; p != NULL; p = p->next) { 148 for (n = p->ind; --n >= 0;) { 149 if (p->fns[n].fn_ptr == NULL) 150 continue; /* already called */ 151 if (dso != NULL && dso != p->fns[n].fn_dso) 152 continue; /* wrong DSO */ 153 154 /* 155 * Mark handler as having been already called to avoid 156 * dupes and loops, then call the appropriate function. 157 */ 158 fn = p->fns[n]; 159 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) { 160 p->fns[n].fn_ptr = NULL; 161 mprotect(p, pgsize, PROT_READ); 162 } 163 _ATEXIT_UNLOCK(); 164 (*fn.fn_ptr)(fn.fn_arg); 165 _ATEXIT_LOCK(); 166 if (restartloop) 167 goto restart; 168 } 169 } 170 171 call_depth--; 172 173 /* 174 * If called via exit(), unmap the pages since we have now run 175 * all the handlers. We defer this until calldepth == 0 so that 176 * we don't unmap things prematurely if called recursively. 177 */ 178 if (dso == NULL && call_depth == 0) { 179 for (p = __atexit; p != NULL; ) { 180 q = p; 181 p = p->next; 182 munmap(q, pgsize); 183 } 184 __atexit = NULL; 185 } 186 _ATEXIT_UNLOCK(); 187 188 extern void __libc_stdio_cleanup(void); 189 __libc_stdio_cleanup(); 190 191 /* BEGIN android-changed: call __unregister_atfork if dso is not null */ 192 if (dso != NULL) { 193 __unregister_atfork(dso); 194 } 195 /* END android-changed */ 196 } 197