1*17423a06Skettenis /* $OpenBSD: init.c,v 1.24 2024/07/22 22:06:27 kettenis Exp $ */ 25af055cdSguenther /* 35af055cdSguenther * Copyright (c) 2014,2015 Philip Guenther <guenther@openbsd.org> 45af055cdSguenther * 55af055cdSguenther * Permission to use, copy, modify, and distribute this software for any 65af055cdSguenther * purpose with or without fee is hereby granted, provided that the above 75af055cdSguenther * copyright notice and this permission notice appear in all copies. 85af055cdSguenther * 95af055cdSguenther * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 105af055cdSguenther * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 115af055cdSguenther * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 125af055cdSguenther * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 135af055cdSguenther * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 145af055cdSguenther * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 155af055cdSguenther * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 165af055cdSguenther */ 175af055cdSguenther 185af055cdSguenther 195af055cdSguenther #define _DYN_LOADER 205af055cdSguenther 215af055cdSguenther #include <sys/types.h> 22d97c60eaSguenther #include <sys/syscall.h> 23d82e6535Spirofti #include <sys/timetc.h> /* timekeep */ 245af055cdSguenther 25fe38b55cSguenther #ifndef PIC 26fe38b55cSguenther #include <sys/mman.h> 27fe38b55cSguenther #endif 28fe38b55cSguenther 29fe38b55cSguenther #include <tib.h> 305af055cdSguenther #include <limits.h> /* NAME_MAX */ 31767451c3Sguenther #include <link.h> 325af055cdSguenther #include <stdlib.h> /* atexit */ 335af055cdSguenther #include <string.h> 34fe38b55cSguenther #include <unistd.h> 355af055cdSguenther 36767451c3Sguenther #include "init.h" 37767451c3Sguenther 38f54aa464Sguenther #define MAX(a,b) (((a)>(b))?(a):(b)) 39f54aa464Sguenther 40f54aa464Sguenther #ifdef TIB_EXTRA_ALIGN 41f54aa464Sguenther # define TIB_ALIGN MAX(__alignof__(struct tib), TIB_EXTRA_ALIGN) 42f54aa464Sguenther #else 43f54aa464Sguenther # define TIB_ALIGN __alignof__(struct tib) 44f54aa464Sguenther #endif 45f54aa464Sguenther 465af055cdSguenther /* XXX should be in an include file shared with csu */ 475af055cdSguenther char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void)); 485af055cdSguenther 49d82e6535Spirofti /* provide definitions for these */ 505af055cdSguenther int _pagesize = 0; 51d82e6535Spirofti struct timekeep *_timekeep; 52ef873df0Sjca unsigned long _hwcap, _hwcap2; 53ef873df0Sjca int _hwcap_avail, _hwcap2_avail; 545af055cdSguenther 555af055cdSguenther /* 562c53affbSjmc * In dynamically linked binaries environ and __progname are overridden by 575af055cdSguenther * the definitions in ld.so. 585af055cdSguenther */ 595af055cdSguenther char **environ __attribute__((weak)) = NULL; 605af055cdSguenther char *__progname __attribute__((weak)) = NULL; 615af055cdSguenther 625af055cdSguenther 635af055cdSguenther #ifndef PIC 645c7d06e5Sguenther struct dl_phdr_info _static_phdr_info __relro = { .dlpi_name = "a.out" }; 65767451c3Sguenther 665af055cdSguenther static inline void early_static_init(char **_argv, char **_envp); 67fe38b55cSguenther static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum); 685af055cdSguenther 69f54aa464Sguenther /* provided by the linker */ 70f54aa464Sguenther extern Elf_Ehdr __executable_start[] __attribute__((weak)); 71f54aa464Sguenther #endif /* PIC */ 725af055cdSguenther 735c7d06e5Sguenther /* provide definitions for these */ 745c7d06e5Sguenther const dl_cb *_dl_cb __relro = NULL; 755c7d06e5Sguenther 761c92691bSderaadt int HIDDEN(execve)(const char *, char *const *, char *const *) 771c92691bSderaadt __attribute__((weak)); 781c92691bSderaadt 795c7d06e5Sguenther void _libc_preinit(int, char **, char **, dl_cb_cb *) __dso_hidden; 805c7d06e5Sguenther void 815c7d06e5Sguenther _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb) 825af055cdSguenther { 835af055cdSguenther AuxInfo *aux; 845af055cdSguenther #ifndef PIC 85fe38b55cSguenther Elf_Phdr *phdr = NULL; 86fe38b55cSguenther int phnum = 0; 87fe38b55cSguenther 885af055cdSguenther /* static libc in a static link? */ 895c7d06e5Sguenther if (cb == NULL) 905af055cdSguenther early_static_init(argv, envp); 915af055cdSguenther #endif /* !PIC */ 925af055cdSguenther 935c7d06e5Sguenther if (cb != NULL) 945c7d06e5Sguenther _dl_cb = cb(DL_CB_CUR); 955c7d06e5Sguenther 965af055cdSguenther /* Extract useful bits from the auxiliary vector */ 975af055cdSguenther while (*envp++ != NULL) 985af055cdSguenther ; 995af055cdSguenther for (aux = (void *)envp; aux->au_id != AUX_null; aux++) { 1005af055cdSguenther switch (aux->au_id) { 101ef873df0Sjca case AUX_hwcap: 102ef873df0Sjca _hwcap = aux->au_v; 103ef873df0Sjca _hwcap_avail = 1; 104ef873df0Sjca break; 105ef873df0Sjca case AUX_hwcap2: 106ef873df0Sjca _hwcap2 = aux->au_v; 107ef873df0Sjca _hwcap2_avail = 1; 108ef873df0Sjca break; 1095af055cdSguenther case AUX_pagesz: 1105af055cdSguenther _pagesize = aux->au_v; 1115af055cdSguenther break; 112fe38b55cSguenther #ifndef PIC 113767451c3Sguenther case AUX_base: 114767451c3Sguenther _static_phdr_info.dlpi_addr = aux->au_v; 115767451c3Sguenther break; 116fe38b55cSguenther case AUX_phdr: 117fe38b55cSguenther phdr = (void *)aux->au_v; 118fe38b55cSguenther break; 119fe38b55cSguenther case AUX_phnum: 120fe38b55cSguenther phnum = aux->au_v; 121fe38b55cSguenther break; 122fe38b55cSguenther #endif /* !PIC */ 123d82e6535Spirofti case AUX_openbsd_timekeep: 124d82e6535Spirofti if (_tc_get_timecount) { 125d82e6535Spirofti _timekeep = (void *)aux->au_v; 126d82e6535Spirofti if (_timekeep && 127d82e6535Spirofti _timekeep->tk_version != TK_VERSION) 128d82e6535Spirofti _timekeep = NULL; 129d82e6535Spirofti } 13022966de3Stedu if (issetugid() == 0 && getenv("LIBC_NOUSERTC")) 13122966de3Stedu _timekeep = NULL; 132d82e6535Spirofti break; 1335af055cdSguenther } 1345af055cdSguenther } 1355af055cdSguenther 136fe38b55cSguenther #ifndef PIC 1375c7d06e5Sguenther if (cb == NULL && phdr == NULL && __executable_start != NULL) { 138f54aa464Sguenther /* 139f54aa464Sguenther * Static non-PIE processes don't get an AUX vector, 140f54aa464Sguenther * so find the phdrs through the ELF header 141f54aa464Sguenther */ 142f54aa464Sguenther phdr = (void *)((char *)__executable_start + 143f54aa464Sguenther __executable_start->e_phoff); 144f54aa464Sguenther phnum = __executable_start->e_phnum; 145f54aa464Sguenther } 1465c7d06e5Sguenther _static_phdr_info.dlpi_phdr = phdr; 1475c7d06e5Sguenther _static_phdr_info.dlpi_phnum = phnum; 1485c7d06e5Sguenther 149fe38b55cSguenther /* static libc in a static link? */ 150c5e6b56aSderaadt if (cb == NULL) 151fe38b55cSguenther setup_static_tib(phdr, phnum); 152493e9f46Sderaadt 153493e9f46Sderaadt /* 154493e9f46Sderaadt * If a static binary has text relocations (DT_TEXT), then un-writeable 155493e9f46Sderaadt * segments were not made immutable by the kernel. Textrel and RELRO 156493e9f46Sderaadt * changes have now been completed and permissions corrected, so these 157493e9f46Sderaadt * regions can become immutable. 158493e9f46Sderaadt */ 159493e9f46Sderaadt if (phdr) { 160493e9f46Sderaadt int i; 161493e9f46Sderaadt 162493e9f46Sderaadt for (i = 0; i < phnum; i++) { 163493e9f46Sderaadt if (phdr[i].p_type == PT_LOAD && 164493e9f46Sderaadt (phdr[i].p_flags & PF_W) == 0) 165493e9f46Sderaadt mimmutable((void *)(_static_phdr_info.dlpi_addr + 166493e9f46Sderaadt phdr[i].p_vaddr), phdr[i].p_memsz); 167493e9f46Sderaadt } 168493e9f46Sderaadt } 169fe38b55cSguenther #endif /* !PIC */ 1705c7d06e5Sguenther } 1715c7d06e5Sguenther 1725c7d06e5Sguenther /* ARM just had to be different... */ 1735c7d06e5Sguenther #ifndef __arm__ 1745c7d06e5Sguenther # define TYPE "@" 1755c7d06e5Sguenther #else 1765c7d06e5Sguenther # define TYPE "%" 1775c7d06e5Sguenther #endif 1785c7d06e5Sguenther 1795c7d06e5Sguenther #ifdef __LP64__ 1805c7d06e5Sguenther # define VALUE_ALIGN ".balign 8" 1815c7d06e5Sguenther # define VALUE_DIRECTIVE ".quad" 1825c7d06e5Sguenther #else 1835c7d06e5Sguenther # define VALUE_ALIGN ".balign 4" 1845c7d06e5Sguenther # ifdef __hppa__ 1855c7d06e5Sguenther /* hppa just had to be different: func pointers prefix with 'P%' */ 1865c7d06e5Sguenther # define VALUE_DIRECTIVE ".int P%" 1875c7d06e5Sguenther # else 1885c7d06e5Sguenther # define VALUE_DIRECTIVE ".int" 1895c7d06e5Sguenther # endif 1905c7d06e5Sguenther #endif 1915c7d06e5Sguenther 1925c7d06e5Sguenther #ifdef PIC 193*17423a06Skettenis /* 194*17423a06Skettenis * Set a priority so _libc_preinit gets called before the constructor 195*17423a06Skettenis * on libcompiler_rt that may use elf_aux_info(3). 196*17423a06Skettenis */ 197*17423a06Skettenis __asm(" .section .init_array.50,\"a\","TYPE"init_array\n " \ 198*17423a06Skettenis VALUE_ALIGN"\n "VALUE_DIRECTIVE" _libc_preinit\n .previous"); 1995c7d06e5Sguenther #else 200*17423a06Skettenis __asm(" .section .preinit_array,\"a\","TYPE"preinit_array\n " \ 201*17423a06Skettenis VALUE_ALIGN"\n "VALUE_DIRECTIVE" _libc_preinit\n .previous"); 2025c7d06e5Sguenther #endif 2035c7d06e5Sguenther 2045c7d06e5Sguenther /* 2055c7d06e5Sguenther * In dynamic links, invoke ld.so's dl_clean_boot() callback, if any, 2065c7d06e5Sguenther * and register its cleanup. 2075c7d06e5Sguenther */ 2085c7d06e5Sguenther char *** 2095c7d06e5Sguenther _csu_finish(char **argv, char **envp, void (*cleanup)(void)) 2105c7d06e5Sguenther { 2115c7d06e5Sguenther if (_dl_cb != NULL && _dl_cb->dl_clean_boot != NULL) 2125c7d06e5Sguenther _dl_cb->dl_clean_boot(); 213fe38b55cSguenther 2145af055cdSguenther if (cleanup != NULL) 2155af055cdSguenther atexit(cleanup); 2165af055cdSguenther 2175af055cdSguenther return &environ; 2185af055cdSguenther } 2195af055cdSguenther 2205af055cdSguenther #ifndef PIC 2215af055cdSguenther /* 222b18b10d8Sguenther * static libc in a static link? Then set up __progname and environ 2235af055cdSguenther */ 2245af055cdSguenther static inline void 2255af055cdSguenther early_static_init(char **argv, char **envp) 2265af055cdSguenther { 227d97c60eaSguenther static char progname_storage[NAME_MAX+1]; 2285af055cdSguenther 2295af055cdSguenther environ = envp; 2305af055cdSguenther 2315af055cdSguenther /* set up __progname */ 2325af055cdSguenther if (*argv != NULL) { /* NULL ptr if argc = 0 */ 2335af055cdSguenther const char *p = strrchr(*argv, '/'); 2345af055cdSguenther 2355af055cdSguenther if (p == NULL) 2365af055cdSguenther p = *argv; 2375af055cdSguenther else 2385af055cdSguenther p++; 2395af055cdSguenther strlcpy(progname_storage, p, sizeof(progname_storage)); 2405af055cdSguenther } 2415af055cdSguenther __progname = progname_storage; 2425af055cdSguenther } 243fe38b55cSguenther 244fe38b55cSguenther /* 245fe38b55cSguenther * static TLS handling 246fe38b55cSguenther */ 247fe38b55cSguenther #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1)) 248fe38b55cSguenther 249fe38b55cSguenther /* for static binaries, the location and size of the TLS image */ 2505c7d06e5Sguenther static void *static_tls __relro; 2515c7d06e5Sguenther static size_t static_tls_fsize __relro; 252fe38b55cSguenther 2535c7d06e5Sguenther size_t _static_tls_size __relro = 0; 2545c7d06e5Sguenther int _static_tls_align __relro; 2555c7d06e5Sguenther int _static_tls_align_offset __relro; 256fe38b55cSguenther 257fe38b55cSguenther static inline void 258fe38b55cSguenther setup_static_tib(Elf_Phdr *phdr, int phnum) 259fe38b55cSguenther { 260fe38b55cSguenther struct tib *tib; 261fe38b55cSguenther char *base; 262fe38b55cSguenther int i; 263fe38b55cSguenther 264f54aa464Sguenther _static_tls_align = TIB_ALIGN; 265fe38b55cSguenther if (phdr != NULL) { 266fe38b55cSguenther for (i = 0; i < phnum; i++) { 267fe38b55cSguenther if (phdr[i].p_type != PT_TLS) 268fe38b55cSguenther continue; 269fe38b55cSguenther if (phdr[i].p_memsz == 0) 270fe38b55cSguenther break; 271fe38b55cSguenther if (phdr[i].p_memsz < phdr[i].p_filesz) 272fe38b55cSguenther break; /* invalid */ 273f54aa464Sguenther if (phdr[i].p_align > getpagesize()) 274f54aa464Sguenther break; /* nope */ 275f54aa464Sguenther _static_tls_align = MAX(phdr[i].p_align, TIB_ALIGN); 276fe38b55cSguenther #if TLS_VARIANT == 1 277f54aa464Sguenther /* 278f54aa464Sguenther * Variant 1 places the data after the TIB. If the 279f54aa464Sguenther * TLS alignment is larger than the TIB alignment 280f54aa464Sguenther * then we may need to pad in front of the TIB to 281f54aa464Sguenther * place the TLS data on the proper alignment. 282f54aa464Sguenther * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4 283f54aa464Sguenther * - need to offset the TIB 12 bytes from the start 284f54aa464Sguenther * - to place ths TLS data at offset 64 285f54aa464Sguenther */ 286fe38b55cSguenther _static_tls_size = phdr[i].p_memsz; 287f54aa464Sguenther _static_tls_align_offset = 288f54aa464Sguenther ELF_ROUND(sizeof(struct tib), _static_tls_align) - 289f54aa464Sguenther sizeof(struct tib); 290fe38b55cSguenther #elif TLS_VARIANT == 2 291fe38b55cSguenther /* 292f54aa464Sguenther * Variant 2 places the data before the TIB 293f54aa464Sguenther * so we need to round up the size to the 294f54aa464Sguenther * TLS data alignment TIB's alignment. 295f54aa464Sguenther * Example A: p_memsz=24 p_align=16 align(TIB)=8 296f54aa464Sguenther * - need to allocate 32 bytes for TLS as compiler 297f54aa464Sguenther * - will give the first TLS symbol an offset of -32 298f54aa464Sguenther * Example B: p_memsz=4 p_align=4 align(TIB)=8 299f54aa464Sguenther * - need to allocate 8 bytes so that the TIB is 300f54aa464Sguenther * - properly aligned 301fe38b55cSguenther */ 302fe38b55cSguenther _static_tls_size = ELF_ROUND(phdr[i].p_memsz, 303fe38b55cSguenther phdr[i].p_align); 304f54aa464Sguenther _static_tls_align_offset = ELF_ROUND(_static_tls_size, 305f54aa464Sguenther _static_tls_align) - _static_tls_size; 306fe38b55cSguenther #endif 307fe38b55cSguenther if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) { 308f54aa464Sguenther static_tls = (void *)phdr[i].p_vaddr + 309f54aa464Sguenther _static_phdr_info.dlpi_addr; 310fe38b55cSguenther static_tls_fsize = phdr[i].p_filesz; 311fe38b55cSguenther } 312fe38b55cSguenther break; 313fe38b55cSguenther } 314fe38b55cSguenther } 315fe38b55cSguenther 316f54aa464Sguenther base = mmap(NULL, _static_tls_size + _static_tls_align_offset 317f54aa464Sguenther + sizeof *tib, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); 318fe38b55cSguenther 319f54aa464Sguenther tib = _static_tls_init(base, NULL); 320fe38b55cSguenther tib->tib_tid = getthrid(); 321fe38b55cSguenther TCB_SET(TIB_TO_TCB(tib)); 322fe38b55cSguenther #if ! TCB_HAVE_MD_GET 323fe38b55cSguenther _libc_single_tcb = TIB_TO_TCB(tib); 324fe38b55cSguenther #endif 325fe38b55cSguenther } 326fe38b55cSguenther 327f54aa464Sguenther struct tib * 328f54aa464Sguenther _static_tls_init(char *base, void *thread) 329fe38b55cSguenther { 330f54aa464Sguenther struct tib *tib; 331f54aa464Sguenther 332f54aa464Sguenther base += _static_tls_align_offset; 333fe38b55cSguenther # if TLS_VARIANT == 1 334f54aa464Sguenther tib = (struct tib *)base; 335fe38b55cSguenther base += sizeof(struct tib); 336f54aa464Sguenther # elif TLS_VARIANT == 2 337f54aa464Sguenther tib = (struct tib *)(base + _static_tls_size); 338fe38b55cSguenther # endif 339f54aa464Sguenther 340f54aa464Sguenther if (_static_tls_size) { 341fe38b55cSguenther if (static_tls != NULL) 342fe38b55cSguenther memcpy(base, static_tls, static_tls_fsize); 343fe38b55cSguenther memset(base + static_tls_fsize, 0, 344fe38b55cSguenther _static_tls_size - static_tls_fsize); 345fe38b55cSguenther } 346f54aa464Sguenther 347f54aa464Sguenther TIB_INIT(tib, NULL, thread); 348f54aa464Sguenther return tib; 349fe38b55cSguenther } 3505af055cdSguenther #endif /* !PIC */ 351