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