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