Bug Summary

File:src/libexec/ld.so/loader.c
Warning:line 608, column 21
Access to field 'load_list' results in a dereference of a null pointer (loaded from variable 'exe_obj')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name loader.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/libexec/ld.so/obj -resource-dir /usr/local/llvm16/lib/clang/16 -D DO_CLEAN_BOOT -I /usr/src/libexec/ld.so -I /usr/src/libexec/ld.so/amd64 -D DEF_WEAK(x)=asm("") -D DEF_STRONG(x)=asm("") -D strsep=_dl_strsep -D strlcat=_dl_strlcat -D strlen=_dl_strlen -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/libexec/ld.so/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fno-builtin -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/libexec/ld.so/loader.c
1/* $OpenBSD: loader.c,v 1.218 2023/12/19 16:13:22 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#define _DYN_LOADER
30
31#include <sys/types.h>
32#include <sys/mman.h>
33#include <sys/syscall.h>
34#include <sys/exec.h>
35#ifdef __i386__
36# include <machine/vmparam.h>
37#endif
38#include <string.h>
39#include <link.h>
40#include <limits.h> /* NAME_MAX */
41#include <dlfcn.h>
42#include <tib.h>
43
44#include "syscall.h"
45#include "util.h"
46#include "resolve.h"
47#include "path.h"
48#include "sod.h"
49
50/*
51 * Local decls.
52 */
53unsigned long _dl_boot(const char **, char **, const long, long *) __boot__attribute__((section(".boot.text")));
54void _dl_debug_state(void);
55void _dl_setup_env(const char *_argv0, char **_envp) __boot__attribute__((section(".boot.text")));
56void _dl_dtors(void);
57void _dl_dopreload(char *_paths) __boot__attribute__((section(".boot.text")));
58void _dl_fixup_user_env(void) __boot__attribute__((section(".boot.text")));
59void _dl_call_preinit(elf_object_t *) __boot__attribute__((section(".boot.text")));
60void _dl_call_init_recurse(elf_object_t *object, int initfirst);
61void _dl_clean_boot(void);
62static inline void unprotect_if_textrel(elf_object_t *_object);
63static inline void reprotect_if_textrel(elf_object_t *_object);
64static void _dl_rreloc(elf_object_t *_object);
65
66int _dl_pagesz __relro__attribute__((section(".data.rel.ro"))) = 4096;
67int _dl_bindnow __relro__attribute__((section(".data.rel.ro"))) = 0;
68int _dl_debug __relro__attribute__((section(".data.rel.ro"))) = 0;
69int _dl_trust __relro__attribute__((section(".data.rel.ro"))) = 0;
70char **_dl_libpath __relro__attribute__((section(".data.rel.ro"))) = NULL((void *)0);
71const char **_dl_argv __relro__attribute__((section(".data.rel.ro"))) = NULL((void *)0);
72int _dl_argc __relro__attribute__((section(".data.rel.ro"))) = 0;
73
74char *_dl_preload __boot_data__attribute__((section(".boot.data"))) = NULL((void *)0);
75char *_dl_tracefmt1 __boot_data__attribute__((section(".boot.data"))) = NULL((void *)0);
76char *_dl_tracefmt2 __boot_data__attribute__((section(".boot.data"))) = NULL((void *)0);
77char *_dl_traceprog __boot_data__attribute__((section(".boot.data"))) = NULL((void *)0);
78void *_dl_exec_hint __boot_data__attribute__((section(".boot.data"))) = NULL((void *)0);
79
80char **environ = NULL((void *)0);
81char *__progname = NULL((void *)0);
82
83int _dl_traceld;
84struct r_debug *_dl_debug_map;
85
86static dl_cb_cb _dl_cb_cb;
87const struct dl_cb_0 callbacks_0 = {
88 .dl_allocate_tib = &_dl_allocate_tib,
89 .dl_free_tib = &_dl_free_tib,
90#if DO_CLEAN_BOOT1
91 .dl_clean_boot = &_dl_clean_boot,
92#endif
93 .dlopen = &dlopen,
94 .dlclose = &dlclose,
95 .dlsym = &dlsym,
96 .dladdr = &dladdr,
97 .dlctl = &dlctl,
98 .dlerror = &dlerror,
99 .dl_iterate_phdr = &dl_iterate_phdr,
100};
101
102
103/*
104 * Run dtors for a single object.
105 */
106void
107_dl_run_dtors(elf_object_t *obj)
108{
109 if (obj->dynDyn.u.fini_array) {
110 int num = obj->dynDyn.u.fini_arraysz / sizeof(Elf_AddrElf64_Addr);
111 int i;
112
113 DL_DEB(("doing finiarray obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing finiarray obj %p @%p: [%s]\n"
, obj, obj->Dyn.u.fini_array, obj->load_name) ; } while
(0)
114 obj, obj->dyn.fini_array, obj->load_name))do { if (_dl_debug) _dl_printf ("doing finiarray obj %p @%p: [%s]\n"
, obj, obj->Dyn.u.fini_array, obj->load_name) ; } while
(0)
;
115 for (i = num; i > 0; i--)
116 (*obj->dynDyn.u.fini_array[i-1])();
117 }
118
119 if (obj->dynDyn.u.fini) {
120 DL_DEB(("doing dtors obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing dtors obj %p @%p: [%s]\n"
, obj, obj->Dyn.u.fini, obj->load_name) ; } while (0)
121 obj, obj->dyn.fini, obj->load_name))do { if (_dl_debug) _dl_printf ("doing dtors obj %p @%p: [%s]\n"
, obj, obj->Dyn.u.fini, obj->load_name) ; } while (0)
;
122 (*obj->dynDyn.u.fini)();
123 }
124}
125
126/*
127 * Run dtors for all objects that are eligible.
128 */
129void
130_dl_run_all_dtors(void)
131{
132 elf_object_t *node;
133 int fini_complete;
134 int skip_initfirst;
135 int initfirst_skipped;
136
137 fini_complete = 0;
138 skip_initfirst = 1;
139 initfirst_skipped = 0;
140
141 while (fini_complete == 0) {
142 fini_complete = 1;
143 for (node = _dl_objects;
144 node != NULL((void *)0);
145 node = node->next) {
146 if ((node->dynDyn.u.fini || node->dynDyn.u.fini_array) &&
147 (OBJECT_REF_CNT(node)((node->refcount + node->opencount + node->grprefcount
))
== 0) &&
148 (node->status & STAT_INIT_DONE0x004) &&
149 ((node->status & STAT_FINI_DONE0x008) == 0)) {
150 if (skip_initfirst &&
151 (node->obj_flags & DF_1_INITFIRST0x00000020))
152 initfirst_skipped = 1;
153 else
154 node->status |= STAT_FINI_READY0x010;
155 }
156 }
157 for (node = _dl_objects;
158 node != NULL((void *)0);
159 node = node->next ) {
160 if ((node->dynDyn.u.fini || node->dynDyn.u.fini_array) &&
161 (OBJECT_REF_CNT(node)((node->refcount + node->opencount + node->grprefcount
))
== 0) &&
162 (node->status & STAT_INIT_DONE0x004) &&
163 ((node->status & STAT_FINI_DONE0x008) == 0) &&
164 (!skip_initfirst ||
165 (node->obj_flags & DF_1_INITFIRST0x00000020) == 0)) {
166 struct object_vector vec = node->child_vec;
167 int i;
168
169 for (i = 0; i < vec.len; i++)
170 vec.vec[i]->status &= ~STAT_FINI_READY0x010;
171 }
172 }
173
174 for (node = _dl_objects;
175 node != NULL((void *)0);
176 node = node->next ) {
177 if (node->status & STAT_FINI_READY0x010) {
178 fini_complete = 0;
179 node->status |= STAT_FINI_DONE0x008;
180 node->status &= ~STAT_FINI_READY0x010;
181 _dl_run_dtors(node);
182 }
183 }
184
185 if (fini_complete && initfirst_skipped)
186 fini_complete = initfirst_skipped = skip_initfirst = 0;
187 }
188}
189
190/*
191 * Routine to walk through all of the objects except the first
192 * (main executable).
193 *
194 * Big question, should dlopen()ed objects be unloaded before or after
195 * the destructor for the main application runs?
196 */
197void
198_dl_dtors(void)
199{
200 _dl_thread_kern_stop();
201
202 /* ORDER? */
203 _dl_unload_dlopen();
204
205 DL_DEB(("doing dtors\n"))do { if (_dl_debug) _dl_printf ("doing dtors\n") ; } while (0
)
;
206
207 _dl_objects->opencount--;
208 _dl_notify_unload_shlib(_dl_objects);
209
210 _dl_run_all_dtors();
211}
212
213#if DO_CLEAN_BOOT1
214void
215_dl_clean_boot(void)
216{
217 extern char boot_text_start[], boot_text_end[];
218#if 0 /* XXX breaks boehm-gc?!? */
219 extern char boot_data_start[], boot_data_end[];
220#endif
221
222 _dl_mmap(boot_text_start, boot_text_end - boot_text_start,
223 PROT_NONE0x00, MAP_FIXED0x0010 | MAP_PRIVATE0x0002 | MAP_ANON0x1000, -1, 0);
224 _dl_mimmutable(boot_text_start, boot_text_end - boot_text_start);
225#if 0 /* XXX breaks boehm-gc?!? */
226 _dl_mmap(boot_data_start, boot_data_end - boot_data_start,
227 PROT_NONE0x00, MAP_FIXED0x0010 | MAP_PRIVATE0x0002 | MAP_ANON0x1000, -1, 0);
228 _dl_mimmutable(boot_data_start, boot_data_end - boot_data_start);
229#endif
230}
231#endif /* DO_CLEAN_BOOT */
232
233void
234_dl_dopreload(char *paths)
235{
236 char *cp, *dp;
237 elf_object_t *shlib;
238 int count;
239
240 dp = paths = _dl_strdup(paths);
241 if (dp == NULL((void *)0))
242 _dl_oom();
243
244 /* preallocate child_vec for the LD_PRELOAD objects */
245 count = 1;
246 while (*dp++ != '\0')
247 if (*dp == ':')
248 count++;
249 object_vec_grow(&_dl_objects->child_vec, count);
250
251 dp = paths;
252 while ((cp = _dl_strsep(&dp, ":")) != NULL((void *)0)) {
253 shlib = _dl_load_shlib(cp, _dl_objects, OBJTYPE_LIB3,
254 _dl_objects->obj_flags, 1);
255 if (shlib == NULL((void *)0))
256 _dl_die("can't preload library '%s'", cp);
257 _dl_add_object(shlib);
258 _dl_link_child(shlib, _dl_objects);
259 }
260 _dl_free(paths);
261 return;
262}
263
264/*
265 * grab interesting environment variables, zap bad env vars if
266 * issetugid, and set the exported environ and __progname variables
267 */
268void
269_dl_setup_env(const char *argv0, char **envp)
270{
271 static char progname_storage[NAME_MAX255+1] = "";
272
273 /*
274 * Don't allow someone to change the search paths if he runs
275 * a suid program without credentials high enough.
276 */
277 _dl_trust = !_dl_issetugid();
278 if (!_dl_trust) { /* Zap paths if s[ug]id... */
279 _dl_unsetenv("LD_DEBUG", envp);
280 _dl_unsetenv("LD_LIBRARY_PATH", envp);
281 _dl_unsetenv("LD_PRELOAD", envp);
282 _dl_unsetenv("LD_BIND_NOW", envp);
283 } else {
284 /*
285 * Get paths to various things we are going to use.
286 */
287 _dl_debug = _dl_getenv("LD_DEBUG", envp) != NULL((void *)0);
288 _dl_libpath = _dl_split_path(_dl_getenv("LD_LIBRARY_PATH",
289 envp));
290 _dl_preload = _dl_getenv("LD_PRELOAD", envp);
291 _dl_bindnow = _dl_getenv("LD_BIND_NOW", envp) != NULL((void *)0);
292 }
293
294 /* these are usable even in setugid processes */
295 _dl_traceld = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp) != NULL((void *)0);
296 _dl_tracefmt1 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT1", envp);
297 _dl_tracefmt2 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT2", envp);
298 _dl_traceprog = _dl_getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", envp);
299
300 environ = envp;
301
302 _dl_trace_setup(envp);
303
304 if (argv0 != NULL((void *)0)) { /* NULL ptr if argc = 0 */
305 const char *p = _dl_strrchr(argv0, '/');
306
307 if (p == NULL((void *)0))
308 p = argv0;
309 else
310 p++;
311 _dl_strlcpy(progname_storage, p, sizeof(progname_storage));
312 }
313 __progname = progname_storage;
314}
315
316int
317_dl_load_dep_libs(elf_object_t *object, int flags, int booting)
318{
319 elf_object_t *dynobj, *obj;
320 Elf_DynElf64_Dyn *dynp;
321 unsigned int loop;
322 int libcount;
323 int depflags, nodelete = 0;
324
325 dynobj = object;
326 while (dynobj) {
327 DL_DEB(("examining: '%s'\n", dynobj->load_name))do { if (_dl_debug) _dl_printf ("examining: '%s'\n", dynobj->
load_name) ; } while (0)
;
328 libcount = 0;
329
330 /* propagate DF_1_NOW to deplibs (can be set by dynamic tags) */
331 depflags = flags | (dynobj->obj_flags & DF_1_NOW0x00000001);
332 if (booting || object->nodelete)
333 nodelete = 1;
334
335 for (dynp = dynobj->load_dyn; dynp->d_tag; dynp++) {
336 if (dynp->d_tag == DT_NEEDED1) {
337 libcount++;
338 }
339 }
340
341 if ( libcount != 0) {
342 struct listent {
343 Elf_DynElf64_Dyn *dynp;
344 elf_object_t *depobj;
345 } *liblist;
346 int *randomlist;
347
348 liblist = _dl_reallocarray(NULL((void *)0), libcount,
349 sizeof(struct listent));
350 randomlist = _dl_reallocarray(NULL((void *)0), libcount,
351 sizeof(int));
352
353 if (liblist == NULL((void *)0) || randomlist == NULL((void *)0))
354 _dl_oom();
355
356 for (dynp = dynobj->load_dyn, loop = 0; dynp->d_tag;
357 dynp++)
358 if (dynp->d_tag == DT_NEEDED1)
359 liblist[loop++].dynp = dynp;
360
361 /* Randomize these */
362 for (loop = 0; loop < libcount; loop++)
363 randomlist[loop] = loop;
364
365 for (loop = 1; loop < libcount; loop++) {
366 unsigned int rnd;
367 int cur;
368 rnd = _dl_arc4random();
369 rnd = rnd % (loop+1);
370 cur = randomlist[rnd];
371 randomlist[rnd] = randomlist[loop];
372 randomlist[loop] = cur;
373 }
374
375 for (loop = 0; loop < libcount; loop++) {
376 elf_object_t *depobj;
377 const char *libname;
378 libname = dynobj->dynDyn.u.strtab;
379 libname +=
380 liblist[randomlist[loop]].dynp->d_un.d_val;
381 DL_DEB(("loading: %s required by %s\n", libname,do { if (_dl_debug) _dl_printf ("loading: %s required by %s\n"
, libname, dynobj->load_name) ; } while (0)
382 dynobj->load_name))do { if (_dl_debug) _dl_printf ("loading: %s required by %s\n"
, libname, dynobj->load_name) ; } while (0)
;
383 depobj = _dl_load_shlib(libname, dynobj,
384 OBJTYPE_LIB3, depflags, nodelete);
385 if (depobj == 0) {
386 if (booting) {
387 _dl_die(
388 "can't load library '%s'",
389 libname);
390 }
391 DL_DEB(("dlopen: failed to open %s\n",do { if (_dl_debug) _dl_printf ("dlopen: failed to open %s\n"
, libname) ; } while (0)
392 libname))do { if (_dl_debug) _dl_printf ("dlopen: failed to open %s\n"
, libname) ; } while (0)
;
393 _dl_free(liblist);
394 _dl_free(randomlist);
395 return (1);
396 }
397 liblist[randomlist[loop]].depobj = depobj;
398 }
399
400 object_vec_grow(&dynobj->child_vec, libcount);
401 for (loop = 0; loop < libcount; loop++) {
402 _dl_add_object(liblist[loop].depobj);
403 _dl_link_child(liblist[loop].depobj, dynobj);
404 }
405 _dl_free(liblist);
406 _dl_free(randomlist);
407 }
408 dynobj = dynobj->next;
409 }
410
411 _dl_cache_grpsym_list_setup(object);
412
413 for (obj = _dl_objects; booting && obj != NULL((void *)0); obj = obj->next) {
414 char *soname = (char *)obj->Dyn.info[DT_SONAME14];
415 struct sym_res sr;
416
417 if (!soname || _dl_strncmp(soname, "libc.so.", 8))
418 continue;
419 sr = _dl_find_symbol("execve",
420 SYM_SEARCH_SELF0x01|SYM_PLT0x20|SYM_WARNNOTFOUND0x10, NULL((void *)0), obj);
421 if (sr.sym)
422 _dl_pinsyscall(SYS_execve59,
423 (void *)sr.obj->obj_base + sr.sym->st_value,
424 sr.sym->st_size);
425 _dl_memset(&sr, 0, sizeof sr);
426 break;
427 }
428 return(0);
429}
430
431
432/* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */
433static inline void
434_dl_self_relro(long loff)
435{
436 Elf_EhdrElf64_Ehdr *ehdp;
437 Elf_PhdrElf64_Phdr *phdp;
438 int i;
439
440 ehdp = (Elf_EhdrElf64_Ehdr *)loff;
441 phdp = (Elf_PhdrElf64_Phdr *)(loff + ehdp->e_phoff);
442 for (i = 0; i < ehdp->e_phnum; i++, phdp++) {
443 switch (phdp->p_type) {
444#if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \
445 defined(__sparc64__)
446 case PT_LOAD1:
447 if ((phdp->p_flags & (PF_X0x1 | PF_W0x2)) != (PF_X0x1 | PF_W0x2))
448 break;
449 _dl_mprotect((void *)(phdp->p_vaddr + loff),
450 phdp->p_memsz, PROT_READ0x01);
451 break;
452#endif
453 case PT_GNU_RELRO0x6474e552:
454 _dl_mprotect((void *)(phdp->p_vaddr + loff),
455 phdp->p_memsz, PROT_READ0x01);
456 _dl_mimmutable((void *)(phdp->p_vaddr + loff),
457 phdp->p_memsz);
458 break;
459 }
460 }
461}
462
463
464#define PFLAGS(X)((((X) & 0x4) ? 0x01 : 0) | (((X) & 0x2) ? 0x02 : 0) |
(((X) & 0x1) ? 0x04 : 0))
((((X) & PF_R0x4) ? PROT_READ0x01 : 0) | \
465 (((X) & PF_W0x2) ? PROT_WRITE0x02 : 0) | \
466 (((X) & PF_X0x1) ? PROT_EXEC0x04 : 0))
467
468/*
469 * To avoid kbind(2) becoming a powerful gadget, it is called inline to a
470 * function. Therefore we cannot create a precise pinsyscall label. Instead
471 * create a duplicate entry to force the kernel's pinsyscall code to skip
472 * validation, rather than labelling it illegal. kbind(2) remains safe
473 * because it self-protects by checking its calling address.
474 */
475#define __STRINGIFY(x)"x" #x
476#define STRINGIFY(x)"x" __STRINGIFY(x)"x"
477#ifdef __arm__
478__asm__(".pushsection .openbsd.syscalls,\"\",%progbits;"
479 ".p2align 2;"
480 ".long 0;"
481 ".long " STRINGIFY(SYS_kbind)"86" ";"
482 ".popsection");
483#else
484__asm__(".pushsection .openbsd.syscalls,\"\",@progbits;"
485 ".p2align 2;"
486 ".long 0;"
487 ".long " STRINGIFY(SYS_kbind)"86" ";"
488 ".popsection");
489#endif
490
491/*
492 * This is the dynamic loader entrypoint. When entering here, depending
493 * on architecture type, the stack and registers are set up according
494 * to the architectures ABI specification. The first thing required
495 * to do is to dig out all information we need to accomplish our task.
496 */
497unsigned long
498_dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
499{
500 struct elf_object *exe_obj; /* Pointer to executable object */
501 struct elf_object *dyn_obj; /* Pointer to ld.so object */
502 struct r_debug **map_link; /* Where to put pointer for gdb */
503 struct r_debug *debug_map;
504 struct load_list *next_load, *load_list = NULL((void *)0);
505 Elf_DynElf64_Dyn *dynp;
506 Elf_PhdrElf64_Phdr *phdp;
507 Elf_EhdrElf64_Ehdr *ehdr;
508 char *us = NULL((void *)0);
509 unsigned int loop;
510 int failed;
511 struct dep_node *n;
512 Elf_AddrElf64_Addr minva, maxva, exe_loff, exec_end, cur_exec_end;
513 Elf_AddrElf64_Addr relro_addr = 0, relro_size = 0;
514 Elf_PhdrElf64_Phdr *ptls = NULL((void *)0);
515 int align;
516
517 if (dl_data[AUX_pagesz] != 0)
1
Assuming the condition is false
2
Taking false branch
518 _dl_pagesz = dl_data[AUX_pagesz];
519 _dl_malloc_init();
520
521 _dl_argv = argv;
522 while (_dl_argv[_dl_argc] != NULL((void *)0))
3
Loop condition is false. Execution continues on line 524
523 _dl_argc++;
524 _dl_setup_env(argv[0], envp);
525
526 /*
527 * Make read-only the GOT and PLT and variables initialized
528 * during the ld.so setup above.
529 */
530 _dl_self_relro(dyn_loff);
531
532 align = _dl_pagesz - 1;
533
534#define ROUND_PG(x)(((x) + align) & ~(align)) (((x) + align) & ~(align))
535#define TRUNC_PG(x)((x) & ~(align)) ((x) & ~(align))
536
537 if (_dl_bindnow) {
4
Assuming '_dl_bindnow' is 0
5
Taking false branch
538 /* Lazy binding disabled, so disable kbind */
539 _dl_kbind(NULL((void *)0), 0, 0);
540 }
541
542 DL_DEB(("ld.so loading: '%s'\n", __progname))do { if (_dl_debug) _dl_printf ("ld.so loading: '%s'\n", __progname
) ; } while (0)
;
6
Assuming '_dl_debug' is 0
7
Taking false branch
8
Loop condition is false. Exiting loop
543
544 /* init this in runtime, not statically */
545 TAILQ_INIT(&_dlopened_child_list)do { (&_dlopened_child_list)->tqh_first = ((void *)0);
(&_dlopened_child_list)->tqh_last = &(&_dlopened_child_list
)->tqh_first; } while (0)
;
9
Loop condition is false. Exiting loop
546
547 exe_obj = NULL((void *)0);
10
Null pointer value stored to 'exe_obj'
548 _dl_loading_object = NULL((void *)0);
549
550 minva = ELF_NO_ADDR((__uint64_t) ~0);
551 maxva = exe_loff = exec_end = 0;
552
553 /*
554 * Examine the user application and set up object information.
555 */
556 phdp = (Elf_PhdrElf64_Phdr *)dl_data[AUX_phdr];
557 for (loop = 0; loop < dl_data[AUX_phnum]; loop++) {
11
Assuming the condition is false
12
Loop condition is false. Execution continues on line 608
558 switch (phdp->p_type) {
559 case PT_PHDR6:
560 exe_loff = (Elf_AddrElf64_Addr)dl_data[AUX_phdr] - phdp->p_vaddr;
561 us += exe_loff;
562 DL_DEB(("exe load offset: 0x%lx\n", exe_loff))do { if (_dl_debug) _dl_printf ("exe load offset: 0x%lx\n", exe_loff
) ; } while (0)
;
563 break;
564 case PT_DYNAMIC2:
565 minva = TRUNC_PG(minva)((minva) & ~(align));
566 maxva = ROUND_PG(maxva)(((maxva) + align) & ~(align));
567 exe_obj = _dl_finalize_object(argv[0] ? argv[0] : "",
568 (Elf_DynElf64_Dyn *)(phdp->p_vaddr + exe_loff),
569 (Elf_PhdrElf64_Phdr *)dl_data[AUX_phdr],
570 dl_data[AUX_phnum], OBJTYPE_EXE2, minva + exe_loff,
571 exe_loff);
572 _dl_add_object(exe_obj);
573 break;
574 case PT_INTERP3:
575 us += phdp->p_vaddr;
576 break;
577 case PT_LOAD1:
578 if (phdp->p_vaddr < minva)
579 minva = phdp->p_vaddr;
580 if (phdp->p_vaddr > maxva)
581 maxva = phdp->p_vaddr + phdp->p_memsz;
582
583 next_load = _dl_calloc(1, sizeof(struct load_list));
584 if (next_load == NULL((void *)0))
585 _dl_oom();
586 next_load->next = load_list;
587 load_list = next_load;
588 next_load->start = (char *)TRUNC_PG(phdp->p_vaddr)((phdp->p_vaddr) & ~(align)) + exe_loff;
589 next_load->size = (phdp->p_vaddr & align) + phdp->p_filesz;
590 next_load->prot = PFLAGS(phdp->p_flags)((((phdp->p_flags) & 0x4) ? 0x01 : 0) | (((phdp->p_flags
) & 0x2) ? 0x02 : 0) | (((phdp->p_flags) & 0x1) ? 0x04
: 0))
;
591 cur_exec_end = (Elf_AddrElf64_Addr)next_load->start + next_load->size;
592 if ((next_load->prot & PROT_EXEC0x04) != 0 &&
593 cur_exec_end > exec_end)
594 exec_end = cur_exec_end;
595 break;
596 case PT_TLS7:
597 if (phdp->p_filesz > phdp->p_memsz)
598 _dl_die("invalid tls data");
599 ptls = phdp;
600 break;
601 case PT_GNU_RELRO0x6474e552:
602 relro_addr = phdp->p_vaddr + exe_loff;
603 relro_size = phdp->p_memsz;
604 break;
605 }
606 phdp++;
607 }
608 exe_obj->load_list = load_list;
13
Access to field 'load_list' results in a dereference of a null pointer (loaded from variable 'exe_obj')
609 exe_obj->obj_flags |= DF_1_GLOBAL0x00000002;
610 exe_obj->nodelete = 1;
611 exe_obj->load_size = maxva - minva;
612 exe_obj->relro_addr = relro_addr;
613 exe_obj->relro_size = relro_size;
614 _dl_set_sod(exe_obj->load_name, &exe_obj->sod);
615
616#ifdef __i386__
617 if (exec_end > I386_MAX_EXE_ADDR)
618 _dl_exec_hint = (void *)ROUND_PG(exec_end-I386_MAX_EXE_ADDR)(((exec_end-I386_MAX_EXE_ADDR) + align) & ~(align));
619 DL_DEB(("_dl_exec_hint: 0x%lx\n", _dl_exec_hint))do { if (_dl_debug) _dl_printf ("_dl_exec_hint: 0x%lx\n", _dl_exec_hint
) ; } while (0)
;
620#endif
621
622 /* TLS bits in the base executable */
623 if (ptls != NULL((void *)0) && ptls->p_memsz)
624 _dl_set_tls(exe_obj, ptls, exe_loff, NULL((void *)0));
625
626 n = _dl_malloc(sizeof *n);
627 if (n == NULL((void *)0))
628 _dl_oom();
629 n->data = exe_obj;
630 TAILQ_INSERT_TAIL(&_dlopened_child_list, n, next_sib)do { (n)->next_sib.tqe_next = ((void *)0); (n)->next_sib
.tqe_prev = (&_dlopened_child_list)->tqh_last; *(&
_dlopened_child_list)->tqh_last = (n); (&_dlopened_child_list
)->tqh_last = &(n)->next_sib.tqe_next; } while (0)
;
631 exe_obj->opencount++;
632
633 if (_dl_preload != NULL((void *)0))
634 _dl_dopreload(_dl_preload);
635
636 _dl_load_dep_libs(exe_obj, exe_obj->obj_flags, 1);
637
638 /*
639 * Now add the dynamic loader itself last in the object list
640 * so we can use the _dl_ code when serving dl.... calls.
641 * Intentionally left off the exe child_vec.
642 */
643 dynp = (Elf_DynElf64_Dyn *)((void *)_DYNAMIC);
644 ehdr = (Elf_EhdrElf64_Ehdr *)dl_data[AUX_base];
645 dyn_obj = _dl_finalize_object(us, dynp,
646 (Elf_PhdrElf64_Phdr *)((char *)dl_data[AUX_base] + ehdr->e_phoff),
647 ehdr->e_phnum, OBJTYPE_LDR1, dl_data[AUX_base], dyn_loff);
648 _dl_add_object(dyn_obj);
649
650 dyn_obj->refcount++;
651 _dl_link_grpsym(dyn_obj);
652
653 dyn_obj->status |= STAT_RELOC_DONE0x001;
654 _dl_set_sod(dyn_obj->load_name, &dyn_obj->sod);
655
656 /* calculate the offsets for static TLS allocations */
657 _dl_allocate_tls_offsets();
658
659 /*
660 * Make something to help gdb when poking around in the code.
661 * Do this poking at the .dynamic section now, before relocation
662 * renders it read-only
663 */
664 map_link = NULL((void *)0);
665#ifdef __mips__
666 for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) {
667 if (dynp->d_tag == DT_MIPS_RLD_MAP_REL) {
668 map_link = (struct r_debug **)
669 (dynp->d_un.d_ptr + (Elf_AddrElf64_Addr)dynp);
670 break;
671 } else if (dynp->d_tag == DT_MIPS_RLD_MAP) {
672 map_link = (struct r_debug **)
673 (dynp->d_un.d_ptr + exe_loff);
674 break;
675 }
676 }
677#endif
678 if (map_link == NULL((void *)0)) {
679 for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) {
680 if (dynp->d_tag == DT_DEBUG21) {
681 map_link = (struct r_debug **)&dynp->d_un.d_ptr;
682 break;
683 }
684 }
685 if (dynp->d_tag != DT_DEBUG21)
686 DL_DEB(("failed to mark DTDEBUG\n"))do { if (_dl_debug) _dl_printf ("failed to mark DTDEBUG\n") ;
} while (0)
;
687 }
688 if (map_link) {
689 debug_map = _dl_malloc(sizeof(*debug_map));
690 if (debug_map == NULL((void *)0))
691 _dl_oom();
692 debug_map->r_version = 1;
693 debug_map->r_map = (struct link_map *)_dl_objects;
694 debug_map->r_brk = (Elf_AddrElf64_Addr)_dl_debug_state;
695 debug_map->r_state = RT_CONSISTENT;
696 debug_map->r_ldbase = dyn_loff;
697 _dl_debug_map = debug_map;
698#ifdef __mips__
699 relro_addr = exe_obj->relro_addr;
700 if (dynp->d_tag == DT_DEBUG21 &&
701 ((Elf_AddrElf64_Addr)map_link + sizeof(*map_link) <= relro_addr ||
702 (Elf_AddrElf64_Addr)map_link >= relro_addr + exe_obj->relro_size)) {
703 _dl_mprotect(map_link, sizeof(*map_link),
704 PROT_READ0x01|PROT_WRITE0x02);
705 *map_link = _dl_debug_map;
706 _dl_mprotect(map_link, sizeof(*map_link),
707 PROT_READ0x01|PROT_EXEC0x04);
708 } else
709#endif
710 *map_link = _dl_debug_map;
711 }
712
713
714 /*
715 * Everything should be in place now for doing the relocation
716 * and binding. Call _dl_rtld to do the job. Fingers crossed.
717 */
718
719 failed = 0;
720 if (!_dl_traceld)
721 failed = _dl_rtld(_dl_objects);
722
723 if (_dl_debug || _dl_traceld) {
724 if (_dl_traceld)
725 _dl_pledge("stdio rpath", NULL((void *)0));
726 _dl_show_objects(NULL((void *)0));
727 }
728
729 DL_DEB(("dynamic loading done, %s.\n",do { if (_dl_debug) _dl_printf ("dynamic loading done, %s.\n"
, (failed == 0) ? "success":"failed") ; } while (0)
730 (failed == 0) ? "success":"failed"))do { if (_dl_debug) _dl_printf ("dynamic loading done, %s.\n"
, (failed == 0) ? "success":"failed") ; } while (0)
;
731
732 if (failed != 0)
733 _dl_die("relocation failed");
734
735 if (_dl_traceld)
736 _dl_exit(0);
737
738 _dl_loading_object = NULL((void *)0);
739
740 /* set up the TIB for the initial thread */
741 _dl_allocate_first_tib();
742
743 _dl_fixup_user_env();
744
745 _dl_debug_state();
746
747 /*
748 * Do not run init code if run from ldd.
749 */
750 if (_dl_objects->next != NULL((void *)0)) {
751 _dl_call_preinit(_dl_objects);
752 _dl_call_init(_dl_objects);
753 }
754
755 DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry]))do { if (_dl_debug) _dl_printf ("entry point: 0x%lx\n", dl_data
[AUX_entry]) ; } while (0)
;
756
757 /*
758 * Return the entry point.
759 */
760 return(dl_data[AUX_entry]);
761}
762
763int
764_dl_rtld(elf_object_t *object)
765{
766 struct load_list *llist;
767 int fails = 0;
768
769 if (object->next)
770 fails += _dl_rtld(object->next);
771
772 if (object->status & STAT_RELOC_DONE0x001)
773 return 0;
774
775 /*
776 * Do relocation information first, then GOT.
777 */
778 unprotect_if_textrel(object);
779 _dl_rreloc(object);
780 fails =_dl_md_reloc(object, DT_REL17, DT_RELSZ18);
781 fails += _dl_md_reloc(object, DT_RELA7, DT_RELASZ8);
782 reprotect_if_textrel(object);
783
784 /*
785 * We do lazy resolution by default, doing eager resolution if
786 * - the object requests it with -znow, OR
787 * - LD_BIND_NOW is set and this object isn't being ltraced
788 *
789 * Note that -znow disables ltrace for the object: on at least
790 * amd64 'ld' doesn't generate the trampoline for lazy relocation
791 * when -znow is used.
792 */
793 fails += _dl_md_reloc_got(object, !(object->obj_flags & DF_1_NOW0x00000001) &&
794 !(_dl_bindnow && !object->traced));
795
796 /*
797 * Look for W&X segments and make them read-only.
798 */
799 for (llist = object->load_list; llist != NULL((void *)0); llist = llist->next) {
800 if ((llist->prot & PROT_WRITE0x02) && (llist->prot & PROT_EXEC0x04)) {
801 _dl_mprotect(llist->start, llist->size,
802 llist->prot & ~PROT_WRITE0x02);
803 }
804 }
805
806 /*
807 * TEXTREL binaries are loaded without immutable on un-writeable sections.
808 * After text relocations are finished, these regions can become
809 * immutable. OPENBSD_MUTABLE section always overlaps writeable LOADs,
810 * so don't be afraid.
811 */
812 if (object->dynDyn.u.textrel) {
813 for (llist = object->load_list; llist != NULL((void *)0); llist = llist->next)
814 if ((llist->prot & PROT_WRITE0x02) == 0)
815 _dl_mimmutable(llist->start, llist->size);
816 }
817
818 if (fails == 0)
819 object->status |= STAT_RELOC_DONE0x001;
820
821 return (fails);
822}
823
824void
825_dl_call_preinit(elf_object_t *object)
826{
827 if (object->dynDyn.u.preinit_array) {
828 int num = object->dynDyn.u.preinit_arraysz / sizeof(Elf_AddrElf64_Addr);
829 int i;
830
831 DL_DEB(("doing preinitarray obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing preinitarray obj %p @%p: [%s]\n"
, object, object->Dyn.u.preinit_array, object->load_name
) ; } while (0)
832 object, object->dyn.preinit_array, object->load_name))do { if (_dl_debug) _dl_printf ("doing preinitarray obj %p @%p: [%s]\n"
, object, object->Dyn.u.preinit_array, object->load_name
) ; } while (0)
;
833 for (i = 0; i < num; i++)
834 (*object->dynDyn.u.preinit_array[i])(_dl_argc, _dl_argv,
835 environ, &_dl_cb_cb);
836 }
837}
838
839void
840_dl_call_init(elf_object_t *object)
841{
842 _dl_call_init_recurse(object, 1);
843 _dl_call_init_recurse(object, 0);
844}
845
846static void
847_dl_relro(elf_object_t *object)
848{
849 /*
850 * Handle GNU_RELRO
851 */
852 if (object->relro_addr != 0 && object->relro_size != 0) {
853 Elf_AddrElf64_Addr addr = object->relro_addr;
854
855 DL_DEB(("protect RELRO [0x%lx,0x%lx) in %s\n",do { if (_dl_debug) _dl_printf ("protect RELRO [0x%lx,0x%lx) in %s\n"
, addr, addr + object->relro_size, object->load_name) ;
} while (0)
856 addr, addr + object->relro_size, object->load_name))do { if (_dl_debug) _dl_printf ("protect RELRO [0x%lx,0x%lx) in %s\n"
, addr, addr + object->relro_size, object->load_name) ;
} while (0)
;
857 _dl_mprotect((void *)addr, object->relro_size, PROT_READ0x01);
858
859 /* if library will never be unloaded, RELRO can be immutable */
860 if (object->nodelete)
861 _dl_mimmutable((void *)addr, object->relro_size);
862 }
863}
864
865void
866_dl_call_init_recurse(elf_object_t *object, int initfirst)
867{
868 struct object_vector vec;
869 int visited_flag = initfirst ? STAT_VISIT_INITFIRST0x100 : STAT_VISIT_INIT0x200;
870 int i;
871
872 object->status |= visited_flag;
873
874 for (vec = object->child_vec, i = 0; i < vec.len; i++) {
875 if (vec.vec[i]->status & visited_flag)
876 continue;
877 _dl_call_init_recurse(vec.vec[i], initfirst);
878 }
879
880 if (object->status & STAT_INIT_DONE0x004)
881 return;
882
883 if (initfirst && (object->obj_flags & DF_1_INITFIRST0x00000020) == 0)
884 return;
885
886 if (!initfirst) {
887 _dl_relro(object);
888 _dl_apply_immutable(object);
889 }
890
891 if (object->dynDyn.u.init) {
892 DL_DEB(("doing ctors obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing ctors obj %p @%p: [%s]\n"
, object, object->Dyn.u.init, object->load_name) ; } while
(0)
893 object, object->dyn.init, object->load_name))do { if (_dl_debug) _dl_printf ("doing ctors obj %p @%p: [%s]\n"
, object, object->Dyn.u.init, object->load_name) ; } while
(0)
;
894 (*object->dynDyn.u.init)();
895 }
896
897 if (object->dynDyn.u.init_array) {
898 int num = object->dynDyn.u.init_arraysz / sizeof(Elf_AddrElf64_Addr);
899 int i;
900
901 DL_DEB(("doing initarray obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing initarray obj %p @%p: [%s]\n"
, object, object->Dyn.u.init_array, object->load_name) ;
} while (0)
902 object, object->dyn.init_array, object->load_name))do { if (_dl_debug) _dl_printf ("doing initarray obj %p @%p: [%s]\n"
, object, object->Dyn.u.init_array, object->load_name) ;
} while (0)
;
903 for (i = 0; i < num; i++)
904 (*object->dynDyn.u.init_array[i])(_dl_argc, _dl_argv,
905 environ, &_dl_cb_cb);
906 }
907
908 if (initfirst) {
909 _dl_relro(object);
910 _dl_apply_immutable(object);
911 }
912
913 object->status |= STAT_INIT_DONE0x004;
914}
915
916char *
917_dl_getenv(const char *var, char **env)
918{
919 const char *ep;
920
921 while ((ep = *env++)) {
922 const char *vp = var;
923
924 while (*vp && *vp == *ep) {
925 vp++;
926 ep++;
927 }
928 if (*vp == '\0' && *ep++ == '=')
929 return((char *)ep);
930 }
931 return(NULL((void *)0));
932}
933
934void
935_dl_unsetenv(const char *var, char **env)
936{
937 char *ep;
938
939 while ((ep = *env)) {
940 const char *vp = var;
941
942 while (*vp && *vp == *ep) {
943 vp++;
944 ep++;
945 }
946 if (*vp == '\0' && *ep++ == '=') {
947 char **P;
948
949 for (P = env;; ++P)
950 if (!(*P = *(P + 1)))
951 break;
952 } else
953 env++;
954 }
955}
956
957static inline void
958fixup_sym(struct elf_object *dummy_obj, const char *name, void *addr)
959{
960 struct sym_res sr;
961
962 sr = _dl_find_symbol(name, SYM_SEARCH_ALL0x00|SYM_NOWARNNOTFOUND0x00|SYM_PLT0x20,
963 NULL((void *)0), dummy_obj);
964 if (sr.sym != NULL((void *)0)) {
965 void *p = (void *)(sr.sym->st_value + sr.obj->obj_base);
966 if (p != addr) {
967 DL_DEB(("setting %s %p@%s[%p] from %p\n", name,do { if (_dl_debug) _dl_printf ("setting %s %p@%s[%p] from %p\n"
, name, p, sr.obj->load_name, (void *)sr.obj, addr) ; } while
(0)
968 p, sr.obj->load_name, (void *)sr.obj, addr))do { if (_dl_debug) _dl_printf ("setting %s %p@%s[%p] from %p\n"
, name, p, sr.obj->load_name, (void *)sr.obj, addr) ; } while
(0)
;
969 *(void **)p = *(void **)addr;
970 }
971 }
972}
973
974/*
975 * _dl_fixup_user_env()
976 *
977 * Set the user environment so that programs can use the environment
978 * while running constructors. Specifically, MALLOC_OPTIONS= for malloc()
979 */
980void
981_dl_fixup_user_env(void)
982{
983 struct elf_object dummy_obj;
984
985 dummy_obj.dynDyn.u.symbolic = 0;
986 dummy_obj.load_name = "ld.so";
987 fixup_sym(&dummy_obj, "environ", &environ);
988 fixup_sym(&dummy_obj, "__progname", &__progname);
989}
990
991const void *
992_dl_cb_cb(int version)
993{
994 DL_DEB(("version %d callbacks requested\n", version))do { if (_dl_debug) _dl_printf ("version %d callbacks requested\n"
, version) ; } while (0)
;
995 if (version == 0)
996 return &callbacks_0;
997 return NULL((void *)0);
998}
999
1000static inline void
1001unprotect_if_textrel(elf_object_t *object)
1002{
1003 struct load_list *ll;
1004
1005 if (__predict_false(object->dyn.textrel == 1)__builtin_expect(((object->Dyn.u.textrel == 1) != 0), 0)) {
1006 for (ll = object->load_list; ll != NULL((void *)0); ll = ll->next) {
1007 if ((ll->prot & PROT_WRITE0x02) == 0)
1008 _dl_mprotect(ll->start, ll->size,
1009 PROT_READ0x01 | PROT_WRITE0x02);
1010 }
1011 }
1012}
1013
1014static inline void
1015reprotect_if_textrel(elf_object_t *object)
1016{
1017 struct load_list *ll;
1018
1019 if (__predict_false(object->dyn.textrel == 1)__builtin_expect(((object->Dyn.u.textrel == 1) != 0), 0)) {
1020 for (ll = object->load_list; ll != NULL((void *)0); ll = ll->next) {
1021 if ((ll->prot & PROT_WRITE0x02) == 0)
1022 _dl_mprotect(ll->start, ll->size, ll->prot);
1023 }
1024 }
1025}
1026
1027static void
1028_dl_rreloc(elf_object_t *object)
1029{
1030 const Elf_RelrElf64_Relr *reloc, *rend;
1031 Elf_AddrElf64_Addr loff = object->obj_base;
1032
1033 reloc = object->dynDyn.u.relr;
1034 rend = (const Elf_RelrElf64_Relr *)((char *)reloc + object->dynDyn.u.relrsz);
1035
1036 while (reloc < rend) {
1037 Elf_AddrElf64_Addr *where;
1038
1039 where = (Elf_AddrElf64_Addr *)(*reloc + loff);
1040 *where++ += loff;
1041
1042 for (reloc++; reloc < rend && (*reloc & 1); reloc++) {
1043 Elf_AddrElf64_Addr bits = *reloc >> 1;
1044
1045 Elf_AddrElf64_Addr *here = where;
1046 while (bits != 0) {
1047 if (bits & 1) {
1048 *here += loff;
1049 }
1050 bits >>= 1;
1051 here++;
1052 }
1053 where += (8 * sizeof *reloc) - 1;
1054 }
1055 }
1056}
1057
1058void
1059_dl_push_range(struct range_vector *v, vaddr_t s, vaddr_t e)
1060{
1061 int i = v->count;
1062
1063 if (i == nitems(v->slice)(sizeof((v->slice)) / sizeof((v->slice)[0]))) {
1064 _dl_die("too many ranges");
1065 }
1066 /* Skips the empty ranges (s == e). */
1067 if (s < e) {
1068 v->slice[i].start = s;
1069 v->slice[i].end = e;
1070 v->count++;
1071 } else if (s > e) {
1072 _dl_die("invalid range");
1073 }
1074}
1075
1076void
1077_dl_push_range_size(struct range_vector *v, vaddr_t s, vsize_t size)
1078{
1079 _dl_push_range(v, s, s + size);
1080}
1081
1082/*
1083 * Finds the truly immutable ranges by taking mutable ones out. Implements
1084 * interval difference of imut and mut. Interval splitting necessitates
1085 * intermediate storage and complex double buffering.
1086 */
1087void
1088_dl_apply_immutable(elf_object_t *object)
1089{
1090 struct range_vector acc[2]; /* flips out to avoid copying */
1091 struct addr_range *m, *im;
1092 int i, j, imut, in, out;
1093
1094 if (object->obj_type != OBJTYPE_LIB3)
1095 return;
1096
1097 for (imut = 0; imut < object->imut.count; imut++) {
1098 im = &object->imut.slice[imut];
1099 out = 0;
1100 acc[out].count = 0;
1101 _dl_push_range(&acc[out], im->start, im->end);
1102
1103 for (i = 0; i < object->mut.count; i++) {
1104 m = &object->mut.slice[i];
1105 in = out;
1106 out = 1 - in;
1107 acc[out].count = 0;
1108 for (j = 0; j < acc[in].count; j++) {
1109 const vaddr_t ms = m->start, me = m->end;
1110 const vaddr_t is = acc[in].slice[j].start,
1111 ie = acc[in].slice[j].end;
1112 if (ie <= ms || me <= is) {
1113 /* is .. ie .. ms .. me -> is .. ie */
1114 /* ms .. me .. is .. ie -> is .. ie */
1115 _dl_push_range(&acc[out], is, ie);
1116 } else if (ms <= is && ie <= me) {
1117 /* PROVIDED: ms < ie && is < me */
1118 /* ms .. is .. ie .. me -> [] */
1119 ;
1120 } else if (ie <= me) {
1121 /* is .. ms .. ie .. me -> is .. ms */
1122 _dl_push_range(&acc[out], is, ms);
1123 } else if (is < ms) {
1124 /* is .. ms .. me .. ie -> is .. ms */
1125 _dl_push_range(&acc[out], is, ms);
1126 _dl_push_range(&acc[out], me, ie);
1127 } else {
1128 /* ms .. is .. me .. ie -> me .. ie */
1129 _dl_push_range(&acc[out], me, ie);
1130 }
1131 }
1132 }
1133
1134 /* and now, install immutability for objects */
1135 for (i = 0; i < acc[out].count; i++) {
1136 const struct addr_range *ar = &acc[out].slice[i];
1137 _dl_mimmutable((void *)ar->start, ar->end - ar->start);
1138 }
1139
1140 }
1141}