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