1 /* $OpenBSD: init.c,v 1.7 2019/06/02 01:03:01 guenther Exp $ */ 2 /* 3 * Copyright (c) 2014,2015 Philip Guenther <guenther@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 19 #define _DYN_LOADER 20 21 #include <sys/types.h> 22 #include <sys/syscall.h> 23 24 #ifndef PIC 25 #include <sys/mman.h> 26 #endif 27 28 #include <tib.h> 29 #include <limits.h> /* NAME_MAX */ 30 #include <link.h> 31 #include <stdlib.h> /* atexit */ 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "init.h" 36 37 #define MAX(a,b) (((a)>(b))?(a):(b)) 38 39 #ifdef TIB_EXTRA_ALIGN 40 # define TIB_ALIGN MAX(__alignof__(struct tib), TIB_EXTRA_ALIGN) 41 #else 42 # define TIB_ALIGN __alignof__(struct tib) 43 #endif 44 45 /* XXX should be in an include file shared with csu */ 46 char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void)); 47 48 /* provide definition for this */ 49 int _pagesize = 0; 50 51 /* 52 * In dynamicly linked binaries environ and __progname are overriden by 53 * the definitions in ld.so. 54 */ 55 char **environ __attribute__((weak)) = NULL; 56 char *__progname __attribute__((weak)) = NULL; 57 58 59 #ifndef PIC 60 struct dl_phdr_info _static_phdr_info __relro = { .dlpi_name = "a.out" }; 61 62 static inline void early_static_init(char **_argv, char **_envp); 63 static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum); 64 65 /* provided by the linker */ 66 extern Elf_Ehdr __executable_start[] __attribute__((weak)); 67 #endif /* PIC */ 68 69 /* provide definitions for these */ 70 const dl_cb *_dl_cb __relro = NULL; 71 72 void _libc_preinit(int, char **, char **, dl_cb_cb *) __dso_hidden; 73 void 74 _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb) 75 { 76 AuxInfo *aux; 77 #ifndef PIC 78 Elf_Phdr *phdr = NULL; 79 int phnum = 0; 80 81 /* static libc in a static link? */ 82 if (cb == NULL) 83 early_static_init(argv, envp); 84 #endif /* !PIC */ 85 86 if (cb != NULL) 87 _dl_cb = cb(DL_CB_CUR); 88 89 /* Extract useful bits from the auxiliary vector */ 90 while (*envp++ != NULL) 91 ; 92 for (aux = (void *)envp; aux->au_id != AUX_null; aux++) { 93 switch (aux->au_id) { 94 case AUX_pagesz: 95 _pagesize = aux->au_v; 96 break; 97 #ifndef PIC 98 case AUX_base: 99 _static_phdr_info.dlpi_addr = aux->au_v; 100 break; 101 case AUX_phdr: 102 phdr = (void *)aux->au_v; 103 break; 104 case AUX_phnum: 105 phnum = aux->au_v; 106 break; 107 #endif /* !PIC */ 108 } 109 } 110 111 #ifndef PIC 112 if (cb == NULL && phdr == NULL && __executable_start != NULL) { 113 /* 114 * Static non-PIE processes don't get an AUX vector, 115 * so find the phdrs through the ELF header 116 */ 117 _static_phdr_info.dlpi_addr = (Elf_Addr)__executable_start; 118 phdr = (void *)((char *)__executable_start + 119 __executable_start->e_phoff); 120 phnum = __executable_start->e_phnum; 121 } 122 _static_phdr_info.dlpi_phdr = phdr; 123 _static_phdr_info.dlpi_phnum = phnum; 124 125 /* static libc in a static link? */ 126 if (cb == NULL) 127 setup_static_tib(phdr, phnum); 128 #endif /* !PIC */ 129 } 130 131 /* ARM just had to be different... */ 132 #ifndef __arm__ 133 # define TYPE "@" 134 #else 135 # define TYPE "%" 136 #endif 137 138 #ifdef __LP64__ 139 # define VALUE_ALIGN ".balign 8" 140 # define VALUE_DIRECTIVE ".quad" 141 #else 142 # define VALUE_ALIGN ".balign 4" 143 # ifdef __hppa__ 144 /* hppa just had to be different: func pointers prefix with 'P%' */ 145 # define VALUE_DIRECTIVE ".int P%" 146 # else 147 # define VALUE_DIRECTIVE ".int" 148 # endif 149 #endif 150 151 #define ADD_TO_ARRAY(func, which) \ 152 __asm( " .section ."#which",\"a\","TYPE#which"\n " \ 153 VALUE_ALIGN"\n "VALUE_DIRECTIVE" "#func"\n .previous") 154 155 #ifdef PIC 156 ADD_TO_ARRAY(_libc_preinit, init_array); 157 #else 158 ADD_TO_ARRAY(_libc_preinit, preinit_array); 159 #endif 160 161 /* 162 * In dynamic links, invoke ld.so's dl_clean_boot() callback, if any, 163 * and register its cleanup. 164 */ 165 char *** 166 _csu_finish(char **argv, char **envp, void (*cleanup)(void)) 167 { 168 if (_dl_cb != NULL && _dl_cb->dl_clean_boot != NULL) 169 _dl_cb->dl_clean_boot(); 170 171 if (cleanup != NULL) 172 atexit(cleanup); 173 174 return &environ; 175 } 176 177 #ifndef PIC 178 /* 179 * static libc in a static link? Then disable kbind and set up 180 * __progname and environ 181 */ 182 static inline void 183 early_static_init(char **argv, char **envp) 184 { 185 static char progname_storage[NAME_MAX+1]; 186 187 /* disable kbind */ 188 syscall(SYS_kbind, (void *)NULL, (size_t)0, (long long)0); 189 190 environ = envp; 191 192 /* set up __progname */ 193 if (*argv != NULL) { /* NULL ptr if argc = 0 */ 194 const char *p = strrchr(*argv, '/'); 195 196 if (p == NULL) 197 p = *argv; 198 else 199 p++; 200 strlcpy(progname_storage, p, sizeof(progname_storage)); 201 } 202 __progname = progname_storage; 203 } 204 205 /* 206 * static TLS handling 207 */ 208 #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1)) 209 210 /* for static binaries, the location and size of the TLS image */ 211 static void *static_tls __relro; 212 static size_t static_tls_fsize __relro; 213 214 size_t _static_tls_size __relro = 0; 215 int _static_tls_align __relro; 216 int _static_tls_align_offset __relro; 217 218 static inline void 219 setup_static_tib(Elf_Phdr *phdr, int phnum) 220 { 221 struct tib *tib; 222 char *base; 223 int i; 224 225 _static_tls_align = TIB_ALIGN; 226 if (phdr != NULL) { 227 for (i = 0; i < phnum; i++) { 228 if (phdr[i].p_type != PT_TLS) 229 continue; 230 if (phdr[i].p_memsz == 0) 231 break; 232 if (phdr[i].p_memsz < phdr[i].p_filesz) 233 break; /* invalid */ 234 if (phdr[i].p_align > getpagesize()) 235 break; /* nope */ 236 _static_tls_align = MAX(phdr[i].p_align, TIB_ALIGN); 237 #if TLS_VARIANT == 1 238 /* 239 * Variant 1 places the data after the TIB. If the 240 * TLS alignment is larger than the TIB alignment 241 * then we may need to pad in front of the TIB to 242 * place the TLS data on the proper alignment. 243 * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4 244 * - need to offset the TIB 12 bytes from the start 245 * - to place ths TLS data at offset 64 246 */ 247 _static_tls_size = phdr[i].p_memsz; 248 _static_tls_align_offset = 249 ELF_ROUND(sizeof(struct tib), _static_tls_align) - 250 sizeof(struct tib); 251 #elif TLS_VARIANT == 2 252 /* 253 * Variant 2 places the data before the TIB 254 * so we need to round up the size to the 255 * TLS data alignment TIB's alignment. 256 * Example A: p_memsz=24 p_align=16 align(TIB)=8 257 * - need to allocate 32 bytes for TLS as compiler 258 * - will give the first TLS symbol an offset of -32 259 * Example B: p_memsz=4 p_align=4 align(TIB)=8 260 * - need to allocate 8 bytes so that the TIB is 261 * - properly aligned 262 */ 263 _static_tls_size = ELF_ROUND(phdr[i].p_memsz, 264 phdr[i].p_align); 265 _static_tls_align_offset = ELF_ROUND(_static_tls_size, 266 _static_tls_align) - _static_tls_size; 267 #endif 268 if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) { 269 static_tls = (void *)phdr[i].p_vaddr + 270 _static_phdr_info.dlpi_addr; 271 static_tls_fsize = phdr[i].p_filesz; 272 } 273 break; 274 } 275 } 276 277 base = mmap(NULL, _static_tls_size + _static_tls_align_offset 278 + sizeof *tib, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); 279 280 tib = _static_tls_init(base, NULL); 281 tib->tib_tid = getthrid(); 282 TCB_SET(TIB_TO_TCB(tib)); 283 #if ! TCB_HAVE_MD_GET 284 _libc_single_tcb = TIB_TO_TCB(tib); 285 #endif 286 } 287 288 struct tib * 289 _static_tls_init(char *base, void *thread) 290 { 291 struct tib *tib; 292 293 base += _static_tls_align_offset; 294 # if TLS_VARIANT == 1 295 tib = (struct tib *)base; 296 base += sizeof(struct tib); 297 # elif TLS_VARIANT == 2 298 tib = (struct tib *)(base + _static_tls_size); 299 # endif 300 301 if (_static_tls_size) { 302 if (static_tls != NULL) 303 memcpy(base, static_tls, static_tls_fsize); 304 memset(base + static_tls_fsize, 0, 305 _static_tls_size - static_tls_fsize); 306 } 307 308 TIB_INIT(tib, NULL, thread); 309 return tib; 310 } 311 #endif /* !PIC */ 312