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