xref: /openbsd/libexec/ld.so/dlfcn.c (revision 771fbea0)
1 /*	$OpenBSD: dlfcn.c,v 1.107 2021/06/02 07:29:03 semarie 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 <nlist.h>
33 #include <link.h>
34 #include <dlfcn.h>
35 #include <unistd.h>
36 
37 #include "syscall.h"
38 #include "archdep.h"
39 #include "resolve.h"
40 #include "sod.h"
41 
42 int _dl_errno;
43 static int _dl_tracelib;
44 
45 static int _dl_real_close(void *handle);
46 static lock_cb *_dl_thread_fnc = NULL;
47 static elf_object_t *obj_from_addr(const void *addr);
48 
49 void *
50 dlopen(const char *libname, int flags)
51 {
52 	elf_object_t *object;
53 	lock_cb *cb;
54 	int failed = 0;
55 	int obj_flags;
56 
57 	if (flags & ~(RTLD_TRACE|RTLD_LAZY|RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE)) {
58 		_dl_errno = DL_INVALID_MODE;
59 		return NULL;
60 	}
61 
62 	if (libname == NULL)
63 		return RTLD_DEFAULT;
64 
65 	if ((flags & RTLD_TRACE) == RTLD_TRACE) {
66 		_dl_traceld = 1;
67 		_dl_tracelib = 1;
68 	}
69 
70 	DL_DEB(("dlopen: loading: %s\n", libname));
71 
72 	cb = _dl_thread_kern_stop();
73 
74 	if (_dl_debug_map && _dl_debug_map->r_brk) {
75 		_dl_debug_map->r_state = RT_ADD;
76 		(*((void (*)(void))_dl_debug_map->r_brk))();
77 	}
78 
79 	_dl_loading_object = NULL;
80 
81 	obj_flags = (flags & RTLD_NOW ? DF_1_NOW : 0)
82 	    | (flags & RTLD_GLOBAL ? DF_1_GLOBAL : 0);
83 	object = _dl_load_shlib(libname, _dl_objects, OBJTYPE_DLO, obj_flags);
84 	if (object == 0) {
85 		DL_DEB(("dlopen: failed to open %s\n", libname));
86 		failed = 1;
87 		goto loaded;
88 	}
89 
90 	if (flags & RTLD_NODELETE)
91 		object->obj_flags |= DF_1_NODELETE;
92 
93 	_dl_link_dlopen(object);
94 
95 	if (OBJECT_REF_CNT(object) > 1) {
96 		_dl_handle_nodelete(object);
97 
98 		/* if opened but grpsym_vec has not been filled in */
99 		if (object->grpsym_vec.len == 0)
100 			_dl_cache_grpsym_list_setup(object);
101 		goto loaded;
102 	}
103 
104 	/* this add_object should not be here, XXX */
105 	_dl_add_object(object);
106 
107 	DL_DEB(("head [%s]\n", object->load_name ));
108 
109 	if ((failed = _dl_load_dep_libs(object, obj_flags, 0)) == 1) {
110 		_dl_real_close(object);
111 		object = NULL;
112 		_dl_errno = DL_CANT_LOAD_OBJ;
113 	} else {
114 		int err;
115 		DL_DEB(("tail %s\n", object->load_name ));
116 		if (_dl_traceld) {
117 			_dl_show_objects();
118 			_dl_unload_shlib(object);
119 			_dl_exit(0);
120 		}
121 		err = _dl_rtld(object);
122 		if (err != 0) {
123 			_dl_real_close(object);
124 			_dl_errno = DL_CANT_LOAD_OBJ;
125 			object = NULL;
126 			failed = 1;
127 		} else {
128 			_dl_call_init(object);
129 		}
130 	}
131 
132 loaded:
133 	_dl_loading_object = NULL;
134 
135 	if (_dl_debug_map && _dl_debug_map->r_brk) {
136 		_dl_debug_map->r_state = RT_CONSISTENT;
137 		(*((void (*)(void))_dl_debug_map->r_brk))();
138 	}
139 
140 	_dl_thread_kern_go(cb);
141 
142 	DL_DEB(("dlopen: %s: done (%s).\n", libname,
143 	    failed ? "failed" : "success"));
144 
145 	return((void *)object);
146 }
147 
148 void *
149 dlsym(void *handle, const char *name)
150 {
151 	elf_object_t	*object;
152 	elf_object_t	*dynobj;
153 	struct sym_res	sr;
154 	int		flags;
155 	Elf_Addr	addr;
156 
157 	if (handle == NULL || handle == RTLD_NEXT ||
158 	    handle == RTLD_SELF || handle == RTLD_DEFAULT) {
159 		void *retaddr;
160 
161 		retaddr = __builtin_return_address(0);	/* __GNUC__ only */
162 
163 		if ((object = obj_from_addr(retaddr)) == NULL) {
164 			_dl_errno = DL_CANT_FIND_OBJ;
165 			return(0);
166 		}
167 
168 		if (handle == RTLD_NEXT)
169 			flags = SYM_SEARCH_NEXT|SYM_PLT;
170 		else if (handle == RTLD_SELF)
171 			flags = SYM_SEARCH_SELF|SYM_PLT;
172 		else if (handle == RTLD_DEFAULT)
173 			flags = SYM_SEARCH_ALL|SYM_PLT;
174 		else
175 			flags = SYM_DLSYM|SYM_PLT;
176 
177 	} else {
178 		object = (elf_object_t *)handle;
179 		flags = SYM_DLSYM|SYM_PLT;
180 
181 		dynobj = _dl_objects;
182 		while (dynobj && dynobj != object)
183 			dynobj = dynobj->next;
184 
185 		if (!dynobj || object != dynobj) {
186 			_dl_errno = DL_INVALID_HANDLE;
187 			return(0);
188 		}
189 	}
190 
191 	sr = _dl_find_symbol(name, flags|SYM_NOWARNNOTFOUND, NULL, object);
192 	if (sr.sym == NULL) {
193 		_dl_errno = DL_NO_SYMBOL;
194 		return NULL;
195 	}
196 
197 	addr = sr.obj->obj_base + sr.sym->st_value;
198 #ifdef __hppa__
199 	if (ELF_ST_TYPE(sr.sym->st_info) == STT_FUNC)
200 		addr = _dl_md_plabel(addr, sr.obj->dyn.pltgot);
201 #endif
202 	DL_DEB(("dlsym: %s in %s: %p\n",
203 	    name, object->load_name, (void *)addr));
204 	return (void *)addr;
205 }
206 
207 int
208 dlctl(void *handle, int command, void *data)
209 {
210 	int retval;
211 
212 	switch (command) {
213 	case DL_SETTHREADLCK:
214 		DL_DEB(("dlctl: _dl_thread_fnc set to %p\n", data));
215 		_dl_thread_fnc = data;
216 		retval = 0;
217 		break;
218 	case DL_SETBINDLCK:
219 		/* made superfluous by kbind */
220 		retval = 0;
221 		break;
222 	case DL_REFERENCE:
223 	{
224 		elf_object_t *obj;
225 
226 		obj = obj_from_addr(data);
227 		if (obj == NULL) {
228 			_dl_errno = DL_CANT_FIND_OBJ;
229 			retval = -1;
230 			break;
231 		}
232 		if ((obj->status & STAT_NODELETE) == 0) {
233 			obj->opencount++;
234 			obj->status |= STAT_NODELETE;
235 		}
236 		retval = 0;
237 		break;
238 	}
239 	case 0x20:
240 		_dl_show_objects();
241 		retval = 0;
242 		break;
243 	case 0x21:
244 	{
245 		struct object_vector vec;
246 		struct dep_node *n, *m;
247 		elf_object_t *obj;
248 		int i;
249 
250 		_dl_printf("Load Groups:\n");
251 
252 		TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) {
253 			obj = n->data;
254 			_dl_printf("%s\n", obj->load_name);
255 
256 			_dl_printf("  children\n");
257 			for (vec = obj->child_vec, i = 0; i < vec.len; i++)
258 				_dl_printf("\t[%s]\n", vec.vec[i]->load_name);
259 
260 			_dl_printf("  grpref\n");
261 			TAILQ_FOREACH(m, &obj->grpref_list, next_sib)
262 				_dl_printf("\t[%s]\n", m->data->load_name);
263 			_dl_printf("\n");
264 		}
265 		retval = 0;
266 		break;
267 	}
268 	default:
269 		_dl_errno = DL_INVALID_CTL;
270 		retval = -1;
271 		break;
272 	}
273 	return (retval);
274 }
275 __strong_alias(_dlctl,dlctl);
276 
277 int
278 dlclose(void *handle)
279 {
280 	lock_cb *cb;
281 	int retval;
282 
283 	if (handle == RTLD_DEFAULT)
284 		return 0;
285 
286 	cb = _dl_thread_kern_stop();
287 
288 	if (_dl_debug_map && _dl_debug_map->r_brk) {
289 		_dl_debug_map->r_state = RT_DELETE;
290 		(*((void (*)(void))_dl_debug_map->r_brk))();
291 	}
292 
293 	retval = _dl_real_close(handle);
294 
295 	if (_dl_debug_map && _dl_debug_map->r_brk) {
296 		_dl_debug_map->r_state = RT_CONSISTENT;
297 		(*((void (*)(void))_dl_debug_map->r_brk))();
298 	}
299 	_dl_thread_kern_go(cb);
300 	return (retval);
301 }
302 
303 int
304 _dl_real_close(void *handle)
305 {
306 	elf_object_t	*object;
307 	elf_object_t	*dynobj;
308 
309 	object = (elf_object_t *)handle;
310 
311 	dynobj = _dl_objects;
312 	while (dynobj && dynobj != object)
313 		dynobj = dynobj->next;
314 
315 	if (!dynobj || object != dynobj) {
316 		_dl_errno = DL_INVALID_HANDLE;
317 		return (1);
318 	}
319 
320 	if (object->opencount == 0) {
321 		_dl_errno = DL_INVALID_HANDLE;
322 		return (1);
323 	}
324 
325 	object->opencount--;
326 	_dl_notify_unload_shlib(object);
327 	_dl_run_all_dtors();
328 	_dl_unload_shlib(object);
329 	_dl_cleanup_objects();
330 	return (0);
331 }
332 
333 
334 /*
335  * Return a character string describing the last dl... error occurred.
336  */
337 char *
338 dlerror(void)
339 {
340 	char *errmsg;
341 
342 	switch (_dl_errno) {
343 	case 0:	/* NO ERROR */
344 		errmsg = NULL;
345 		break;
346 	case DL_NOT_FOUND:
347 		errmsg = "File not found";
348 		break;
349 	case DL_CANT_OPEN:
350 		errmsg = "Can't open file";
351 		break;
352 	case DL_NOT_ELF:
353 		errmsg = "File not an ELF object";
354 		break;
355 	case DL_CANT_OPEN_REF:
356 		errmsg = "Can't open referenced object";
357 		break;
358 	case DL_CANT_MMAP:
359 		errmsg = "Can't map ELF object";
360 		break;
361 	case DL_INVALID_HANDLE:
362 		errmsg = "Invalid handle";
363 		break;
364 	case DL_NO_SYMBOL:
365 		errmsg = "Unable to resolve symbol";
366 		break;
367 	case DL_INVALID_CTL:
368 		errmsg = "Invalid dlctl() command";
369 		break;
370 	case DL_NO_OBJECT:
371 		errmsg = "No shared object contains address";
372 		break;
373 	case DL_CANT_FIND_OBJ:
374 		errmsg = "Cannot determine caller's shared object";
375 		break;
376 	case DL_CANT_LOAD_OBJ:
377 		errmsg = "Cannot load specified object";
378 		break;
379 	case DL_INVALID_MODE:
380 		errmsg = "Invalid mode";
381 		break;
382 	default:
383 		errmsg = "Unknown error";
384 	}
385 
386 	_dl_errno = 0;
387 	return (errmsg);
388 }
389 
390 static void
391 _dl_tracefmt(int fd, elf_object_t *object, const char *fmt1, const char *fmt2,
392     const char *objtypename)
393 {
394 	const char *fmt;
395 	int i;
396 
397 	fmt = object->sod.sod_library ? fmt1 : fmt2;
398 
399 	for (i = 0; fmt[i]; i++) {
400 		if (fmt[i] != '%' && fmt[i] != '\\') {
401 			_dl_dprintf(fd, "%c", fmt[i]);
402 			continue;
403 		}
404 		if (fmt[i] == '%') {
405 			i++;
406 			switch (fmt[i]) {
407 			case '\0':
408 				return;
409 			case '%':
410 				_dl_dprintf(fd, "%c", '%');
411 				break;
412 			case 'A':
413 				_dl_dprintf(fd, "%s", _dl_traceprog ?
414 				    _dl_traceprog : "");
415 				break;
416 			case 'a':
417 				_dl_dprintf(fd, "%s", __progname);
418 				break;
419 			case 'e':
420 				_dl_dprintf(fd, "%lX",
421 				    (void *)(object->load_base +
422 				    object->load_size));
423 				break;
424 			case 'g':
425 				_dl_dprintf(fd, "%d", object->grprefcount);
426 				break;
427 			case 'm':
428 				_dl_dprintf(fd, "%d", object->sod.sod_major);
429 				break;
430 			case 'n':
431 				_dl_dprintf(fd, "%d", object->sod.sod_minor);
432 				break;
433 			case 'O':
434 				_dl_dprintf(fd, "%d", object->opencount);
435 				break;
436 			case 'o':
437 				_dl_dprintf(fd, "%s", object->sod.sod_name);
438 				break;
439 			case 'p':
440 				_dl_dprintf(fd, "%s", object->load_name);
441 				break;
442 			case 'r':
443 				_dl_dprintf(fd, "%d", object->refcount);
444 				break;
445 			case 't':
446 				_dl_dprintf(fd, "%s", objtypename);
447 				break;
448 			case 'x':
449 				_dl_dprintf(fd, "%lX", object->load_base);
450 				break;
451 			}
452 		}
453 		if (fmt[i] == '\\') {
454 			i++;
455 			switch (fmt[i]) {
456 			case '\0':
457 				return;
458 			case 'n':
459 				_dl_dprintf(fd, "%c", '\n');
460 				break;
461 			case 'r':
462 				_dl_dprintf(fd, "%c", '\r');
463 				break;
464 			case 't':
465 				_dl_dprintf(fd, "%c", '\t');
466 				break;
467 			default:
468 				_dl_dprintf(fd, "%c", fmt[i]);
469 				break;
470 			}
471 		}
472 	}
473 }
474 
475 void
476 _dl_show_objects(void)
477 {
478 	elf_object_t *object;
479 	char *objtypename;
480 	int outputfd;
481 	char *pad;
482 	const char *fmt1, *fmt2;
483 
484 	object = _dl_objects;
485 	if (_dl_traceld)
486 		outputfd = STDOUT_FILENO;
487 	else
488 		outputfd = STDERR_FILENO;
489 
490 	if (sizeof(long) == 8)
491 		pad = "        ";
492 	else
493 		pad = "";
494 
495 	fmt1 = _dl_tracefmt1 ? _dl_tracefmt1 :
496 	    "\t%x %e %t %O    %r   %g      %p\n";
497 	fmt2 = _dl_tracefmt2 ? _dl_tracefmt2 :
498 	    "\t%x %e %t %O    %r   %g      %p\n";
499 
500 	if (_dl_tracefmt1 == NULL && _dl_tracefmt2 == NULL)
501 		_dl_dprintf(outputfd, "\tStart   %s End     %s Type  Open Ref GrpRef Name\n",
502 		    pad, pad);
503 
504 	if (_dl_tracelib) {
505 		for (; object != NULL; object = object->next)
506 			if (object->obj_type == OBJTYPE_LDR) {
507 				object = object->next;
508 				break;
509 			}
510 	}
511 
512 	for (; object != NULL; object = object->next) {
513 		switch (object->obj_type) {
514 		case OBJTYPE_LDR:
515 			objtypename = "ld.so";
516 			break;
517 		case OBJTYPE_EXE:
518 			objtypename = "exe  ";
519 			break;
520 		case OBJTYPE_LIB:
521 			objtypename = "rlib ";
522 			break;
523 		case OBJTYPE_DLO:
524 			objtypename = "dlib ";
525 			break;
526 		default:
527 			objtypename = "?????";
528 			break;
529 		}
530 		_dl_tracefmt(outputfd, object, fmt1, fmt2, objtypename);
531 	}
532 }
533 
534 lock_cb *
535 _dl_thread_kern_stop(void)
536 {
537 	lock_cb *cb = _dl_thread_fnc;
538 
539 	if (cb != NULL)
540 		(*cb)(0);
541 	return cb;
542 }
543 
544 void
545 _dl_thread_kern_go(lock_cb *cb)
546 {
547 	if (cb != NULL)
548 		(*cb)(1);
549 }
550 
551 int
552 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *data),
553 	void *data)
554 {
555 	elf_object_t *object;
556 	struct dl_phdr_info info;
557 	int retval = -1;
558 
559 	for (object = _dl_objects; object != NULL; object = object->next) {
560 		if (object->phdrp == NULL)
561 			continue;
562 
563 		info.dlpi_addr = object->obj_base;
564 		info.dlpi_name = object->load_name;
565 		info.dlpi_phdr = object->phdrp;
566 		info.dlpi_phnum = object->phdrc;
567 		retval = callback(&info, sizeof (struct dl_phdr_info), data);
568 		if (retval)
569 			break;
570 	}
571 
572 	return retval;
573 }
574 
575 static elf_object_t *
576 obj_from_addr(const void *addr)
577 {
578 	elf_object_t *dynobj;
579 	Elf_Phdr *phdrp;
580 	int phdrc;
581 	Elf_Addr start;
582 	int i;
583 
584 	for (dynobj = _dl_objects; dynobj != NULL; dynobj = dynobj->next) {
585 		if (dynobj->phdrp == NULL)
586 			continue;
587 
588 		phdrp = dynobj->phdrp;
589 		phdrc = dynobj->phdrc;
590 
591 		for (i = 0; i < phdrc; i++, phdrp++) {
592 			if (phdrp->p_type == PT_LOAD) {
593 				start = dynobj->obj_base + phdrp->p_vaddr;
594 				if ((Elf_Addr)addr >= start &&
595 				    (Elf_Addr)addr < start + phdrp->p_memsz)
596 					return dynobj;
597 			}
598 		}
599 	}
600 
601 	return NULL;
602 }
603 
604 int
605 dladdr(const void *addr, Dl_info *info)
606 {
607 	const elf_object_t *object;
608 	const Elf_Sym *sym;
609 	void *symbol_addr;
610 	u_int32_t symoffset;
611 
612 	object = obj_from_addr(addr);
613 
614 	if (object == NULL) {
615 		_dl_errno = DL_NO_OBJECT;
616 		return 0;
617 	}
618 
619 	info->dli_fname = (char *)object->load_name;
620 	info->dli_fbase = (void *)object->load_base;
621 	info->dli_sname = NULL;
622 	info->dli_saddr = NULL;
623 
624 	/*
625 	 * Walk the symbol list looking for the symbol whose address is
626 	 * closest to the address sent in.
627 	 */
628 	for (symoffset = 0; symoffset < object->nchains; symoffset++) {
629 		sym = object->dyn.symtab + symoffset;
630 
631 		/*
632 		 * For skip the symbol if st_shndx is either SHN_UNDEF or
633 		 * SHN_COMMON.
634 		 */
635 		if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
636 			continue;
637 
638 		/*
639 		 * If the symbol is greater than the specified address, or if
640 		 * it is further away from addr than the current nearest
641 		 * symbol, then reject it.
642 		 */
643 		symbol_addr = (void *)(object->obj_base + sym->st_value);
644 		if (symbol_addr > addr || symbol_addr < info->dli_saddr)
645 			continue;
646 
647 		/* Update our idea of the nearest symbol. */
648 		info->dli_sname = object->dyn.strtab + sym->st_name;
649 		info->dli_saddr = symbol_addr;
650 
651 		/* Exact match? */
652 		if (info->dli_saddr == addr)
653 			break;
654 	}
655 
656 	return 1;
657 }
658