1*210cc31eSderaadt /* $OpenBSD: loader.c,v 1.223 2024/01/22 02:08:31 deraadt Exp $ */
24d11faf9Srahnds
34d11faf9Srahnds /*
44d11faf9Srahnds * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
54d11faf9Srahnds *
64d11faf9Srahnds * Redistribution and use in source and binary forms, with or without
74d11faf9Srahnds * modification, are permitted provided that the following conditions
84d11faf9Srahnds * are met:
94d11faf9Srahnds * 1. Redistributions of source code must retain the above copyright
104d11faf9Srahnds * notice, this list of conditions and the following disclaimer.
114d11faf9Srahnds * 2. Redistributions in binary form must reproduce the above copyright
124d11faf9Srahnds * notice, this list of conditions and the following disclaimer in the
134d11faf9Srahnds * documentation and/or other materials provided with the distribution.
144d11faf9Srahnds *
154d11faf9Srahnds * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
164d11faf9Srahnds * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
174d11faf9Srahnds * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184d11faf9Srahnds * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
194d11faf9Srahnds * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204d11faf9Srahnds * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214d11faf9Srahnds * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224d11faf9Srahnds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234d11faf9Srahnds * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244d11faf9Srahnds * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254d11faf9Srahnds * SUCH DAMAGE.
264d11faf9Srahnds *
274d11faf9Srahnds */
284d11faf9Srahnds
294d11faf9Srahnds #define _DYN_LOADER
304d11faf9Srahnds
314d11faf9Srahnds #include <sys/types.h>
324d11faf9Srahnds #include <sys/mman.h>
33a4ba1e57Sderaadt #include <sys/syscall.h>
346dd2d847Sderaadt #include <sys/exec.h>
35b722ba42Sguenther #ifdef __i386__
360458707bSkurt # include <machine/vmparam.h>
37b722ba42Sguenther #endif
38bcbffc12Sdrahn #include <string.h>
394d11faf9Srahnds #include <link.h>
40702424caSguenther #include <limits.h> /* NAME_MAX */
4150f3e86fSdrahn #include <dlfcn.h>
42c0197e40Sguenther #include <tib.h>
434d11faf9Srahnds
444d11faf9Srahnds #include "syscall.h"
45b722ba42Sguenther #include "util.h"
464d11faf9Srahnds #include "resolve.h"
47b722ba42Sguenther #include "path.h"
48bcbffc12Sdrahn #include "sod.h"
494d11faf9Srahnds
504d11faf9Srahnds /*
514d11faf9Srahnds * Local decls.
524d11faf9Srahnds */
53c0197e40Sguenther unsigned long _dl_boot(const char **, char **, const long, long *) __boot;
545b36bcefSderaadt void _dl_debug_state(void);
55c0197e40Sguenther void _dl_setup_env(const char *_argv0, char **_envp) __boot;
565b36bcefSderaadt void _dl_dtors(void);
57c0197e40Sguenther void _dl_dopreload(char *_paths) __boot;
58c0197e40Sguenther void _dl_fixup_user_env(void) __boot;
59c0197e40Sguenther void _dl_call_preinit(elf_object_t *) __boot;
600fdecfd0Sguenther void _dl_call_init_recurse(elf_object_t *object, int initfirst);
61c0197e40Sguenther void _dl_clean_boot(void);
6290273bfbSguenther static inline void unprotect_if_textrel(elf_object_t *_object);
6390273bfbSguenther static inline void reprotect_if_textrel(elf_object_t *_object);
64b3331980Sguenther static void _dl_rreloc(elf_object_t *_object);
654d11faf9Srahnds
66d1b0fb8fSguenther int _dl_pagesz __relro = 4096;
67d1b0fb8fSguenther int _dl_bindnow __relro = 0;
68d1b0fb8fSguenther int _dl_debug __relro = 0;
69d1b0fb8fSguenther int _dl_trust __relro = 0;
70d1b0fb8fSguenther char **_dl_libpath __relro = NULL;
71c0197e40Sguenther const char **_dl_argv __relro = NULL;
72c0197e40Sguenther int _dl_argc __relro = 0;
735a40d3e0Skettenis const char *_dl_libcname;
74d1b0fb8fSguenther
75c0197e40Sguenther char *_dl_preload __boot_data = NULL;
76c0197e40Sguenther char *_dl_tracefmt1 __boot_data = NULL;
77c0197e40Sguenther char *_dl_tracefmt2 __boot_data = NULL;
78c0197e40Sguenther char *_dl_traceprog __boot_data = NULL;
790458707bSkurt void *_dl_exec_hint __boot_data = NULL;
80c0197e40Sguenther
81c0197e40Sguenther char **environ = NULL;
82c0197e40Sguenther char *__progname = NULL;
83d1b0fb8fSguenther
8410200827Sguenther int _dl_traceld;
854d11faf9Srahnds struct r_debug *_dl_debug_map;
864d11faf9Srahnds
87c0197e40Sguenther static dl_cb_cb _dl_cb_cb;
88c0197e40Sguenther const struct dl_cb_0 callbacks_0 = {
89c0197e40Sguenther .dl_allocate_tib = &_dl_allocate_tib,
90c0197e40Sguenther .dl_free_tib = &_dl_free_tib,
91c0197e40Sguenther #if DO_CLEAN_BOOT
92c0197e40Sguenther .dl_clean_boot = &_dl_clean_boot,
93c0197e40Sguenther #endif
94c0197e40Sguenther .dlopen = &dlopen,
95c0197e40Sguenther .dlclose = &dlclose,
96c0197e40Sguenther .dlsym = &dlsym,
97c0197e40Sguenther .dladdr = &dladdr,
98c0197e40Sguenther .dlctl = &dlctl,
99c0197e40Sguenther .dlerror = &dlerror,
100c0197e40Sguenther .dl_iterate_phdr = &dl_iterate_phdr,
101c0197e40Sguenther };
102c0197e40Sguenther
103bcbffc12Sdrahn
1044d11faf9Srahnds /*
10586fa57a2Skettenis * Run dtors for a single object.
10686fa57a2Skettenis */
10786fa57a2Skettenis void
_dl_run_dtors(elf_object_t * obj)10886fa57a2Skettenis _dl_run_dtors(elf_object_t *obj)
10986fa57a2Skettenis {
11086fa57a2Skettenis if (obj->dyn.fini_array) {
11186fa57a2Skettenis int num = obj->dyn.fini_arraysz / sizeof(Elf_Addr);
11286fa57a2Skettenis int i;
11386fa57a2Skettenis
11486fa57a2Skettenis DL_DEB(("doing finiarray obj %p @%p: [%s]\n",
11586fa57a2Skettenis obj, obj->dyn.fini_array, obj->load_name));
11686fa57a2Skettenis for (i = num; i > 0; i--)
11786fa57a2Skettenis (*obj->dyn.fini_array[i-1])();
11886fa57a2Skettenis }
11986fa57a2Skettenis
12086fa57a2Skettenis if (obj->dyn.fini) {
12186fa57a2Skettenis DL_DEB(("doing dtors obj %p @%p: [%s]\n",
12286fa57a2Skettenis obj, obj->dyn.fini, obj->load_name));
12386fa57a2Skettenis (*obj->dyn.fini)();
12486fa57a2Skettenis }
12586fa57a2Skettenis }
12686fa57a2Skettenis
12786fa57a2Skettenis /*
12850cabf59Skurt * Run dtors for all objects that are eligible.
12952dd7988Sdrahn */
13052dd7988Sdrahn void
_dl_run_all_dtors(void)1310fdecfd0Sguenther _dl_run_all_dtors(void)
132db7b3db5Sdrahn {
133034b0143Sdrahn elf_object_t *node;
1340fdecfd0Sguenther int fini_complete;
1350fdecfd0Sguenther int skip_initfirst;
1360fdecfd0Sguenther int initfirst_skipped;
137034b0143Sdrahn
138034b0143Sdrahn fini_complete = 0;
1390fdecfd0Sguenther skip_initfirst = 1;
1400fdecfd0Sguenther initfirst_skipped = 0;
141034b0143Sdrahn
142034b0143Sdrahn while (fini_complete == 0) {
143034b0143Sdrahn fini_complete = 1;
14486fa57a2Skettenis for (node = _dl_objects;
145034b0143Sdrahn node != NULL;
146034b0143Sdrahn node = node->next) {
14786fa57a2Skettenis if ((node->dyn.fini || node->dyn.fini_array) &&
148ca7a62b5Skurt (OBJECT_REF_CNT(node) == 0) &&
149034b0143Sdrahn (node->status & STAT_INIT_DONE) &&
150034b0143Sdrahn ((node->status & STAT_FINI_DONE) == 0)) {
1510fdecfd0Sguenther if (skip_initfirst &&
1520fdecfd0Sguenther (node->obj_flags & DF_1_INITFIRST))
1530fdecfd0Sguenther initfirst_skipped = 1;
1540fdecfd0Sguenther else
155034b0143Sdrahn node->status |= STAT_FINI_READY;
1563072fcbcSderaadt }
157034b0143Sdrahn }
15886fa57a2Skettenis for (node = _dl_objects;
159034b0143Sdrahn node != NULL;
160034b0143Sdrahn node = node->next) {
16186fa57a2Skettenis if ((node->dyn.fini || node->dyn.fini_array) &&
162ca7a62b5Skurt (OBJECT_REF_CNT(node) == 0) &&
163034b0143Sdrahn (node->status & STAT_INIT_DONE) &&
1640fdecfd0Sguenther ((node->status & STAT_FINI_DONE) == 0) &&
1650fdecfd0Sguenther (!skip_initfirst ||
166d937a926Sguenther (node->obj_flags & DF_1_INITFIRST) == 0)) {
167d937a926Sguenther struct object_vector vec = node->child_vec;
168d937a926Sguenther int i;
169d937a926Sguenther
170d937a926Sguenther for (i = 0; i < vec.len; i++)
171d937a926Sguenther vec.vec[i]->status &= ~STAT_FINI_READY;
172d937a926Sguenther }
173034b0143Sdrahn }
174034b0143Sdrahn
17586fa57a2Skettenis for (node = _dl_objects;
176034b0143Sdrahn node != NULL;
177034b0143Sdrahn node = node->next) {
178034b0143Sdrahn if (node->status & STAT_FINI_READY) {
179034b0143Sdrahn fini_complete = 0;
180034b0143Sdrahn node->status |= STAT_FINI_DONE;
181034b0143Sdrahn node->status &= ~STAT_FINI_READY;
18286fa57a2Skettenis _dl_run_dtors(node);
183034b0143Sdrahn }
184034b0143Sdrahn }
1850fdecfd0Sguenther
1860fdecfd0Sguenther if (fini_complete && initfirst_skipped)
1870fdecfd0Sguenther fini_complete = initfirst_skipped = skip_initfirst = 0;
188034b0143Sdrahn }
189db7b3db5Sdrahn }
190db7b3db5Sdrahn
191034b0143Sdrahn /*
192034b0143Sdrahn * Routine to walk through all of the objects except the first
193034b0143Sdrahn * (main executable).
194034b0143Sdrahn *
195034b0143Sdrahn * Big question, should dlopen()ed objects be unloaded before or after
196034b0143Sdrahn * the destructor for the main application runs?
197034b0143Sdrahn */
198034b0143Sdrahn void
_dl_dtors(void)1997a154befSart _dl_dtors(void)
20052dd7988Sdrahn {
201034b0143Sdrahn _dl_thread_kern_stop();
202034b0143Sdrahn
203034b0143Sdrahn /* ORDER? */
204034b0143Sdrahn _dl_unload_dlopen();
205034b0143Sdrahn
2069c8de590Sart DL_DEB(("doing dtors\n"));
207034b0143Sdrahn
20850cabf59Skurt _dl_objects->opencount--;
20950cabf59Skurt _dl_notify_unload_shlib(_dl_objects);
21050cabf59Skurt
21150cabf59Skurt _dl_run_all_dtors();
21252dd7988Sdrahn }
2137a154befSart
214c0197e40Sguenther #if DO_CLEAN_BOOT
215c0197e40Sguenther void
_dl_clean_boot(void)216c0197e40Sguenther _dl_clean_boot(void)
217c0197e40Sguenther {
218c0197e40Sguenther extern char boot_text_start[], boot_text_end[];
21961923635Sderaadt #if 0 /* XXX breaks boehm-gc?!? */
220c0197e40Sguenther extern char boot_data_start[], boot_data_end[];
22161923635Sderaadt #endif
222c0197e40Sguenther
2238e29f60aSderaadt _dl_mmap(boot_text_start, boot_text_end - boot_text_start,
2248e29f60aSderaadt PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
2258e29f60aSderaadt _dl_mimmutable(boot_text_start, boot_text_end - boot_text_start);
22661923635Sderaadt #if 0 /* XXX breaks boehm-gc?!? */
2278e29f60aSderaadt _dl_mmap(boot_data_start, boot_data_end - boot_data_start,
2288e29f60aSderaadt PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
2298e29f60aSderaadt _dl_mimmutable(boot_data_start, boot_data_end - boot_data_start);
23061923635Sderaadt #endif
231c0197e40Sguenther }
232c0197e40Sguenther #endif /* DO_CLEAN_BOOT */
233c0197e40Sguenther
234bcbffc12Sdrahn void
_dl_dopreload(char * paths)235896cf611Sderaadt _dl_dopreload(char *paths)
236bcbffc12Sdrahn {
237bcbffc12Sdrahn char *cp, *dp;
2382c770406Sdrahn elf_object_t *shlib;
239d937a926Sguenther int count;
240bcbffc12Sdrahn
241bcbffc12Sdrahn dp = paths = _dl_strdup(paths);
2423b50b772Sguenther if (dp == NULL)
2433b50b772Sguenther _dl_oom();
244bcbffc12Sdrahn
245d937a926Sguenther /* preallocate child_vec for the LD_PRELOAD objects */
246d937a926Sguenther count = 1;
247d937a926Sguenther while (*dp++ != '\0')
248d937a926Sguenther if (*dp == ':')
249d937a926Sguenther count++;
250d937a926Sguenther object_vec_grow(&_dl_objects->child_vec, count);
251d937a926Sguenther
252d937a926Sguenther dp = paths;
253bcbffc12Sdrahn while ((cp = _dl_strsep(&dp, ":")) != NULL) {
25450f3e86fSdrahn shlib = _dl_load_shlib(cp, _dl_objects, OBJTYPE_LIB,
25507cf23bbSderaadt _dl_objects->obj_flags, 1);
2563b50b772Sguenther if (shlib == NULL)
2573b50b772Sguenther _dl_die("can't preload library '%s'", cp);
25870be5820Sdrahn _dl_add_object(shlib);
259ea03aff5Skurt _dl_link_child(shlib, _dl_objects);
260bcbffc12Sdrahn }
261bcbffc12Sdrahn _dl_free(paths);
262bcbffc12Sdrahn return;
263bcbffc12Sdrahn }
264bcbffc12Sdrahn
26552dd7988Sdrahn /*
2661f579edaSdrahn * grab interesting environment variables, zap bad env vars if
267702424caSguenther * issetugid, and set the exported environ and __progname variables
2684d11faf9Srahnds */
2691f579edaSdrahn void
_dl_setup_env(const char * argv0,char ** envp)270702424caSguenther _dl_setup_env(const char *argv0, char **envp)
2711f579edaSdrahn {
272702424caSguenther static char progname_storage[NAME_MAX+1] = "";
273702424caSguenther
2744d11faf9Srahnds /*
2754d11faf9Srahnds * Don't allow someone to change the search paths if he runs
2764d11faf9Srahnds * a suid program without credentials high enough.
2774d11faf9Srahnds */
278337bd349Skurt _dl_trust = !_dl_issetugid();
279337bd349Skurt if (!_dl_trust) { /* Zap paths if s[ug]id... */
280bd6b0c7aSdrahn _dl_unsetenv("LD_DEBUG", envp);
2814b65c70cSguenther _dl_unsetenv("LD_LIBRARY_PATH", envp);
2824b65c70cSguenther _dl_unsetenv("LD_PRELOAD", envp);
2834b65c70cSguenther _dl_unsetenv("LD_BIND_NOW", envp);
2844b65c70cSguenther } else {
2854b65c70cSguenther /*
2864b65c70cSguenther * Get paths to various things we are going to use.
2874b65c70cSguenther */
2884b65c70cSguenther _dl_debug = _dl_getenv("LD_DEBUG", envp) != NULL;
2894b65c70cSguenther _dl_libpath = _dl_split_path(_dl_getenv("LD_LIBRARY_PATH",
2904b65c70cSguenther envp));
2914b65c70cSguenther _dl_preload = _dl_getenv("LD_PRELOAD", envp);
2924b65c70cSguenther _dl_bindnow = _dl_getenv("LD_BIND_NOW", envp) != NULL;
293bd6b0c7aSdrahn }
2944b65c70cSguenther
2954b65c70cSguenther /* these are usable even in setugid processes */
2964b65c70cSguenther _dl_traceld = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp) != NULL;
2974b65c70cSguenther _dl_tracefmt1 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT1", envp);
2984b65c70cSguenther _dl_tracefmt2 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT2", envp);
2994b65c70cSguenther _dl_traceprog = _dl_getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", envp);
3004b65c70cSguenther
301702424caSguenther environ = envp;
302ae398163Smiod
303ae398163Smiod _dl_trace_setup(envp);
304702424caSguenther
305702424caSguenther if (argv0 != NULL) { /* NULL ptr if argc = 0 */
306702424caSguenther const char *p = _dl_strrchr(argv0, '/');
307702424caSguenther
308702424caSguenther if (p == NULL)
309702424caSguenther p = argv0;
310702424caSguenther else
311702424caSguenther p++;
312702424caSguenther _dl_strlcpy(progname_storage, p, sizeof(progname_storage));
313702424caSguenther }
314702424caSguenther __progname = progname_storage;
3151f579edaSdrahn }
3161f579edaSdrahn
31767939fc6Skurt int
_dl_load_dep_libs(elf_object_t * object,int flags,int booting)31867939fc6Skurt _dl_load_dep_libs(elf_object_t *object, int flags, int booting)
31967939fc6Skurt {
320a09d28f1Sderaadt elf_object_t *dynobj;
32167939fc6Skurt Elf_Dyn *dynp;
32267939fc6Skurt unsigned int loop;
32367939fc6Skurt int libcount;
32482e9b32aSderaadt int depflags, nodelete = 0;
32567939fc6Skurt
32667939fc6Skurt dynobj = object;
32767939fc6Skurt while (dynobj) {
32867939fc6Skurt DL_DEB(("examining: '%s'\n", dynobj->load_name));
32967939fc6Skurt libcount = 0;
3308f55ac75Skurt
3310fdecfd0Sguenther /* propagate DF_1_NOW to deplibs (can be set by dynamic tags) */
3320fdecfd0Sguenther depflags = flags | (dynobj->obj_flags & DF_1_NOW);
33382e9b32aSderaadt if (booting || object->nodelete)
33482e9b32aSderaadt nodelete = 1;
3358f55ac75Skurt
33667939fc6Skurt for (dynp = dynobj->load_dyn; dynp->d_tag; dynp++) {
33767939fc6Skurt if (dynp->d_tag == DT_NEEDED) {
33867939fc6Skurt libcount++;
33967939fc6Skurt }
34067939fc6Skurt }
34167939fc6Skurt
34267939fc6Skurt if (libcount != 0) {
34367939fc6Skurt struct listent {
34467939fc6Skurt Elf_Dyn *dynp;
34567939fc6Skurt elf_object_t *depobj;
34667939fc6Skurt } *liblist;
34767939fc6Skurt int *randomlist;
34867939fc6Skurt
349c827e20bSotto liblist = _dl_reallocarray(NULL, libcount,
350c827e20bSotto sizeof(struct listent));
351c827e20bSotto randomlist = _dl_reallocarray(NULL, libcount,
352c827e20bSotto sizeof(int));
35367939fc6Skurt
354ccf88c65Sotto if (liblist == NULL || randomlist == NULL)
3553b50b772Sguenther _dl_oom();
35667939fc6Skurt
35767939fc6Skurt for (dynp = dynobj->load_dyn, loop = 0; dynp->d_tag;
35867939fc6Skurt dynp++)
35967939fc6Skurt if (dynp->d_tag == DT_NEEDED)
36067939fc6Skurt liblist[loop++].dynp = dynp;
36167939fc6Skurt
3625a40d3e0Skettenis /*
3635a40d3e0Skettenis * We can't support multiple versions of libc
3645a40d3e0Skettenis * in a single process. So remember the first
3655a40d3e0Skettenis * libc SONAME we encounter as a dependency
3665a40d3e0Skettenis * and use it in further loads of libc. In
3675a40d3e0Skettenis * practice this means we will always use the
3685a40d3e0Skettenis * libc version that the binary was linked
3695a40d3e0Skettenis * against. This isn't entirely correct, but
3705a40d3e0Skettenis * it will keep most binaries running when
3715a40d3e0Skettenis * transitioning over a libc major bump.
3725a40d3e0Skettenis */
3735a40d3e0Skettenis if (_dl_libcname == NULL) {
3745a40d3e0Skettenis for (loop = 0; loop < libcount; loop++) {
3755a40d3e0Skettenis const char *libname;
3765a40d3e0Skettenis libname = dynobj->dyn.strtab;
3775a40d3e0Skettenis libname +=
3785a40d3e0Skettenis liblist[loop].dynp->d_un.d_val;
3795a40d3e0Skettenis if (_dl_strncmp(libname,
3805a40d3e0Skettenis "libc.so.", 8) == 0) {
3815a40d3e0Skettenis _dl_libcname = libname;
3825a40d3e0Skettenis break;
3835a40d3e0Skettenis }
3845a40d3e0Skettenis }
3855a40d3e0Skettenis }
3865a40d3e0Skettenis
38767939fc6Skurt /* Randomize these */
38867939fc6Skurt for (loop = 0; loop < libcount; loop++)
38967939fc6Skurt randomlist[loop] = loop;
39067939fc6Skurt
39167939fc6Skurt for (loop = 1; loop < libcount; loop++) {
39267939fc6Skurt unsigned int rnd;
39367939fc6Skurt int cur;
394acb148b1Sderaadt rnd = _dl_arc4random();
39567939fc6Skurt rnd = rnd % (loop+1);
39667939fc6Skurt cur = randomlist[rnd];
39767939fc6Skurt randomlist[rnd] = randomlist[loop];
39867939fc6Skurt randomlist[loop] = cur;
39967939fc6Skurt }
40067939fc6Skurt
40167939fc6Skurt for (loop = 0; loop < libcount; loop++) {
40267939fc6Skurt elf_object_t *depobj;
40367939fc6Skurt const char *libname;
40467939fc6Skurt libname = dynobj->dyn.strtab;
40567939fc6Skurt libname +=
40667939fc6Skurt liblist[randomlist[loop]].dynp->d_un.d_val;
40767939fc6Skurt DL_DEB(("loading: %s required by %s\n", libname,
40867939fc6Skurt dynobj->load_name));
4095a40d3e0Skettenis if (_dl_strncmp(libname, "libc.so.", 8) == 0) {
4105a40d3e0Skettenis if (_dl_libcname)
4115a40d3e0Skettenis libname = _dl_libcname;
4125a40d3e0Skettenis }
41367939fc6Skurt depobj = _dl_load_shlib(libname, dynobj,
41482e9b32aSderaadt OBJTYPE_LIB, depflags, nodelete);
41567939fc6Skurt if (depobj == 0) {
41667939fc6Skurt if (booting) {
4173b50b772Sguenther _dl_die(
4183b50b772Sguenther "can't load library '%s'",
4193b50b772Sguenther libname);
4203b50b772Sguenther }
42167939fc6Skurt DL_DEB(("dlopen: failed to open %s\n",
42267939fc6Skurt libname));
42367939fc6Skurt _dl_free(liblist);
42442d12061Sjsg _dl_free(randomlist);
42567939fc6Skurt return (1);
42667939fc6Skurt }
42767939fc6Skurt liblist[randomlist[loop]].depobj = depobj;
42867939fc6Skurt }
42967939fc6Skurt
430d937a926Sguenther object_vec_grow(&dynobj->child_vec, libcount);
43167939fc6Skurt for (loop = 0; loop < libcount; loop++) {
43267939fc6Skurt _dl_add_object(liblist[loop].depobj);
43367939fc6Skurt _dl_link_child(liblist[loop].depobj, dynobj);
43467939fc6Skurt }
43567939fc6Skurt _dl_free(liblist);
43642d12061Sjsg _dl_free(randomlist);
43767939fc6Skurt }
43867939fc6Skurt dynobj = dynobj->next;
43967939fc6Skurt }
44067939fc6Skurt
4411a53160bSdrahn _dl_cache_grpsym_list_setup(object);
44267939fc6Skurt return(0);
44367939fc6Skurt }
44467939fc6Skurt
4456a54f14dSdrahn
446d1b0fb8fSguenther /* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */
447d1b0fb8fSguenther static inline void
_dl_self_relro(long loff)448d1b0fb8fSguenther _dl_self_relro(long loff)
449d1b0fb8fSguenther {
450d1b0fb8fSguenther Elf_Ehdr *ehdp;
451d1b0fb8fSguenther Elf_Phdr *phdp;
452d1b0fb8fSguenther int i;
453d1b0fb8fSguenther
454d1b0fb8fSguenther ehdp = (Elf_Ehdr *)loff;
455d1b0fb8fSguenther phdp = (Elf_Phdr *)(loff + ehdp->e_phoff);
456d1b0fb8fSguenther for (i = 0; i < ehdp->e_phnum; i++, phdp++) {
457d1b0fb8fSguenther switch (phdp->p_type) {
458d1b0fb8fSguenther #if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \
459d1b0fb8fSguenther defined(__sparc64__)
460d1b0fb8fSguenther case PT_LOAD:
461d1b0fb8fSguenther if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W))
462d1b0fb8fSguenther break;
463d1b0fb8fSguenther _dl_mprotect((void *)(phdp->p_vaddr + loff),
464d1b0fb8fSguenther phdp->p_memsz, PROT_READ);
465d1b0fb8fSguenther break;
466d1b0fb8fSguenther #endif
467d1b0fb8fSguenther case PT_GNU_RELRO:
468d1b0fb8fSguenther _dl_mprotect((void *)(phdp->p_vaddr + loff),
469d1b0fb8fSguenther phdp->p_memsz, PROT_READ);
470980da63bSderaadt _dl_mimmutable((void *)(phdp->p_vaddr + loff),
471980da63bSderaadt phdp->p_memsz);
472d1b0fb8fSguenther break;
473d1b0fb8fSguenther }
474d1b0fb8fSguenther }
475d1b0fb8fSguenther }
476d1b0fb8fSguenther
477d1b0fb8fSguenther
4782cd0722aSkettenis #define PFLAGS(X) ((((X) & PF_R) ? PROT_READ : 0) | \
4792cd0722aSkettenis (((X) & PF_W) ? PROT_WRITE : 0) | \
4802cd0722aSkettenis (((X) & PF_X) ? PROT_EXEC : 0))
4816a54f14dSdrahn
4821f579edaSdrahn /*
483876ab33dSderaadt * To avoid kbind(2) becoming a powerful gadget, it is called inline to a
484876ab33dSderaadt * function. Therefore we cannot create a precise pinsyscall label. Instead
485876ab33dSderaadt * create a duplicate entry to force the kernel's pinsyscall code to skip
486876ab33dSderaadt * validation, rather than labelling it illegal. kbind(2) remains safe
487876ab33dSderaadt * because it self-protects by checking its calling address.
488876ab33dSderaadt */
489876ab33dSderaadt #define __STRINGIFY(x) #x
490876ab33dSderaadt #define STRINGIFY(x) __STRINGIFY(x)
491876ab33dSderaadt #ifdef __arm__
492babd3aceSderaadt __asm__(".pushsection .openbsd.syscalls,\"\",%progbits;"
493876ab33dSderaadt ".p2align 2;"
494876ab33dSderaadt ".long 0;"
495876ab33dSderaadt ".long " STRINGIFY(SYS_kbind) ";"
496876ab33dSderaadt ".popsection");
497876ab33dSderaadt #else
498babd3aceSderaadt __asm__(".pushsection .openbsd.syscalls,\"\",@progbits;"
499876ab33dSderaadt ".p2align 2;"
500d20ca04bSderaadt ".long 0;"
501876ab33dSderaadt ".long " STRINGIFY(SYS_kbind) ";"
502876ab33dSderaadt ".popsection");
503876ab33dSderaadt #endif
504876ab33dSderaadt
505876ab33dSderaadt /*
5061f579edaSdrahn * This is the dynamic loader entrypoint. When entering here, depending
5071f579edaSdrahn * on architecture type, the stack and registers are set up according
5081f579edaSdrahn * to the architectures ABI specification. The first thing required
5091f579edaSdrahn * to do is to dig out all information we need to accomplish our task.
5101f579edaSdrahn */
5111f579edaSdrahn unsigned long
_dl_boot(const char ** argv,char ** envp,const long dyn_loff,long * dl_data)512d6c8b198Skurt _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
5131f579edaSdrahn {
5141f579edaSdrahn struct elf_object *exe_obj; /* Pointer to executable object */
515702424caSguenther struct elf_object *dyn_obj; /* Pointer to ld.so object */
5161f579edaSdrahn struct r_debug **map_link; /* Where to put pointer for gdb */
5171f579edaSdrahn struct r_debug *debug_map;
5182cd0722aSkettenis struct load_list *next_load, *load_list = NULL;
5191f579edaSdrahn Elf_Dyn *dynp;
5201f579edaSdrahn Elf_Phdr *phdp;
5219f6c3316Skurt Elf_Ehdr *ehdr;
522d6c8b198Skurt char *us = NULL;
52361632685Sdrahn unsigned int loop;
52467939fc6Skurt int failed;
5250acae5e5Sdrahn struct dep_node *n;
5260458707bSkurt Elf_Addr minva, maxva, exe_loff, exec_end, cur_exec_end;
527f9a87ca6Skn Elf_Addr relro_addr = 0, relro_size = 0;
528fe38b55cSguenther Elf_Phdr *ptls = NULL;
529d6c8b198Skurt int align;
5301f579edaSdrahn
53131f74128Sderaadt if (dl_data[AUX_pagesz] != 0)
53231f74128Sderaadt _dl_pagesz = dl_data[AUX_pagesz];
533d1b0fb8fSguenther _dl_malloc_init();
534c0197e40Sguenther
535c0197e40Sguenther _dl_argv = argv;
536c0197e40Sguenther while (_dl_argv[_dl_argc] != NULL)
537c0197e40Sguenther _dl_argc++;
538d1b0fb8fSguenther _dl_setup_env(argv[0], envp);
539d1b0fb8fSguenther
540d1b0fb8fSguenther /*
541d1b0fb8fSguenther * Make read-only the GOT and PLT and variables initialized
542d1b0fb8fSguenther * during the ld.so setup above.
543d1b0fb8fSguenther */
544d1b0fb8fSguenther _dl_self_relro(dyn_loff);
54531f74128Sderaadt
546d6c8b198Skurt align = _dl_pagesz - 1;
547d6c8b198Skurt
548d6c8b198Skurt #define ROUND_PG(x) (((x) + align) & ~(align))
549d6c8b198Skurt #define TRUNC_PG(x) ((x) & ~(align))
550d6c8b198Skurt
5517c5a529fSguenther if (_dl_bindnow) {
5527c5a529fSguenther /* Lazy binding disabled, so disable kbind */
5531d60349dSguenther _dl_kbind(NULL, 0, 0);
5547c5a529fSguenther }
555149e4352Sguenther
556998f22c3Sderaadt DL_DEB(("ld.so loading: '%s'\n", __progname));
55731f74128Sderaadt
5580acae5e5Sdrahn /* init this in runtime, not statically */
5590acae5e5Sdrahn TAILQ_INIT(&_dlopened_child_list);
5600acae5e5Sdrahn
561bcbffc12Sdrahn exe_obj = NULL;
56297ba1a81Skurt _dl_loading_object = NULL;
563d6c8b198Skurt
564de10163aSguenther minva = ELF_NO_ADDR;
5650458707bSkurt maxva = exe_loff = exec_end = 0;
566d6c8b198Skurt
5674d11faf9Srahnds /*
5684d11faf9Srahnds * Examine the user application and set up object information.
5694d11faf9Srahnds */
570cd0faa30Sdrahn phdp = (Elf_Phdr *)dl_data[AUX_phdr];
57161632685Sdrahn for (loop = 0; loop < dl_data[AUX_phnum]; loop++) {
572d6c8b198Skurt switch (phdp->p_type) {
573d6c8b198Skurt case PT_PHDR:
574d6c8b198Skurt exe_loff = (Elf_Addr)dl_data[AUX_phdr] - phdp->p_vaddr;
575d6c8b198Skurt us += exe_loff;
576d6c8b198Skurt DL_DEB(("exe load offset: 0x%lx\n", exe_loff));
577d6c8b198Skurt break;
578d6c8b198Skurt case PT_DYNAMIC:
579d6c8b198Skurt minva = TRUNC_PG(minva);
580d6c8b198Skurt maxva = ROUND_PG(maxva);
581cc809ae3Sdrahn exe_obj = _dl_finalize_object(argv[0] ? argv[0] : "",
5821212aee3Skurt (Elf_Dyn *)(phdp->p_vaddr + exe_loff),
5831212aee3Skurt (Elf_Phdr *)dl_data[AUX_phdr],
5841212aee3Skurt dl_data[AUX_phnum], OBJTYPE_EXE, minva + exe_loff,
5851212aee3Skurt exe_loff);
58670be5820Sdrahn _dl_add_object(exe_obj);
587d6c8b198Skurt break;
588d6c8b198Skurt case PT_INTERP:
589d6c8b198Skurt us += phdp->p_vaddr;
590d6c8b198Skurt break;
591d6c8b198Skurt case PT_LOAD:
592d6c8b198Skurt if (phdp->p_vaddr < minva)
593d6c8b198Skurt minva = phdp->p_vaddr;
594d6c8b198Skurt if (phdp->p_vaddr > maxva)
595d6c8b198Skurt maxva = phdp->p_vaddr + phdp->p_memsz;
5962cd0722aSkettenis
597c827e20bSotto next_load = _dl_calloc(1, sizeof(struct load_list));
59867b06ea7Sotto if (next_load == NULL)
5993b50b772Sguenther _dl_oom();
6002cd0722aSkettenis next_load->next = load_list;
6012cd0722aSkettenis load_list = next_load;
602d6c8b198Skurt next_load->start = (char *)TRUNC_PG(phdp->p_vaddr) + exe_loff;
603d6c8b198Skurt next_load->size = (phdp->p_vaddr & align) + phdp->p_filesz;
6042cd0722aSkettenis next_load->prot = PFLAGS(phdp->p_flags);
6050458707bSkurt cur_exec_end = (Elf_Addr)next_load->start + next_load->size;
6060458707bSkurt if ((next_load->prot & PROT_EXEC) != 0 &&
6070458707bSkurt cur_exec_end > exec_end)
6080458707bSkurt exec_end = cur_exec_end;
609d6c8b198Skurt break;
61061a0379fSjsing case PT_TLS:
6113b50b772Sguenther if (phdp->p_filesz > phdp->p_memsz)
6123b50b772Sguenther _dl_die("invalid tls data");
613fe38b55cSguenther ptls = phdp;
61461a0379fSjsing break;
615660c432fSguenther case PT_GNU_RELRO:
616f9a87ca6Skn relro_addr = phdp->p_vaddr + exe_loff;
617f9a87ca6Skn relro_size = phdp->p_memsz;
618660c432fSguenther break;
6192cd0722aSkettenis }
6204d11faf9Srahnds phdp++;
6214d11faf9Srahnds }
6222cd0722aSkettenis exe_obj->load_list = load_list;
6230fdecfd0Sguenther exe_obj->obj_flags |= DF_1_GLOBAL;
624b8b81751Sderaadt exe_obj->nodelete = 1;
625d6c8b198Skurt exe_obj->load_size = maxva - minva;
626f9a87ca6Skn exe_obj->relro_addr = relro_addr;
627f9a87ca6Skn exe_obj->relro_size = relro_size;
6280af06aafSkurt _dl_set_sod(exe_obj->load_name, &exe_obj->sod);
6290acae5e5Sdrahn
6300458707bSkurt #ifdef __i386__
6310458707bSkurt if (exec_end > I386_MAX_EXE_ADDR)
6320458707bSkurt _dl_exec_hint = (void *)ROUND_PG(exec_end-I386_MAX_EXE_ADDR);
6330458707bSkurt DL_DEB(("_dl_exec_hint: 0x%lx\n", _dl_exec_hint));
6340458707bSkurt #endif
6350458707bSkurt
636fe38b55cSguenther /* TLS bits in the base executable */
637fe38b55cSguenther if (ptls != NULL && ptls->p_memsz)
638fe38b55cSguenther _dl_set_tls(exe_obj, ptls, exe_loff, NULL);
639fe38b55cSguenther
6400acae5e5Sdrahn n = _dl_malloc(sizeof *n);
6410acae5e5Sdrahn if (n == NULL)
6423b50b772Sguenther _dl_oom();
6436fa405c3Sdrahn n->data = exe_obj;
6446fa405c3Sdrahn TAILQ_INSERT_TAIL(&_dlopened_child_list, n, next_sib);
64550cabf59Skurt exe_obj->opencount++;
6464d11faf9Srahnds
647bcbffc12Sdrahn if (_dl_preload != NULL)
648bcbffc12Sdrahn _dl_dopreload(_dl_preload);
649bcbffc12Sdrahn
6508f55ac75Skurt _dl_load_dep_libs(exe_obj, exe_obj->obj_flags, 1);
651ea03aff5Skurt
6524d11faf9Srahnds /*
6534d11faf9Srahnds * Now add the dynamic loader itself last in the object list
6544d11faf9Srahnds * so we can use the _dl_ code when serving dl.... calls.
655d937a926Sguenther * Intentionally left off the exe child_vec.
6564d11faf9Srahnds */
657cd0faa30Sdrahn dynp = (Elf_Dyn *)((void *)_DYNAMIC);
6589f6c3316Skurt ehdr = (Elf_Ehdr *)dl_data[AUX_base];
6599f6c3316Skurt dyn_obj = _dl_finalize_object(us, dynp,
6609f6c3316Skurt (Elf_Phdr *)((char *)dl_data[AUX_base] + ehdr->e_phoff),
661d6c8b198Skurt ehdr->e_phnum, OBJTYPE_LDR, dl_data[AUX_base], dyn_loff);
66270be5820Sdrahn _dl_add_object(dyn_obj);
6630acae5e5Sdrahn
6641a15fa31Skurt dyn_obj->refcount++;
665bae526eeSguenther _dl_link_grpsym(dyn_obj);
6660acae5e5Sdrahn
6674d11faf9Srahnds dyn_obj->status |= STAT_RELOC_DONE;
6680af06aafSkurt _dl_set_sod(dyn_obj->load_name, &dyn_obj->sod);
6694d11faf9Srahnds
670fe38b55cSguenther /* calculate the offsets for static TLS allocations */
671fe38b55cSguenther _dl_allocate_tls_offsets();
672fe38b55cSguenther
6734d11faf9Srahnds /*
674660c432fSguenther * Make something to help gdb when poking around in the code.
675660c432fSguenther * Do this poking at the .dynamic section now, before relocation
676660c432fSguenther * renders it read-only
6774d11faf9Srahnds */
678de140c13Skettenis map_link = NULL;
679fdb5f44cSart #ifdef __mips__
68041b7dcd7Svisa for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) {
68141b7dcd7Svisa if (dynp->d_tag == DT_MIPS_RLD_MAP_REL) {
68241b7dcd7Svisa map_link = (struct r_debug **)
68341b7dcd7Svisa (dynp->d_un.d_ptr + (Elf_Addr)dynp);
68441b7dcd7Svisa break;
68541b7dcd7Svisa } else if (dynp->d_tag == DT_MIPS_RLD_MAP) {
68641b7dcd7Svisa map_link = (struct r_debug **)
68741b7dcd7Svisa (dynp->d_un.d_ptr + exe_loff);
68841b7dcd7Svisa break;
68941b7dcd7Svisa }
69041b7dcd7Svisa }
691de140c13Skettenis #endif
692de140c13Skettenis if (map_link == NULL) {
693fdb5f44cSart for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) {
6944be7d39eSrahnds if (dynp->d_tag == DT_DEBUG) {
695fdb5f44cSart map_link = (struct r_debug **)&dynp->d_un.d_ptr;
6964be7d39eSrahnds break;
6974be7d39eSrahnds }
6984be7d39eSrahnds }
699896cf611Sderaadt if (dynp->d_tag != DT_DEBUG)
700fdb5f44cSart DL_DEB(("failed to mark DTDEBUG\n"));
701de140c13Skettenis }
7024d11faf9Srahnds if (map_link) {
70315531fceSderaadt debug_map = _dl_malloc(sizeof(*debug_map));
70467b06ea7Sotto if (debug_map == NULL)
7053b50b772Sguenther _dl_oom();
7064d11faf9Srahnds debug_map->r_version = 1;
7074d11faf9Srahnds debug_map->r_map = (struct link_map *)_dl_objects;
708cd0faa30Sdrahn debug_map->r_brk = (Elf_Addr)_dl_debug_state;
7094d11faf9Srahnds debug_map->r_state = RT_CONSISTENT;
710d6c8b198Skurt debug_map->r_ldbase = dyn_loff;
7114d11faf9Srahnds _dl_debug_map = debug_map;
712de140c13Skettenis #ifdef __mips__
713f9a87ca6Skn relro_addr = exe_obj->relro_addr;
714d4ca23acSguenther if (dynp->d_tag == DT_DEBUG &&
715d4ca23acSguenther ((Elf_Addr)map_link + sizeof(*map_link) <= relro_addr ||
716d4ca23acSguenther (Elf_Addr)map_link >= relro_addr + exe_obj->relro_size)) {
717de140c13Skettenis _dl_mprotect(map_link, sizeof(*map_link),
7183f92fbc1Skettenis PROT_READ|PROT_WRITE);
7194d11faf9Srahnds *map_link = _dl_debug_map;
720de140c13Skettenis _dl_mprotect(map_link, sizeof(*map_link),
721de140c13Skettenis PROT_READ|PROT_EXEC);
722d4ca23acSguenther } else
723de140c13Skettenis #endif
724d4ca23acSguenther *map_link = _dl_debug_map;
7254d11faf9Srahnds }
7264d11faf9Srahnds
727660c432fSguenther
728660c432fSguenther /*
729660c432fSguenther * Everything should be in place now for doing the relocation
730660c432fSguenther * and binding. Call _dl_rtld to do the job. Fingers crossed.
731660c432fSguenther */
732660c432fSguenther
733660c432fSguenther failed = 0;
73410200827Sguenther if (!_dl_traceld)
735660c432fSguenther failed = _dl_rtld(_dl_objects);
736660c432fSguenther
737660c432fSguenther if (_dl_debug || _dl_traceld) {
738660c432fSguenther if (_dl_traceld)
739660c432fSguenther _dl_pledge("stdio rpath", NULL);
740ac42b3c8Sguenther _dl_show_objects(NULL);
741660c432fSguenther }
742660c432fSguenther
743660c432fSguenther DL_DEB(("dynamic loading done, %s.\n",
744660c432fSguenther (failed == 0) ? "success":"failed"));
745660c432fSguenther
746660c432fSguenther if (failed != 0)
7473b50b772Sguenther _dl_die("relocation failed");
748660c432fSguenther
749660c432fSguenther if (_dl_traceld)
750660c432fSguenther _dl_exit(0);
751660c432fSguenther
752660c432fSguenther _dl_loading_object = NULL;
753660c432fSguenther
754660c432fSguenther /* set up the TIB for the initial thread */
755660c432fSguenther _dl_allocate_first_tib();
756660c432fSguenther
757660c432fSguenther _dl_fixup_user_env();
758660c432fSguenther
7594d11faf9Srahnds _dl_debug_state();
7604d11faf9Srahnds
761b4481b06Smickey /*
76283826a70Smickey * Do not run init code if run from ldd.
76383826a70Smickey */
76483826a70Smickey if (_dl_objects->next != NULL) {
76586fa57a2Skettenis _dl_call_preinit(_dl_objects);
76683826a70Smickey _dl_call_init(_dl_objects);
76783826a70Smickey }
76883826a70Smickey
769e1d366c8Sart DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry]));
77050f3e86fSdrahn
7717a154befSart /*
7727a154befSart * Return the entry point.
7737a154befSart */
7744d11faf9Srahnds return(dl_data[AUX_entry]);
7754d11faf9Srahnds }
7764d11faf9Srahnds
77761632685Sdrahn int
_dl_rtld(elf_object_t * object)7784d11faf9Srahnds _dl_rtld(elf_object_t *object)
7794d11faf9Srahnds {
7803f8ba917Skettenis struct load_list *llist;
78161632685Sdrahn int fails = 0;
78261632685Sdrahn
78339b7d201Sderaadt if (object->next)
78461632685Sdrahn fails += _dl_rtld(object->next);
7854d11faf9Srahnds
786bb87ac8eSart if (object->status & STAT_RELOC_DONE)
78761632685Sdrahn return 0;
788bb87ac8eSart
7894d11faf9Srahnds /*
7904d11faf9Srahnds * Do relocation information first, then GOT.
7914d11faf9Srahnds */
79290273bfbSguenther unprotect_if_textrel(object);
793b3331980Sguenther _dl_rreloc(object);
79461632685Sdrahn fails =_dl_md_reloc(object, DT_REL, DT_RELSZ);
79561632685Sdrahn fails += _dl_md_reloc(object, DT_RELA, DT_RELASZ);
79690273bfbSguenther reprotect_if_textrel(object);
797d9337de3Sguenther
798d9337de3Sguenther /*
799d9337de3Sguenther * We do lazy resolution by default, doing eager resolution if
800d9337de3Sguenther * - the object requests it with -znow, OR
801d9337de3Sguenther * - LD_BIND_NOW is set and this object isn't being ltraced
802d9337de3Sguenther *
803d9337de3Sguenther * Note that -znow disables ltrace for the object: on at least
804d9337de3Sguenther * amd64 'ld' doesn't generate the trampoline for lazy relocation
805d9337de3Sguenther * when -znow is used.
806d9337de3Sguenther */
807d9337de3Sguenther fails += _dl_md_reloc_got(object, !(object->obj_flags & DF_1_NOW) &&
808d9337de3Sguenther !(_dl_bindnow && !object->traced));
809c9cd759cSdrahn
8103f8ba917Skettenis /*
8113718ab45Sguenther * Look for W&X segments and make them read-only.
8123f8ba917Skettenis */
8133f8ba917Skettenis for (llist = object->load_list; llist != NULL; llist = llist->next) {
8143f8ba917Skettenis if ((llist->prot & PROT_WRITE) && (llist->prot & PROT_EXEC)) {
8153f8ba917Skettenis _dl_mprotect(llist->start, llist->size,
8163f8ba917Skettenis llist->prot & ~PROT_WRITE);
8173f8ba917Skettenis }
8183f8ba917Skettenis }
8193f8ba917Skettenis
820d23cb5cdSderaadt /*
821d23cb5cdSderaadt * TEXTREL binaries are loaded without immutable on un-writeable sections.
822d23cb5cdSderaadt * After text relocations are finished, these regions can become
823d23cb5cdSderaadt * immutable. OPENBSD_MUTABLE section always overlaps writeable LOADs,
824d23cb5cdSderaadt * so don't be afraid.
825d23cb5cdSderaadt */
826d23cb5cdSderaadt if (object->dyn.textrel) {
827d23cb5cdSderaadt for (llist = object->load_list; llist != NULL; llist = llist->next)
828d23cb5cdSderaadt if ((llist->prot & PROT_WRITE) == 0)
829d23cb5cdSderaadt _dl_mimmutable(llist->start, llist->size);
830d23cb5cdSderaadt }
831d23cb5cdSderaadt
83261632685Sdrahn if (fails == 0)
83382e43d29Sart object->status |= STAT_RELOC_DONE;
83461632685Sdrahn
83561632685Sdrahn return (fails);
8364d11faf9Srahnds }
8370fdecfd0Sguenther
8384d11faf9Srahnds void
_dl_call_preinit(elf_object_t * object)83986fa57a2Skettenis _dl_call_preinit(elf_object_t *object)
84086fa57a2Skettenis {
84186fa57a2Skettenis if (object->dyn.preinit_array) {
84286fa57a2Skettenis int num = object->dyn.preinit_arraysz / sizeof(Elf_Addr);
84386fa57a2Skettenis int i;
84486fa57a2Skettenis
84586fa57a2Skettenis DL_DEB(("doing preinitarray obj %p @%p: [%s]\n",
84686fa57a2Skettenis object, object->dyn.preinit_array, object->load_name));
84786fa57a2Skettenis for (i = 0; i < num; i++)
848c0197e40Sguenther (*object->dyn.preinit_array[i])(_dl_argc, _dl_argv,
849c0197e40Sguenther environ, &_dl_cb_cb);
85086fa57a2Skettenis }
85186fa57a2Skettenis }
85286fa57a2Skettenis
85386fa57a2Skettenis void
_dl_call_init(elf_object_t * object)8544d11faf9Srahnds _dl_call_init(elf_object_t *object)
8554d11faf9Srahnds {
8560fdecfd0Sguenther _dl_call_init_recurse(object, 1);
8570fdecfd0Sguenther _dl_call_init_recurse(object, 0);
8585509b646Sdrahn }
8594d11faf9Srahnds
860c0197e40Sguenther static void
_dl_relro(elf_object_t * object)861c0197e40Sguenther _dl_relro(elf_object_t *object)
862c0197e40Sguenther {
863c0197e40Sguenther /*
864c0197e40Sguenther * Handle GNU_RELRO
865c0197e40Sguenther */
866c0197e40Sguenther if (object->relro_addr != 0 && object->relro_size != 0) {
867c0197e40Sguenther Elf_Addr addr = object->relro_addr;
868c0197e40Sguenther
869c0197e40Sguenther DL_DEB(("protect RELRO [0x%lx,0x%lx) in %s\n",
870c0197e40Sguenther addr, addr + object->relro_size, object->load_name));
871c0197e40Sguenther _dl_mprotect((void *)addr, object->relro_size, PROT_READ);
872118353eaSderaadt
873118353eaSderaadt /* if library will never be unloaded, RELRO can be immutable */
87407cf23bbSderaadt if (object->nodelete)
875118353eaSderaadt _dl_mimmutable((void *)addr, object->relro_size);
876c0197e40Sguenther }
877c0197e40Sguenther }
878c0197e40Sguenther
8790fdecfd0Sguenther void
_dl_call_init_recurse(elf_object_t * object,int initfirst)8800fdecfd0Sguenther _dl_call_init_recurse(elf_object_t *object, int initfirst)
8810fdecfd0Sguenther {
882d937a926Sguenther struct object_vector vec;
8835c3b452cSguenther int visited_flag = initfirst ? STAT_VISIT_INITFIRST : STAT_VISIT_INIT;
884d937a926Sguenther int i;
8850fdecfd0Sguenther
8865c3b452cSguenther object->status |= visited_flag;
8870fdecfd0Sguenther
888d937a926Sguenther for (vec = object->child_vec, i = 0; i < vec.len; i++) {
889d937a926Sguenther if (vec.vec[i]->status & visited_flag)
8900fdecfd0Sguenther continue;
891d937a926Sguenther _dl_call_init_recurse(vec.vec[i], initfirst);
8920fdecfd0Sguenther }
8930fdecfd0Sguenther
89439b7d201Sderaadt if (object->status & STAT_INIT_DONE)
8954d11faf9Srahnds return;
8964d11faf9Srahnds
8970fdecfd0Sguenther if (initfirst && (object->obj_flags & DF_1_INITFIRST) == 0)
8980fdecfd0Sguenther return;
8990fdecfd0Sguenther
9009ba2c65fSderaadt if (!initfirst) {
901c0197e40Sguenther _dl_relro(object);
9029ba2c65fSderaadt _dl_apply_immutable(object);
9039ba2c65fSderaadt }
904c0197e40Sguenther
905b99706abSmickey if (object->dyn.init) {
906034b0143Sdrahn DL_DEB(("doing ctors obj %p @%p: [%s]\n",
907034b0143Sdrahn object, object->dyn.init, object->load_name));
9085c69b21eSdrahn (*object->dyn.init)();
909b99706abSmickey }
9104d11faf9Srahnds
91186fa57a2Skettenis if (object->dyn.init_array) {
91286fa57a2Skettenis int num = object->dyn.init_arraysz / sizeof(Elf_Addr);
91386fa57a2Skettenis int i;
91486fa57a2Skettenis
91586fa57a2Skettenis DL_DEB(("doing initarray obj %p @%p: [%s]\n",
91686fa57a2Skettenis object, object->dyn.init_array, object->load_name));
91786fa57a2Skettenis for (i = 0; i < num; i++)
918c0197e40Sguenther (*object->dyn.init_array[i])(_dl_argc, _dl_argv,
919c0197e40Sguenther environ, &_dl_cb_cb);
92086fa57a2Skettenis }
92186fa57a2Skettenis
9229ba2c65fSderaadt if (initfirst) {
923c0197e40Sguenther _dl_relro(object);
9249ba2c65fSderaadt _dl_apply_immutable(object);
9259ba2c65fSderaadt }
926c0197e40Sguenther
9274d11faf9Srahnds object->status |= STAT_INIT_DONE;
9284d11faf9Srahnds }
9294d11faf9Srahnds
930ae398163Smiod char *
_dl_getenv(const char * var,char ** env)931bd6b0c7aSdrahn _dl_getenv(const char *var, char **env)
9324d11faf9Srahnds {
9334d11faf9Srahnds const char *ep;
9344d11faf9Srahnds
9354d11faf9Srahnds while ((ep = *env++)) {
9364d11faf9Srahnds const char *vp = var;
9377a154befSart
9384d11faf9Srahnds while (*vp && *vp == *ep) {
9394d11faf9Srahnds vp++;
9404d11faf9Srahnds ep++;
9414d11faf9Srahnds }
94239b7d201Sderaadt if (*vp == '\0' && *ep++ == '=')
9434d11faf9Srahnds return((char *)ep);
9444d11faf9Srahnds }
9454ffea0b8Sdrahn return(NULL);
9464d11faf9Srahnds }
9474ffea0b8Sdrahn
948ae398163Smiod void
_dl_unsetenv(const char * var,char ** env)949bd6b0c7aSdrahn _dl_unsetenv(const char *var, char **env)
950bd6b0c7aSdrahn {
951bd6b0c7aSdrahn char *ep;
952bd6b0c7aSdrahn
953bd6b0c7aSdrahn while ((ep = *env)) {
954bd6b0c7aSdrahn const char *vp = var;
955bd6b0c7aSdrahn
956bd6b0c7aSdrahn while (*vp && *vp == *ep) {
957bd6b0c7aSdrahn vp++;
958bd6b0c7aSdrahn ep++;
959bd6b0c7aSdrahn }
960bd6b0c7aSdrahn if (*vp == '\0' && *ep++ == '=') {
961bd6b0c7aSdrahn char **P;
962bd6b0c7aSdrahn
963bd6b0c7aSdrahn for (P = env;; ++P)
964bd6b0c7aSdrahn if (!(*P = *(P + 1)))
965bd6b0c7aSdrahn break;
96685ee2307Sderaadt } else
967bd6b0c7aSdrahn env++;
968bd6b0c7aSdrahn }
969bd6b0c7aSdrahn }
970ef2daedeSdrahn
971143e5accSguenther static inline void
fixup_sym(struct elf_object * dummy_obj,const char * name,void * addr)972143e5accSguenther fixup_sym(struct elf_object *dummy_obj, const char *name, void *addr)
973143e5accSguenther {
974143e5accSguenther struct sym_res sr;
975143e5accSguenther
976143e5accSguenther sr = _dl_find_symbol(name, SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
977143e5accSguenther NULL, dummy_obj);
978143e5accSguenther if (sr.sym != NULL) {
979143e5accSguenther void *p = (void *)(sr.sym->st_value + sr.obj->obj_base);
980143e5accSguenther if (p != addr) {
981143e5accSguenther DL_DEB(("setting %s %p@%s[%p] from %p\n", name,
982143e5accSguenther p, sr.obj->load_name, (void *)sr.obj, addr));
983143e5accSguenther *(void **)p = *(void **)addr;
984143e5accSguenther }
985143e5accSguenther }
986143e5accSguenther }
987143e5accSguenther
988ef2daedeSdrahn /*
989ef2daedeSdrahn * _dl_fixup_user_env()
990ef2daedeSdrahn *
991ef2daedeSdrahn * Set the user environment so that programs can use the environment
992ef2daedeSdrahn * while running constructors. Specifically, MALLOC_OPTIONS= for malloc()
993ef2daedeSdrahn */
994ef2daedeSdrahn void
_dl_fixup_user_env(void)995ef2daedeSdrahn _dl_fixup_user_env(void)
996ef2daedeSdrahn {
997ef2daedeSdrahn struct elf_object dummy_obj;
998ef2daedeSdrahn
999ef2daedeSdrahn dummy_obj.dyn.symbolic = 0;
1000ef2daedeSdrahn dummy_obj.load_name = "ld.so";
1001143e5accSguenther fixup_sym(&dummy_obj, "environ", &environ);
1002143e5accSguenther fixup_sym(&dummy_obj, "__progname", &__progname);
1003ef2daedeSdrahn }
1004c0197e40Sguenther
1005c0197e40Sguenther const void *
_dl_cb_cb(int version)1006c0197e40Sguenther _dl_cb_cb(int version)
1007c0197e40Sguenther {
1008c0197e40Sguenther DL_DEB(("version %d callbacks requested\n", version));
1009c0197e40Sguenther if (version == 0)
1010c0197e40Sguenther return &callbacks_0;
1011c0197e40Sguenther return NULL;
1012c0197e40Sguenther }
101390273bfbSguenther
101490273bfbSguenther static inline void
unprotect_if_textrel(elf_object_t * object)101590273bfbSguenther unprotect_if_textrel(elf_object_t *object)
101690273bfbSguenther {
101790273bfbSguenther struct load_list *ll;
101890273bfbSguenther
101990273bfbSguenther if (__predict_false(object->dyn.textrel == 1)) {
102090273bfbSguenther for (ll = object->load_list; ll != NULL; ll = ll->next) {
102190273bfbSguenther if ((ll->prot & PROT_WRITE) == 0)
102290273bfbSguenther _dl_mprotect(ll->start, ll->size,
102390273bfbSguenther PROT_READ | PROT_WRITE);
102490273bfbSguenther }
102590273bfbSguenther }
102690273bfbSguenther }
102790273bfbSguenther
102890273bfbSguenther static inline void
reprotect_if_textrel(elf_object_t * object)102990273bfbSguenther reprotect_if_textrel(elf_object_t *object)
103090273bfbSguenther {
103190273bfbSguenther struct load_list *ll;
103290273bfbSguenther
103390273bfbSguenther if (__predict_false(object->dyn.textrel == 1)) {
103490273bfbSguenther for (ll = object->load_list; ll != NULL; ll = ll->next) {
103590273bfbSguenther if ((ll->prot & PROT_WRITE) == 0)
103690273bfbSguenther _dl_mprotect(ll->start, ll->size, ll->prot);
103790273bfbSguenther }
103890273bfbSguenther }
103990273bfbSguenther }
1040b3331980Sguenther
1041b3331980Sguenther static void
_dl_rreloc(elf_object_t * object)1042b3331980Sguenther _dl_rreloc(elf_object_t *object)
1043b3331980Sguenther {
1044b3331980Sguenther const Elf_Relr *reloc, *rend;
1045b3331980Sguenther Elf_Addr loff = object->obj_base;
1046b3331980Sguenther
1047b3331980Sguenther reloc = object->dyn.relr;
1048b3331980Sguenther rend = (const Elf_Relr *)((char *)reloc + object->dyn.relrsz);
1049b3331980Sguenther
1050b3331980Sguenther while (reloc < rend) {
1051b3331980Sguenther Elf_Addr *where;
1052b3331980Sguenther
1053b3331980Sguenther where = (Elf_Addr *)(*reloc + loff);
1054b3331980Sguenther *where++ += loff;
1055b3331980Sguenther
1056b3331980Sguenther for (reloc++; reloc < rend && (*reloc & 1); reloc++) {
1057b3331980Sguenther Elf_Addr bits = *reloc >> 1;
1058b3331980Sguenther
1059b3331980Sguenther Elf_Addr *here = where;
1060b3331980Sguenther while (bits != 0) {
1061b3331980Sguenther if (bits & 1) {
1062b3331980Sguenther *here += loff;
1063b3331980Sguenther }
1064b3331980Sguenther bits >>= 1;
1065b3331980Sguenther here++;
1066b3331980Sguenther }
1067b3331980Sguenther where += (8 * sizeof *reloc) - 1;
1068b3331980Sguenther }
1069b3331980Sguenther }
1070b3331980Sguenther }
1071b3331980Sguenther
10729ba2c65fSderaadt void
_dl_push_range(struct range_vector * v,vaddr_t s,vaddr_t e)10734098e116Sgnezdo _dl_push_range(struct range_vector *v, vaddr_t s, vaddr_t e)
10749ba2c65fSderaadt {
10754098e116Sgnezdo int i = v->count;
10769ba2c65fSderaadt
10774098e116Sgnezdo if (i == nitems(v->slice)) {
10784098e116Sgnezdo _dl_die("too many ranges");
10799ba2c65fSderaadt }
10804098e116Sgnezdo /* Skips the empty ranges (s == e). */
10814098e116Sgnezdo if (s < e) {
10824098e116Sgnezdo v->slice[i].start = s;
10834098e116Sgnezdo v->slice[i].end = e;
10844098e116Sgnezdo v->count++;
10854098e116Sgnezdo } else if (s > e) {
10864098e116Sgnezdo _dl_die("invalid range");
10879ba2c65fSderaadt }
10889ba2c65fSderaadt }
10899ba2c65fSderaadt
10909ba2c65fSderaadt void
_dl_push_range_size(struct range_vector * v,vaddr_t s,vsize_t size)10914098e116Sgnezdo _dl_push_range_size(struct range_vector *v, vaddr_t s, vsize_t size)
10929ba2c65fSderaadt {
10934098e116Sgnezdo _dl_push_range(v, s, s + size);
10949ba2c65fSderaadt }
10959ba2c65fSderaadt
10964098e116Sgnezdo /*
10974098e116Sgnezdo * Finds the truly immutable ranges by taking mutable ones out. Implements
10984098e116Sgnezdo * interval difference of imut and mut. Interval splitting necessitates
10994098e116Sgnezdo * intermediate storage and complex double buffering.
11004098e116Sgnezdo */
11019ba2c65fSderaadt void
_dl_apply_immutable(elf_object_t * object)11029ba2c65fSderaadt _dl_apply_immutable(elf_object_t *object)
11039ba2c65fSderaadt {
11044098e116Sgnezdo struct range_vector acc[2]; /* flips out to avoid copying */
11054098e116Sgnezdo struct addr_range *m, *im;
11064098e116Sgnezdo int i, j, imut, in, out;
11079ba2c65fSderaadt
11089ba2c65fSderaadt if (object->obj_type != OBJTYPE_LIB)
11099ba2c65fSderaadt return;
11109ba2c65fSderaadt
11114098e116Sgnezdo for (imut = 0; imut < object->imut.count; imut++) {
11124098e116Sgnezdo im = &object->imut.slice[imut];
11134098e116Sgnezdo out = 0;
11144098e116Sgnezdo acc[out].count = 0;
11154098e116Sgnezdo _dl_push_range(&acc[out], im->start, im->end);
11169ba2c65fSderaadt
11174098e116Sgnezdo for (i = 0; i < object->mut.count; i++) {
11184098e116Sgnezdo m = &object->mut.slice[i];
11194098e116Sgnezdo in = out;
11204098e116Sgnezdo out = 1 - in;
11214098e116Sgnezdo acc[out].count = 0;
11224098e116Sgnezdo for (j = 0; j < acc[in].count; j++) {
11234098e116Sgnezdo const vaddr_t ms = m->start, me = m->end;
11244098e116Sgnezdo const vaddr_t is = acc[in].slice[j].start,
11254098e116Sgnezdo ie = acc[in].slice[j].end;
11264098e116Sgnezdo if (ie <= ms || me <= is) {
11274098e116Sgnezdo /* is .. ie .. ms .. me -> is .. ie */
11284098e116Sgnezdo /* ms .. me .. is .. ie -> is .. ie */
11294098e116Sgnezdo _dl_push_range(&acc[out], is, ie);
11304098e116Sgnezdo } else if (ms <= is && ie <= me) {
11314098e116Sgnezdo /* PROVIDED: ms < ie && is < me */
11324098e116Sgnezdo /* ms .. is .. ie .. me -> [] */
11339ba2c65fSderaadt ;
11344098e116Sgnezdo } else if (ie <= me) {
11354098e116Sgnezdo /* is .. ms .. ie .. me -> is .. ms */
11364098e116Sgnezdo _dl_push_range(&acc[out], is, ms);
11374098e116Sgnezdo } else if (is < ms) {
11384098e116Sgnezdo /* is .. ms .. me .. ie -> is .. ms */
11394098e116Sgnezdo _dl_push_range(&acc[out], is, ms);
11404098e116Sgnezdo _dl_push_range(&acc[out], me, ie);
11419ba2c65fSderaadt } else {
11424098e116Sgnezdo /* ms .. is .. me .. ie -> me .. ie */
11434098e116Sgnezdo _dl_push_range(&acc[out], me, ie);
11449ba2c65fSderaadt }
11459ba2c65fSderaadt }
11469ba2c65fSderaadt }
11479ba2c65fSderaadt
11489ba2c65fSderaadt /* and now, install immutability for objects */
11494098e116Sgnezdo for (i = 0; i < acc[out].count; i++) {
11504098e116Sgnezdo const struct addr_range *ar = &acc[out].slice[i];
11514098e116Sgnezdo _dl_mimmutable((void *)ar->start, ar->end - ar->start);
11529ba2c65fSderaadt }
11534098e116Sgnezdo
11544098e116Sgnezdo }
11559ba2c65fSderaadt }
1156