diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 16 | ||||
-rw-r--r-- | elf/cache.c | 2 | ||||
-rw-r--r-- | elf/dl-close.c | 10 | ||||
-rw-r--r-- | elf/dl-find_object.c | 8 | ||||
-rw-r--r-- | elf/dl-load.c | 6 | ||||
-rw-r--r-- | elf/dl-open.c | 44 | ||||
-rw-r--r-- | elf/dl-reloc.c | 32 | ||||
-rw-r--r-- | elf/dl-support.c | 3 | ||||
-rw-r--r-- | elf/libc_early_init.c | 3 | ||||
-rw-r--r-- | elf/rtld.c | 107 | ||||
-rw-r--r-- | elf/tst-dlopen-auditdup-auditmod.c | 104 | ||||
-rw-r--r-- | elf/tst-dlopen-auditdup.c | 36 | ||||
-rw-r--r-- | elf/tst-dlopen-auditdupmod.c | 48 | ||||
-rw-r--r-- | elf/tst-rtld-no-malloc-audit.c | 1 | ||||
-rw-r--r-- | elf/tst-rtld-no-malloc-preload.c | 1 | ||||
-rw-r--r-- | elf/tst-rtld-no-malloc.c | 76 |
16 files changed, 396 insertions, 101 deletions
diff --git a/elf/Makefile b/elf/Makefile index 09d77093a7..3a1cb72955 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -414,6 +414,7 @@ tests += \ tst-dlmopen1 \ tst-dlmopen3 \ tst-dlmopen4 \ + tst-dlopen-auditdup \ tst-dlopen-self \ tst-dlopen-tlsmodid \ tst-dlopen-tlsreinit1 \ @@ -452,6 +453,9 @@ tests += \ tst-recursive-tls \ tst-relsort1 \ tst-ro-dynamic \ + tst-rtld-no-malloc \ + tst-rtld-no-malloc-audit \ + tst-rtld-no-malloc-preload \ tst-rtld-run-static \ tst-single_threaded \ tst-single_threaded-pthread \ @@ -865,6 +869,8 @@ modules-names += \ tst-dlmopen-twice-mod1 \ tst-dlmopen-twice-mod2 \ tst-dlmopen1mod \ + tst-dlopen-auditdup-auditmod \ + tst-dlopen-auditdupmod \ tst-dlopen-tlsreinitmod1 \ tst-dlopen-tlsreinitmod2 \ tst-dlopen-tlsreinitmod3 \ @@ -3153,3 +3159,13 @@ $(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so $(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + +tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so +$(objpfx)tst-dlopen-auditdup.out: \ + $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so + +# Reuse an audit module which provides ample debug logging. +tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + +# Any shared object should do. +tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so diff --git a/elf/cache.c b/elf/cache.c index 8a618e11fa..62d681df42 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -820,7 +820,7 @@ struct aux_cache_entry struct aux_cache_entry *next; }; -#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0" +#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-2.0" struct aux_cache_file_entry { diff --git a/elf/dl-close.c b/elf/dl-close.c index 88226245eb..b6f4daac79 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -723,6 +723,11 @@ _dl_close_worker (struct link_map *map, bool force) /* TLS is cleaned up for the unloaded modules. */ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + /* Notify the debugger those objects are finalized and gone. */ + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (unmap_complete, 2, nsid, r); + #ifdef SHARED /* Auditing checkpoint: we have deleted all objects. Also, do not notify auditors of the cleanup of a failed audit module loading attempt. */ @@ -735,11 +740,6 @@ _dl_close_worker (struct link_map *map, bool force) --GL(dl_nns); while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL); - /* Notify the debugger those objects are finalized and gone. */ - r->r_state = RT_CONSISTENT; - _dl_debug_state (); - LIBC_PROBE (unmap_complete, 2, nsid, r); - /* Recheck if we need to retry, release the lock. */ out: if (dl_close_state == rerun) diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c index 449302eda3..ae18b438d3 100644 --- a/elf/dl-find_object.c +++ b/elf/dl-find_object.c @@ -662,6 +662,14 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count) = _dlfo_loaded_mappings[!active_idx]; size_t remaining_to_add = current_used + count; + /* remaining_to_add can be 0 if (current_used + count) wraps, but in practice + this is not possible as it represent counts of link maps. Link maps have + sizes larger than 1 byte, so the sum of any two link map counts will + always fit within a size_t without wrapping around. This check ensures + that target_seg is not erroneously considered potentially NULL by GCC. */ + if (remaining_to_add == 0) + __builtin_unreachable (); + /* Ensure that the new segment chain has enough space. */ { size_t new_allocated diff --git a/elf/dl-load.c b/elf/dl-load.c index ac8e217a7f..335b34c56d 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1931,6 +1931,9 @@ _dl_map_object (struct link_map *loader, const char *name, : "\nfile=%s [%lu]; dynamically loaded by %s [%lu]\n", name, nsid, DSO_FILENAME (loader->l_name), loader->l_ns); + /* Will be true if we found a DSO which is of the other ELF class. */ + bool found_other_class = false; + #ifdef SHARED /* Give the auditing libraries a chance to change the name before we try anything. */ @@ -1948,9 +1951,6 @@ _dl_map_object (struct link_map *loader, const char *name, } #endif - /* Will be true if we found a DSO which is of the other ELF class. */ - bool found_other_class = false; - if (strchr (name, '/') == NULL) { /* Search for NAME in several places. */ diff --git a/elf/dl-open.c b/elf/dl-open.c index 8b4704c09d..ba3c266e6a 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -565,6 +565,14 @@ dl_open_worker_begin (void *a) _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", new->l_name, new->l_ns, new->l_direct_opencount); +#ifdef SHARED + /* No relocation processing on this execution path. But + relocation has not been performed for static + position-dependent executables, so disable the assert for + static linking. */ + assert (new->l_relocated); +#endif + /* If the user requested the object to be in the global namespace but it is not so far, prepare to add it now. This can raise an exception to do a malloc failure. */ @@ -586,10 +594,6 @@ dl_open_worker_begin (void *a) if ((mode & RTLD_GLOBAL) && new->l_global == 0) add_to_global_update (new); - const int r_state __attribute__ ((unused)) - = _dl_debug_update (args->nsid)->r_state; - assert (r_state == RT_CONSISTENT); - return; } @@ -620,17 +624,6 @@ dl_open_worker_begin (void *a) #endif } -#ifdef SHARED - /* Auditing checkpoint: we have added all objects. */ - _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); -#endif - - /* Notify the debugger all new objects are now ready to go. */ - struct r_debug *r = _dl_debug_update (args->nsid); - r->r_state = RT_CONSISTENT; - _dl_debug_state (); - LIBC_PROBE (map_complete, 3, args->nsid, r, new); - _dl_open_check (new); /* Print scope information. */ @@ -677,6 +670,7 @@ dl_open_worker_begin (void *a) created dlmopen namespaces. Do not do this for static dlopen because libc has relocations against ld.so, which may not have been relocated at this point. */ + struct r_debug *r = _dl_debug_update (args->nsid); #ifdef SHARED if (GL(dl_ns)[args->nsid].libc_map != NULL) _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map, @@ -768,6 +762,26 @@ dl_open_worker (void *a) __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + /* Auditing checkpoint and debugger signalling. Do this even on + error, so that dlopen exists with consistent state. */ + if (args->nsid >= 0 || args->map != NULL) + { + Lmid_t nsid = args->map != NULL ? args->map->l_ns : args->nsid; + struct r_debug *r = _dl_debug_update (nsid); +#ifdef SHARED + bool was_not_consistent = r->r_state != RT_CONSISTENT; +#endif + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, nsid, r, args->map); + +#ifdef SHARED + if (was_not_consistent) + /* Avoid redudant/recursive signalling. */ + _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT); +#endif + } + if (__glibc_unlikely (ex.errstring != NULL)) /* Reraise the error. */ _dl_signal_exception (err, &ex, NULL); diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 4bf7aec88b..76d14830dd 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -202,12 +202,9 @@ resolve_map (lookup_t l, struct r_scope_elem *scope[], const ElfW(Sym) **ref, #include "dynamic-link.h" void -_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], - int reloc_mode, int consider_profiling) +_dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[], + int reloc_mode, int consider_profiling) { - if (l->l_relocated) - return; - struct textrels { caddr_t start; @@ -220,8 +217,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], int lazy = reloc_mode & RTLD_LAZY; int skip_ifunc = reloc_mode & __RTLD_NOIFUNC; -#ifdef SHARED bool consider_symbind = false; +#ifdef SHARED /* If we are auditing, install the same handlers we need for profiling. */ if ((reloc_mode & __RTLD_AUDIT) == 0) { @@ -240,9 +237,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], } #elif defined PROF /* Never use dynamic linker profiling for gprof profiling code. */ -# define consider_profiling 0 -#else -# define consider_symbind 0 + consider_profiling = 0; #endif /* If DT_BIND_NOW is set relocate all references in this object. We @@ -300,7 +295,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc); -#ifndef PROF if ((consider_profiling || consider_symbind) && l->l_info[DT_PLTRELSZ] != NULL) { @@ -321,7 +315,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], _dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name); } } -#endif } /* Mark the object so we know this work has been done. */ @@ -342,17 +335,24 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], textrels = textrels->next; } - - /* In case we can protect the data now that the relocations are - done, do it. */ - if (l->l_relro_size != 0) - _dl_protect_relro (l); } +void +_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int reloc_mode, int consider_profiling) +{ + if (l->l_relocated) + return; + _dl_relocate_object_no_relro (l, scope, reloc_mode, consider_profiling); + _dl_protect_relro (l); +} void _dl_protect_relro (struct link_map *l) { + if (l->l_relro_size == 0) + return; + ElfW(Addr) start = ALIGN_DOWN((l->l_addr + l->l_relro_addr), GLRO(dl_pagesize)); diff --git a/elf/dl-support.c b/elf/dl-support.c index 451932dd03..ee590edf93 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -338,8 +338,7 @@ _dl_non_dynamic_init (void) call_function_static_weak (_dl_find_object_init); /* Setup relro on the binary itself. */ - if (_dl_main_map.l_relro_size != 0) - _dl_protect_relro (&_dl_main_map); + _dl_protect_relro (&_dl_main_map); } #ifdef DL_SYSINFO_IMPLEMENTATION diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c index 575b837f8f..20c71fd48b 100644 --- a/elf/libc_early_init.c +++ b/elf/libc_early_init.c @@ -23,6 +23,7 @@ #include <lowlevellock.h> #include <pthread_early_init.h> #include <sys/single_threaded.h> +#include <getrandom-internal.h> #ifdef SHARED _Bool __libc_initial; @@ -43,6 +44,8 @@ __libc_early_init (_Bool initial) __pthread_early_init (); + __getrandom_early_init (initial); + #if ENABLE_ELISION_SUPPORT __lll_elision_init (); #endif diff --git a/elf/rtld.c b/elf/rtld.c index cb6b61d570..b8cc3f605f 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1963,43 +1963,37 @@ dl_main (const ElfW(Phdr) *phdr, if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map)) break; - bool rtld_multiple_ref = false; - if (__glibc_likely (i < main_map->l_searchlist.r_nlist)) - { - /* Some DT_NEEDED entry referred to the interpreter object itself, so - put it back in the list of visible objects. We insert it into the - chain in symbol search order because gdb uses the chain's order as - its symbol search order. */ - rtld_multiple_ref = true; + /* Insert the link map for the dynamic loader into the chain in + symbol search order because gdb uses the chain's order as its + symbol search order. */ - GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; - if (__glibc_likely (state.mode == rtld_mode_normal)) - { - GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist - ? main_map->l_searchlist.r_list[i + 1] - : NULL); + GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; + if (__glibc_likely (state.mode == rtld_mode_normal)) + { + GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist + ? main_map->l_searchlist.r_list[i + 1] + : NULL); #ifdef NEED_DL_SYSINFO_DSO - if (GLRO(dl_sysinfo_map) != NULL - && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map) - && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map)) - GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map); + if (GLRO(dl_sysinfo_map) != NULL + && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map) + && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map)) + GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map); #endif - } - else - /* In trace mode there might be an invisible object (which we - could not find) after the previous one in the search list. - In this case it doesn't matter much where we put the - interpreter object, so we just initialize the list pointer so - that the assertion below holds. */ - GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next; - - assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next); - GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map); - if (GL(dl_rtld_map).l_next != NULL) - { - assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev); - GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map); - } + } + else + /* In trace mode there might be an invisible object (which we + could not find) after the previous one in the search list. + In this case it doesn't matter much where we put the + interpreter object, so we just initialize the list pointer so + that the assertion below holds. */ + GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next; + + assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next); + GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map); + if (GL(dl_rtld_map).l_next != NULL) + { + assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev); + GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map); } /* Now let us see whether all libraries are available in the @@ -2327,35 +2321,30 @@ dl_main (const ElfW(Phdr) *phdr, /* Make sure no new search directories have been added. */ assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs)); - if (rtld_multiple_ref) - { - /* There was an explicit ref to the dynamic linker as a shared lib. - Re-relocate ourselves with user-controlled symbol definitions. + /* Set up the object lookup structures. */ + _dl_find_object_init (); - We must do this after TLS initialization in case after this - re-relocation, we might call a user-supplied function - (e.g. calloc from _dl_relocate_object) that uses TLS data. */ + /* Likewise for the locking implementation. */ + __rtld_mutex_init (); - /* Set up the object lookup structures. */ - _dl_find_object_init (); + /* Re-relocate ourselves with user-controlled symbol definitions. */ - /* The malloc implementation has been relocated, so resolving - its symbols (and potentially calling IFUNC resolvers) is safe - at this point. */ - __rtld_malloc_init_real (main_map); + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); - /* Likewise for the locking implementation. */ - __rtld_mutex_init (); + _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0); - RTLD_TIMING_VAR (start); - rtld_timer_start (&start); + /* The malloc implementation has been relocated, so resolving + its symbols (and potentially calling IFUNC resolvers) is safe + at this point. */ + __rtld_malloc_init_real (main_map); - /* Mark the link map as not yet relocated again. */ - GL(dl_rtld_map).l_relocated = 0; - _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); + if (GL(dl_rtld_map).l_relro_size != 0) + _dl_protect_relro (&GL(dl_rtld_map)); - rtld_timer_accum (&relocate_time, start); - } + rtld_timer_accum (&relocate_time, start); + } /* Relocation is complete. Perform early libc initialization. This is the initial libc, even if audit modules have been loaded with @@ -2369,9 +2358,6 @@ dl_main (const ElfW(Phdr) *phdr, _dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */ _dl_sysdep_start_cleanup (); - /* Auditing checkpoint: we have added all objects. */ - _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT); - /* Notify the debugger all new objects are now ready to go. We must re-get the address since by now the variable might be in another object. */ r = _dl_debug_update (LM_ID_BASE); @@ -2379,6 +2365,9 @@ dl_main (const ElfW(Phdr) *phdr, _dl_debug_state (); LIBC_PROBE (init_complete, 2, LM_ID_BASE, r); + /* Auditing checkpoint: we have added all objects. */ + _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT); + #if defined USE_LDCONFIG && !defined MAP_COPY /* We must munmap() the cache file. */ _dl_unload_cache (); diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c new file mode 100644 index 0000000000..270a595ec4 --- /dev/null +++ b/elf/tst-dlopen-auditdup-auditmod.c @@ -0,0 +1,104 @@ +/* Auditor that opens again an object that just has been opened. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <link.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +unsigned int +la_version (unsigned int v) +{ + return LAV_CURRENT; +} + +static bool trigger_on_la_activity; + +unsigned int +la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) +{ + printf ("info: la_objopen: \"%s\"\n", map->l_name); + if (strstr (map->l_name, "/tst-dlopen-auditdupmod.so") != NULL) + trigger_on_la_activity = true; + return 0; +} + +void +la_activity (uintptr_t *cookie, unsigned int flag) +{ + static unsigned int calls; + ++calls; + printf ("info: la_activity: call %u (flag %u)\n", calls, flag); + fflush (stdout); + if (trigger_on_la_activity) + { + /* Avoid triggering on the dlmopen call below. */ + static bool recursion; + if (recursion) + return; + recursion = true; + + puts ("info: about to dlmopen tst-dlopen-auditdupmod.so"); + fflush (stdout); + void *handle = dlmopen (LM_ID_BASE, "tst-dlopen-auditdupmod.so", + RTLD_NOW); + if (handle == NULL) + { + printf ("error: dlmopen: %s\n", dlerror ()); + fflush (stdout); + _exit (1); + } + + /* Check that the constructor has not run. Running the + constructor would require constructing its dependencies, but + the constructor call that triggered this auditing activity + has not completed, and constructors among the dependencies + may not be able to deal with that. */ + int *status = dlsym (handle, "auditdupmod_status"); + if (status == NULL) + { + printf ("error: dlsym: %s\n", dlerror ()); + fflush (stdout); + _exit (1); + } + printf ("info: auditdupmod_status == %d\n", *status); + if (*status != 0) + { + puts ("error: auditdupmod_status == 0 expected"); + fflush (stdout); + _exit (1); + } + /* Checked in the destructor and the main program. */ + ++*status; + printf ("info: auditdupmod_status == %d\n", *status); + + /* Check that the module has been relocated. */ + int **status_address = dlsym (handle, "auditdupmod_status_address"); + if (status_address == NULL || *status_address != status) + { + puts ("error: invalid auditdupmod_status address in" + " tst-dlopen-auditdupmod.so"); + fflush (stdout); + _exit (1); + } + + fflush (stdout); + } +} diff --git a/elf/tst-dlopen-auditdup.c b/elf/tst-dlopen-auditdup.c new file mode 100644 index 0000000000..d022c58ae3 --- /dev/null +++ b/elf/tst-dlopen-auditdup.c @@ -0,0 +1,36 @@ +/* Test that recursive dlopen from auditor works (bug 31986). + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <support/check.h> +#include <support/xdlfcn.h> + +static int +do_test (void) +{ + puts ("info: about to dlopen tst-dlopen-auditdupmod.so"); + fflush (stdout); + void *handle = xdlopen ("tst-dlopen-auditdupmod.so", RTLD_NOW); + int *status = xdlsym (handle, "auditdupmod_status"); + printf ("info: auditdupmod_status == %d (from main)\n", *status); + TEST_COMPARE (*status, 2); + xdlclose (handle); + return 0; +} + +#include <support/test-driver.c> diff --git a/elf/tst-dlopen-auditdupmod.c b/elf/tst-dlopen-auditdupmod.c new file mode 100644 index 0000000000..59b7e21daa --- /dev/null +++ b/elf/tst-dlopen-auditdupmod.c @@ -0,0 +1,48 @@ +/* Directly opened test module that gets reopened from the auditor. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <support/xdlfcn.h> + +int auditdupmod_status; + +/* Used to check for successful relocation processing. */ +int *auditdupmod_status_address = &auditdupmod_status; + +static void __attribute__ ((constructor)) +init (void) +{ + ++auditdupmod_status; + printf ("info: tst-dlopen-auditdupmod.so constructor called (status %d)\n", + auditdupmod_status); +} + +static void __attribute__ ((destructor)) +fini (void) +{ + /* The tst-dlopen-auditdup-auditmod.so auditor incremented + auditdupmod_status. */ + printf ("info: tst-dlopen-auditdupmod.so destructor called (status %d)\n", + auditdupmod_status); + if (auditdupmod_status != 2) + { + puts ("error: auditdupmod_status == 2 expected"); + exit (1); + } +} diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c new file mode 100644 index 0000000000..a028377ad1 --- /dev/null +++ b/elf/tst-rtld-no-malloc-audit.c @@ -0,0 +1 @@ +#include "tst-rtld-no-malloc.c" diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c new file mode 100644 index 0000000000..a028377ad1 --- /dev/null +++ b/elf/tst-rtld-no-malloc-preload.c @@ -0,0 +1 @@ +#include "tst-rtld-no-malloc.c" diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c new file mode 100644 index 0000000000..5f24d4bd72 --- /dev/null +++ b/elf/tst-rtld-no-malloc.c @@ -0,0 +1,76 @@ +/* Test that program loading does not call malloc. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + + +#include <string.h> +#include <unistd.h> + +static void +print (const char *s) +{ + const char *end = s + strlen (s); + while (s < end) + { + ssize_t ret = write (STDOUT_FILENO, s, end - s); + if (ret <= 0) + _exit (2); + s += ret; + } +} + +static void __attribute__ ((noreturn)) +unexpected_call (const char *function) +{ + print ("error: unexpected call to "); + print (function); + print ("\n"); + _exit (1); +} + +/* These are the malloc functions implement in elf/dl-minimal.c. */ + +void +free (void *ignored) +{ + unexpected_call ("free"); +} + +void * +calloc (size_t ignored1, size_t ignored2) +{ + unexpected_call ("calloc"); +} + +void * +malloc (size_t ignored) +{ + unexpected_call ("malloc"); +} + +void * +realloc (void *ignored1, size_t ignored2) +{ + unexpected_call ("realloc"); +} + +int +main (void) +{ + /* Do not use the test wrapper, to avoid spurious malloc calls from it. */ + return 0; +} |