1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-18 15:30:21 +00:00

rtld: implement _dl_iterate_phdr_locked

Some sanitizers need to be able to use dl_iterate_phdr() after stopping
the rest of the process, but it's very hard to do so reliably as a
non-participant in the main logic of the program.

Introduce _dl_iterate_phdr_locked to bypass the locking that's normally
required for dl_iterate_phdr() and slap some scary warning on it.  It
will remain undocumented and probably shouldn't be used for anything
else.

Reviewed by:	kib
Differential Revision:	https://reviews.freebsd.org/D47558
This commit is contained in:
Kyle Evans 2024-11-13 19:33:59 -06:00
parent 4b202f4faf
commit 1426fd6cff
4 changed files with 46 additions and 4 deletions

View File

@ -464,6 +464,7 @@ FBSDprivate_1.0 {
/* needed by thread libraries */
__thr_jtable;
_dl_iterate_phdr_locked;
_pthread_atfork;
_pthread_attr_destroy;
_pthread_attr_getdetachstate;

View File

@ -203,9 +203,10 @@ dl_init_phdr_info(void)
}
#endif
#pragma weak dl_iterate_phdr
#pragma weak _dl_iterate_phdr_locked
int
dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
_dl_iterate_phdr_locked(
int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
void *data __unused)
{
#if defined IN_LIBDL
@ -227,14 +228,29 @@ dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
_once(&dl_phdr_info_once, dl_init_phdr_info);
ti.ti_module = 1;
ti.ti_offset = 0;
mutex_lock(&dl_phdr_info_lock);
phdr_info.dlpi_tls_data = __tls_get_addr(&ti);
ret = callback(&phdr_info, sizeof(phdr_info), data);
mutex_unlock(&dl_phdr_info_lock);
return (ret);
#endif
}
#pragma weak dl_iterate_phdr
int
dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
void *data __unused)
{
int error;
#if !defined(IN_LIBDL) && !defined(PIC)
mutex_lock(&dl_phdr_info_lock);
#endif
error = _dl_iterate_phdr_locked(callback, data);
#if !defined(IN_LIBDL) && !defined(PIC)
mutex_unlock(&dl_phdr_info_lock);
#endif
return (error);
}
#pragma weak fdlopen
void *
fdlopen(int fd __unused, int mode __unused)

View File

@ -27,6 +27,7 @@ FBSD_1.8 {
};
FBSDprivate_1.0 {
_dl_iterate_phdr_locked;
_rtld_thread_init;
_rtld_allocate_tls;
_rtld_free_tls;

View File

@ -252,6 +252,7 @@ int dladdr(const void *, Dl_info *) __exported;
void dllockinit(void *, void *(*)(void *), void (*)(void *), void (*)(void *),
void (*)(void *), void (*)(void *), void (*)(void *)) __exported;
int dlinfo(void *, int , void *) __exported;
int _dl_iterate_phdr_locked(__dl_iterate_hdr_callback, void *) __exported;
int dl_iterate_phdr(__dl_iterate_hdr_callback, void *) __exported;
int _rtld_addr_phdr(const void *, struct dl_phdr_info *) __exported;
int _rtld_get_stack_prot(void) __exported;
@ -4201,6 +4202,29 @@ rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info)
phdr_info->dlpi_subs = obj_loads - obj_count;
}
/*
* It's completely UB to actually use this, so extreme caution is advised. It's
* probably not what you want.
*/
int
_dl_iterate_phdr_locked(__dl_iterate_hdr_callback callback, void *param)
{
struct dl_phdr_info phdr_info;
Obj_Entry *obj;
int error;
for (obj = globallist_curr(TAILQ_FIRST(&obj_list)); obj != NULL;
obj = globallist_next(obj)) {
rtld_fill_dl_phdr_info(obj, &phdr_info);
error = callback(&phdr_info, sizeof(phdr_info), param);
if (error != 0)
return (error);
}
rtld_fill_dl_phdr_info(&obj_rtld, &phdr_info);
return (callback(&phdr_info, sizeof(phdr_info), param));
}
int
dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param)
{