xref: /netbsd-src/libexec/ld.elf_so/rtld.c (revision ace896fac114f559f7469472324fbe68bbe378e5)
1 /*	$NetBSD: rtld.c,v 1.5 1997/10/08 08:55:37 mrg Exp $	*/
2 
3 /*
4  * Copyright 1996 John D. Polstra.
5  * Copyright 1996 Matt Thomas <matt@3am-software.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by John Polstra.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Dynamic linker for ELF.
36  *
37  * John Polstra <jdp@polstra.com>.
38  */
39 
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <sys/param.h>
49 #include <sys/mman.h>
50 #include <dirent.h>
51 
52 #include <ctype.h>
53 
54 #include <dlfcn.h>
55 #include "debug.h"
56 #include "rtld.h"
57 
58 #include "sysident.h"
59 
60 #ifndef RTLD_NOW
61 #define	RTLD_NOW	(RTLD_LAZY + 1)
62 #endif
63 
64 /*
65  * Debugging support.
66  */
67 
68 typedef void (*funcptr)(void);
69 
70 /*
71  * Function declarations.
72  */
73 static void _rtld_init(caddr_t);
74 static void _rtld_exit(void);
75 
76 /*
77  * Data declarations.
78  */
79 static char *error_message;	/* Message for dlopen(), or NULL */
80 
81 struct r_debug _rtld_debug;	/* for GDB; */
82 bool _rtld_trust;		/* False for setuid and setgid programs */
83 Obj_Entry *_rtld_objlist;	/* Head of linked list of shared objects */
84 Obj_Entry **_rtld_objtail;	/* Link field of last object in list */
85 Obj_Entry *_rtld_objmain;	/* The main program shared object */
86 Obj_Entry _rtld_objself;	/* The dynamic linker shared object */
87 char _rtld_path[] = _PATH_RTLD;
88 
89 Search_Path *_rtld_paths;
90 /*
91  * Global declarations normally provided by crt0.
92  */
93 char *__progname;
94 char **environ;
95 
96 #ifdef OLD_GOT
97 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
98 #else
99 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
100 extern Elf_Dyn _DYNAMIC;
101 #endif
102 
103 static void
104 _rtld_call_fini_functions(
105     Obj_Entry *first)
106 {
107     Obj_Entry *obj;
108 
109     for (obj = first;  obj != NULL;  obj = obj->next)
110 	if (obj->fini != NULL)
111 	    (*obj->fini)();
112 }
113 
114 static void
115 _rtld_call_init_functions(
116     Obj_Entry *first)
117 {
118     if (first != NULL) {
119 	_rtld_call_init_functions(first->next);
120 	if (first->init != NULL)
121 	    (*first->init)();
122     }
123 }
124 
125 /*
126  * Initialize the dynamic linker.  The argument is the address at which
127  * the dynamic linker has been mapped into memory.  The primary task of
128  * this function is to relocate the dynamic linker.
129  */
130 static void
131 _rtld_init(
132     caddr_t mapbase)
133 {
134     _rtld_add_paths(&_rtld_paths, RTLD_DEFAULT_LIBRARY_PATH);
135 
136     /* Conjure up an Obj_Entry structure for the dynamic linker. */
137 
138     _rtld_objself.path = _rtld_path;
139     _rtld_objself.rtld = true;
140     _rtld_objself.mapbase = mapbase;
141     _rtld_objself.relocbase = mapbase;
142     _rtld_objself.pltgot = NULL;
143 #ifdef OLD_GOT
144     _rtld_objself.dynamic = (Elf_Dyn *) _GLOBAL_OFFSET_TABLE_[0];
145 #else
146     _rtld_objself.dynamic = &_DYNAMIC;
147 #endif
148 
149     _rtld_digest_dynamic(&_rtld_objself);
150 #ifdef __alpha__
151 /* XXX XXX XXX */
152 _rtld_objself.pltgot = NULL;
153 #endif
154     assert(_rtld_objself.needed == NULL);
155     assert(!_rtld_objself.textrel);
156 
157     /* Set up the _rtld_objlist pointer, so that rtld symbols can be found. */
158     _rtld_objlist = &_rtld_objself;
159 
160     _rtld_relocate_objects(&_rtld_objself, true);
161 
162     /* Make the object list empty again. */
163     _rtld_objlist = NULL;
164     _rtld_objtail = &_rtld_objlist;
165 
166     _rtld_debug.r_brk = _rtld_debug_state;
167     _rtld_debug.r_state = RT_CONSISTENT;
168 }
169 
170 /*
171  * Cleanup procedure.  It will be called (by the atexit() mechanism) just
172  * before the process exits.
173  */
174 static void
175 _rtld_exit(void)
176 {
177     dbg("rtld_exit()");
178 
179     _rtld_call_fini_functions(_rtld_objlist->next);
180 }
181 
182 /*
183  * Main entry point for dynamic linking.  The argument is the stack
184  * pointer.  The stack is expected to be laid out as described in the
185  * SVR4 ABI specification, Intel 386 Processor Supplement.  Specifically,
186  * the stack pointer points to a word containing ARGC.  Following that
187  * in the stack is a null-terminated sequence of pointers to argument
188  * strings.  Then comes a null-terminated sequence of pointers to
189  * environment strings.  Finally, there is a sequence of "auxiliary
190  * vector" entries.
191  *
192  * This function returns the entry point for the main program in %eax,
193  * and the dynamic linker's exit procedure in %edx.  We accomplish this
194  * by declaring the return value to have the 64-bit type "long long".
195  * Such values are returned with their most-significant 32 bits in %edx,
196  * and their least-significant 32 bits in %eax.
197  */
198 Elf_Addr _rtld(Elf_Word *);
199 
200 Elf_Addr
201 _rtld(
202     Elf_Word *sp)
203 {
204     const AuxInfo *aux_info[AUX_count];
205     int i = 0;
206     char **env;
207     const AuxInfo *aux;
208     const AuxInfo *auxp;
209     Elf_Word * const osp = sp;
210     bool bind_now = 0;
211     const char *ld_bind_now;
212     const char **argv;
213 
214     /*
215      * On entry, the dynamic linker itself has not been relocated yet.
216      * Be very careful not to reference any global data until after
217      * _rtld_init has returned.  It is OK to reference file-scope statics
218      * and string constants, and to call static and global functions.
219      */
220     /* Find the auxiliary vector on the stack. */
221     /* first Elf_Word reserved to address of exit routine */
222 #ifdef RTLD_DEBUG
223     xprintf("sp = %p, argc = %d, argv = %p <%s>\n", sp, sp[2], &sp[3], sp[3]);
224     xprintf("got is at %p, dynamic is at %p\n", _GLOBAL_OFFSET_TABLE_, &_DYNAMIC);
225     debug = 1;
226     xprintf("_ctype_ is %p\n", _ctype_);
227 #endif
228 
229     sp += 2;		/* skip over return argument space */
230     argv = (const char **) &sp[1];
231     sp += sp[0] + 2;	/* Skip over argc, arguments, and NULL terminator */
232     env = (char **) sp;
233     while (*sp++ != 0) {	/* Skip over environment, and NULL terminator */
234 #ifdef RTLD_DEBUG
235 	xprintf("env[%d] = %p\n", i++, sp[-1]);
236 #endif
237     }
238     aux = (const AuxInfo *) sp;
239 
240     /* Digest the auxiliary vector. */
241     for (i = 0;  i < AUX_count;  ++i)
242 	aux_info[i] = NULL;
243     for (auxp = aux;  auxp->au_id != AUX_null;  ++auxp) {
244 	if (auxp->au_id < AUX_count)
245 	    aux_info[auxp->au_id] = auxp;
246     }
247 
248     /* Initialize and relocate ourselves. */
249     assert(aux_info[AUX_base] != NULL);
250     _rtld_init((caddr_t) aux_info[AUX_base]->au_v);
251 
252 #ifdef RTLD_DEBUG
253     xprintf("_ctype_ is %p\n", _ctype_);
254 #endif
255     if (aux_info[AUX_debug] != NULL)	/* Set debugging level */
256 	debug = aux_info[AUX_debug]->au_v;
257 
258     __progname = _rtld_objself.path;
259     environ = env;
260 
261     _rtld_trust = geteuid() == getuid() && getegid() == getgid();
262 
263     ld_bind_now = getenv("LD_BIND_NOW");
264     if (ld_bind_now != NULL && *ld_bind_now != '\0')
265 	bind_now = true;
266     if (_rtld_trust) {
267 	const char *ld_debug = getenv("LD_DEBUG");
268 	if (ld_debug != NULL && *ld_debug != '\0')
269 	    debug = 1;
270 	_rtld_add_paths(&_rtld_paths, getenv("LD_LIBRARY_PATH"));
271     }
272 
273     dbg("%s is initialized, base address = %p", __progname,
274 	(caddr_t) aux_info[AUX_base]->au_v);
275 
276     /*
277      * Load the main program, or process its program header if it is
278      * already loaded.
279      */
280     if (aux_info[AUX_execfd] != NULL) {	/* Load the main program. */
281 	int fd = aux_info[AUX_execfd]->au_v;
282 	dbg("loading main program");
283 	_rtld_objmain = _rtld_map_object(argv[0], fd);
284 	close(fd);
285 	if (_rtld_objmain == NULL)
286 	    _rtld_die();
287     } else {				/* Main program already loaded. */
288 	const Elf_Phdr *phdr;
289 	int phnum;
290 	caddr_t entry;
291 
292 	dbg("processing main program's program header");
293 	assert(aux_info[AUX_phdr] != NULL);
294 	phdr = (const Elf_Phdr *) aux_info[AUX_phdr]->au_v;
295 	assert(aux_info[AUX_phnum] != NULL);
296 	phnum = aux_info[AUX_phnum]->au_v;
297 	assert(aux_info[AUX_phent] != NULL);
298 	assert(aux_info[AUX_phent]->au_v == sizeof(Elf_Phdr));
299 	assert(aux_info[AUX_entry] != NULL);
300 	entry = (caddr_t) aux_info[AUX_entry]->au_v;
301 	_rtld_objmain = _rtld_digest_phdr(phdr, phnum, entry);
302     }
303 
304     _rtld_objmain->path = xstrdup("main program");
305     _rtld_objmain->mainprog = true;
306     _rtld_digest_dynamic(_rtld_objmain);
307 
308     _rtld_linkmap_add(_rtld_objmain);
309     _rtld_linkmap_add(&_rtld_objself);
310 
311     /* Link the main program into the list of objects. */
312     *_rtld_objtail = _rtld_objmain;
313     _rtld_objtail = &_rtld_objmain->next;
314     ++_rtld_objmain->refcount;
315 
316     dbg("loading needed objects");
317     if (_rtld_load_needed_objects(_rtld_objmain) == -1)
318 	_rtld_die();
319 
320     dbg("relocating objects");
321     if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1)
322 	_rtld_die();
323 
324     dbg("doing copy relocations");
325     if (_rtld_do_copy_relocations(_rtld_objmain) == -1)
326 	_rtld_die();
327 
328     dbg("calling _init functions");
329     _rtld_call_init_functions(_rtld_objmain->next);
330 
331     dbg("transferring control to program entry point = %p",
332 	_rtld_objmain->entry);
333 
334     /* Return with the entry point and the exit procedure in at the top of
335      * stack.
336      */
337 
338     _rtld_debug_state();	/* say hello to gdb! */
339 
340     ((void **) osp)[0] = _rtld_exit;
341     ((void **) osp)[1] = _rtld_objmain;
342     return (Elf_Addr) _rtld_objmain->entry;
343 }
344 
345 void
346 _rtld_die(
347     void)
348 {
349     const char *msg = _rtld_dlerror();
350 
351     if (msg == NULL)
352 	msg = "Fatal error";
353     xerrx(1, "%s\n", msg);
354 }
355 
356 static Obj_Entry *
357 _rtld_dlcheck(
358     void *handle)
359 {
360     Obj_Entry *obj;
361 
362     for (obj = _rtld_objlist;  obj != NULL;  obj = obj->next)
363 	if (obj == (Obj_Entry *) handle)
364 	    break;
365 
366     if (obj == NULL || obj->dl_refcount == 0) {
367 	xwarnx("Invalid shared object handle %p", handle);
368 	return NULL;
369     }
370     return obj;
371 }
372 
373 static void
374 _rtld_unref_object_dag(
375     Obj_Entry *root)
376 {
377     assert(root->refcount != 0);
378     --root->refcount;
379     if (root->refcount == 0) {
380 	const Needed_Entry *needed;
381 
382 	for (needed = root->needed;  needed != NULL;  needed = needed->next)
383 	    _rtld_unref_object_dag(needed->obj);
384     }
385 }
386 
387 int
388 _rtld_dlclose(
389     void *handle)
390 {
391     Obj_Entry *root = _rtld_dlcheck(handle);
392 
393     if (root == NULL)
394 	return -1;
395 
396     _rtld_debug.r_state = RT_DELETE;
397     _rtld_debug_state();
398 
399     --root->dl_refcount;
400     _rtld_unref_object_dag(root);
401     if (root->refcount == 0) {	/* We are finished with some objects. */
402 	Obj_Entry *obj;
403 	Obj_Entry **linkp;
404 
405 	/* Finalize objects that are about to be unmapped. */
406 	for (obj = _rtld_objlist->next;  obj != NULL;  obj = obj->next)
407 	    if (obj->refcount == 0 && obj->fini != NULL)
408 		(*obj->fini)();
409 
410 	/* Unmap all objects that are no longer referenced. */
411 	linkp = &_rtld_objlist->next;
412 	while((obj = *linkp) != NULL) {
413 	    if (obj->refcount == 0) {
414 		munmap(obj->mapbase, obj->mapsize);
415 		free(obj->path);
416 		while(obj->needed != NULL) {
417 		    Needed_Entry *needed = obj->needed;
418 		    obj->needed = needed->next;
419 		    free(needed);
420 		}
421 		_rtld_linkmap_delete(obj);
422 		*linkp = obj->next;
423 		free(obj);
424 	    } else
425 		linkp = &obj->next;
426 	}
427     }
428 
429     _rtld_debug.r_state = RT_CONSISTENT;
430     _rtld_debug_state();
431 
432     return 0;
433 }
434 
435 char *
436 _rtld_dlerror(
437     void)
438 {
439     char *msg = error_message;
440     error_message = NULL;
441     return msg;
442 }
443 
444 void *
445 _rtld_dlopen(
446     const char *name,
447     int mode)
448 {
449     Obj_Entry **old_obj_tail = _rtld_objtail;
450     Obj_Entry *obj = NULL;
451 
452     _rtld_debug.r_state = RT_ADD;
453     _rtld_debug_state();
454 
455     if (name == NULL) {
456 	obj = _rtld_objmain;
457     } else {
458 	char *path = _rtld_find_library(name, NULL);
459 	if (path != NULL)
460 	    obj = _rtld_load_object(path);
461     }
462 
463     if (obj != NULL) {
464 	++obj->dl_refcount;
465 	if (*old_obj_tail != NULL) {		/* We loaded something new. */
466 	    assert(*old_obj_tail == obj);
467 
468 	    /* FIXME - Clean up properly after an error. */
469 	    if (_rtld_load_needed_objects(obj) == -1) {
470 		--obj->dl_refcount;
471 		obj = NULL;
472 	    } else if (_rtld_relocate_objects(obj, mode == RTLD_NOW) == -1) {
473 		--obj->dl_refcount;
474 		obj = NULL;
475 	    } else {
476 		_rtld_call_init_functions(obj);
477 	    }
478 	}
479     }
480 
481     _rtld_debug.r_state = RT_CONSISTENT;
482     _rtld_debug_state();
483 
484     return obj;
485 }
486 
487 void *
488 _rtld_dlsym(
489     void *handle,
490     const char *name)
491 {
492     const Obj_Entry *obj = _rtld_dlcheck(handle);
493     const Elf_Sym *def;
494     const Obj_Entry *defobj;
495 
496     if (obj == NULL)
497 	return NULL;
498 
499     /*
500      * FIXME - This isn't correct.  The search should include the whole
501      * DAG rooted at the given object.
502      */
503     def = _rtld_find_symdef(_rtld_objlist, 0, name, obj, &defobj, false);
504     if (def != NULL)
505 	return defobj->relocbase + def->st_value;
506 
507     _rtld_error("Undefined symbol \"%s\"", name);
508     return NULL;
509 }
510 
511 /*
512  * Error reporting function.  Use it like printf.  If formats the message
513  * into a buffer, and sets things up so that the next call to dlerror()
514  * will return the message.
515  */
516 void
517 _rtld_error(
518     const char *fmt, ...)
519 {
520     static char buf[512];
521     va_list ap;
522 
523     va_start(ap, fmt);
524     xvsnprintf(buf, sizeof buf, fmt, ap);
525     error_message = buf;
526     va_end(ap);
527 }
528 
529 void
530 _rtld_debug_state(
531     void)
532 {
533     /* do nothing */
534 }
535 
536 void
537 _rtld_linkmap_add(
538     Obj_Entry *obj)
539 {
540     struct link_map *l = &obj->linkmap;
541     struct link_map *prev;
542 
543     obj->linkmap.l_name = obj->path;
544     obj->linkmap.l_addr = obj->mapbase;
545     obj->linkmap.l_ld = obj->dynamic;
546 
547     if (_rtld_debug.r_map == NULL) {
548 	_rtld_debug.r_map = l;
549 	return;
550     }
551 
552     for (prev = _rtld_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
553 	;
554     l->l_prev = prev;
555     prev->l_next = l;
556     l->l_next = NULL;
557 }
558 
559 void
560 _rtld_linkmap_delete(
561     Obj_Entry *obj)
562 {
563     struct link_map *l = &obj->linkmap;
564 
565     if (l->l_prev == NULL) {
566 	if ((_rtld_debug.r_map = l->l_next) != NULL)
567 	    l->l_next->l_prev = NULL;
568 	return;
569     }
570 
571     if ((l->l_prev->l_next = l->l_next) != NULL)
572 	l->l_next->l_prev = l->l_prev;
573 }
574 
575