@@ -44,8 +44,8 @@ install-lib-ldscripts = libdl.so
$(inst_libdir)/libdl.so:
ifeq ($(build-shared),yes)
-routines += dlopenold
-shared-only-routines := dlopenold
+routines += dlopenold dlaudit
+shared-only-routines := dlopenold dlaudit
endif
ifeq (yes,$(build-shared))
@@ -28,6 +28,9 @@ libc {
dlsym;
dlvsym;
}
+ GLIBC_2.38 {
+ dlload_audit_module;
+ }
GLIBC_PRIVATE {
__libc_dlerror_result;
_dlerror_run;
new file mode 100644
@@ -0,0 +1,62 @@
+/* Load an audit module at run time.
+ Copyright (C) 1995-2023 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 <libintl.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <shlib-compat.h>
+
+struct dlload_am_args
+{
+ /* The arguments for dlload_am_doit. */
+ const char *file;
+ int flags;
+ /* The return value of dlload_am_doit. */
+ void *new;
+};
+
+static void
+dlload_am_doit (void *a)
+{
+ struct dlload_am_args *args = (struct dlload_am_args *) a;
+
+ if (args->flags)
+ _dl_signal_error (0, NULL, NULL, _("invalid flags parameter"));
+
+ args->new = GLRO(dlload_audit_module) (args->file, args->flags);
+}
+
+static void *
+dlload_am_implementation (const char *file, int flags)
+{
+ struct dlload_am_args args;
+ args.file = file;
+ args.flags = flags;
+
+ return _dlerror_run (dlload_am_doit, &args) ? NULL : args.new;
+}
+
+void *
+___dlload_audit_module (const char *file, int flags)
+{
+ return dlload_am_implementation (file, flags);
+}
+versioned_symbol (libc, ___dlload_audit_module, dlload_audit_module,
+ GLIBC_2_38);
@@ -822,6 +822,7 @@ modules-names += \
tst-deep1mod1 \
tst-deep1mod2 \
tst-deep1mod3 \
+ tst-dynauditmod \
tst-dl_find_object-mod1 \
tst-dl_find_object-mod2 \
tst-dl_find_object-mod3 \
@@ -1058,6 +1059,7 @@ ifeq (yes,$(build-shared))
tests += \
tst-ifunc-fault-bindnow \
tst-ifunc-fault-lazy \
+ tst-loadaudit \
# tests
# Note: sysdeps/x86_64/ifuncmain8.c uses ifuncmain8.
tests-internal += \
@@ -2352,6 +2354,10 @@ $(objpfx)tst-audit28.out: $(objpfx)tst-auditmod28.so
$(objpfx)tst-auditmod28.so: $(libsupport)
tst-audit28-ENV = LD_AUDIT=$(objpfx)tst-auditmod28.so
+$(objpfx)tst-loadaudit.out: $(objpfx)tst-dynauditmod.so \
+ $(objpfx)tst-audit18mod.so
+tst-loadaudit-ARGS = -- $(host-test-program-cmd)
+
# tst-sonamemove links against an older implementation of the library.
LDFLAGS-tst-sonamemove-linkmod1.so = \
-Wl,--version-script=tst-sonamemove-linkmod1.map \
@@ -27,8 +27,8 @@
void
_dl_audit_activity_map (struct link_map *l, int action)
{
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->activity != NULL)
afct->activity (&link_map_audit_state (l, cnt)->cookie, action);
@@ -43,8 +43,7 @@ _dl_audit_activity_nsid (Lmid_t nsid, int action)
does not give us a way to signal LA_ACT_CONSISTENT for it because the
first loaded module is used to identify the namespace. */
struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
- if (__glibc_likely (GLRO(dl_naudit) == 0)
- || head == NULL || head->l_auditing)
+ if (__glibc_likely (head == NULL || head->l_naudit == 0 || head->l_auditing))
return;
_dl_audit_activity_map (head, action);
@@ -56,8 +55,8 @@ _dl_audit_objsearch (const char *name, struct link_map *l, unsigned int code)
if (l == NULL || l->l_auditing || code == 0)
return name;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->objsearch != NULL)
{
@@ -75,11 +74,11 @@ _dl_audit_objsearch (const char *name, struct link_map *l, unsigned int code)
void
_dl_audit_objopen (struct link_map *l, Lmid_t nsid)
{
- if (__glibc_likely (GLRO(dl_naudit) == 0))
+ if (__glibc_likely (l->l_naudit == 0))
return;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->objopen != NULL)
{
@@ -95,12 +94,12 @@ _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
void
_dl_audit_objclose (struct link_map *l)
{
- if (__glibc_likely (GLRO(dl_naudit) == 0)
+ if (__glibc_likely (l->l_naudit == 0)
|| GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
return;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->objclose != NULL)
{
@@ -116,11 +115,11 @@ _dl_audit_objclose (struct link_map *l)
void
_dl_audit_preinit (struct link_map *l)
{
- if (__glibc_likely (GLRO(dl_naudit) == 0))
+ if (__glibc_likely (l->l_naudit == 0))
return;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->preinit != NULL)
afct->preinit (&link_map_audit_state (l, cnt)->cookie);
@@ -145,8 +144,8 @@ _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, void **value,
ElfW(Sym) sym = *ref;
sym.st_value = (ElfW(Addr)) *value;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
struct auditstate *match_audit = link_map_audit_state (l, cnt);
struct auditstate *result_audit = link_map_audit_state (result, cnt);
@@ -212,9 +211,9 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
const char *strtab2 = (const void *) D_PTR (result, l_info[DT_STRTAB]);
unsigned int flags = 0;
- struct audit_ifaces *afct = GLRO(dl_audit);
+ struct audit_ifaces *afct = GL(dl_audit);
uintptr_t new_value = (uintptr_t) sym.st_value;
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
/* XXX Check whether both DSOs must request action or only one */
struct auditstate *l_state = link_map_audit_state (l, cnt);
@@ -267,7 +266,7 @@ _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result,
DL_FIXUP_VALUE_TYPE *value, void *regs, long int *framesize)
{
/* Don't do anything if no auditor wants to intercept this call. */
- if (GLRO(dl_naudit) == 0
+ if (l->l_naudit == 0
|| (reloc_result->enterexit & LA_SYMB_NOPLTENTER))
return;
@@ -290,8 +289,8 @@ _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result,
/* Keep track of overwritten addresses. */
unsigned int flags = reloc_result->flags;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->ARCH_LA_PLTENTER != NULL
&& (reloc_result->enterexit
@@ -363,8 +362,8 @@ _dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
l_info[DT_STRTAB]);
const char *symname = strtab + sym.st_name;
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < l->l_naudit; ++cnt)
{
if (afct->ARCH_LA_PLTEXIT != NULL
&& (reloc_result->enterexit
@@ -129,7 +129,7 @@ _dl_fini (void)
}
#ifdef SHARED
- if (! do_audit && GLRO(dl_naudit) > 0)
+ if (! do_audit && GL(dl_naudit) > 0)
{
do_audit = 1;
goto again;
@@ -1032,6 +1032,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
l->l_addr = l->l_real->l_addr;
l->l_ld = l->l_real->l_ld;
+ /* Do not call audit when this lm closes. */
+ l->l_naudit = 0;
+
/* No need to bump the refcount of the real object, ld.so will
never be unloaded. */
__close_nocancel (fd);
@@ -1607,7 +1610,7 @@ open_verify (const char *name, int fd,
#ifdef SHARED
/* Give the auditing libraries a chance. */
- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ if (__glibc_unlikely (GL(dl_naudit) > 0))
{
const char *original_name = name;
name = _dl_audit_objsearch (name, loader, whatcode);
@@ -2001,7 +2004,7 @@ _dl_map_object (struct link_map *loader, const char *name,
#ifdef SHARED
/* Give the auditing libraries a chance to change the name before we
try anything. */
- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ if (__glibc_unlikely (GL(dl_naudit) > 0))
{
const char *before = name;
name = _dl_audit_objsearch (name, loader, LA_SER_ORIG);
@@ -77,7 +77,7 @@ _dl_new_object (char *realname, const char *libname, int type,
naudit = DL_NNS;
}
else
- naudit = GLRO (dl_naudit);
+ naudit = GL (dl_naudit);
#endif
size_t libname_len = strlen (libname) + 1;
@@ -136,6 +136,8 @@ _dl_new_object (char *realname, const char *libname, int type,
new->l_ns = nsid;
#ifdef SHARED
+ /* GL(dl_naudit) is a current value and naudit is maximum value. */
+ new->l_naudit = GL (dl_naudit);
for (unsigned int cnt = 0; cnt < naudit; ++cnt)
/* No need to initialize bindflags due to calloc. */
link_map_audit_state (new, cnt)->cookie = (uintptr_t) new;
@@ -222,8 +222,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
/* If we are auditing, install the same handlers we need for profiling. */
if ((reloc_mode & __RTLD_AUDIT) == 0)
{
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ struct audit_ifaces *afct = GL(dl_audit);
+ for (unsigned int cnt = 0; cnt < GL(dl_naudit); ++cnt)
{
/* Profiling is needed only if PLT hooks are provided. */
if (afct->ARCH_LA_PLTENTER != NULL
@@ -313,7 +313,7 @@ _dl_profile_fixup (
/* Auditing checkpoint: we have a new binding. Provide the
auditing libraries the possibility to change the value and
tell us whether further auditing is wanted. */
- if (defsym != NULL && GLRO(dl_naudit) > 0)
+ if (defsym != NULL && GL(dl_naudit) > 0)
_dl_audit_symbind (l, reloc_result, defsym, &value, result);
#endif
@@ -50,7 +50,7 @@ _dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
/* Auditing checkpoint: we have a new binding. Provide the
auditing libraries the possibility to change the value and
tell us whether further auditing is wanted. */
- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ if (__glibc_unlikely (GL(dl_naudit) > 0))
{
if (match == NULL)
match = _dl_sym_find_caller_link_map (caller);
@@ -148,7 +148,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
skip_ifunc);
#if defined SHARED
if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
- && GLRO(dl_naudit) > 0)
+ && GL(dl_naudit) > 0)
{
struct link_map *sym_map
= RESOLVE_MAP (map, scope, &sym, rversion,
@@ -193,7 +193,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
skip_ifunc);
# if defined SHARED
if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
- && GLRO(dl_naudit) > 0)
+ && GL(dl_naudit) > 0)
{
struct link_map *sym_map
= RESOLVE_MAP (map, scope, &sym,
@@ -151,6 +151,10 @@ static const char *audit_list_next (struct audit_list *);
/* Initialize *STATE with the defaults. */
static void dl_main_state_init (struct dl_main_state *state);
+/* Loads audit module. */
+static void *
+_dlload_audit_module (const char *name, int flags);
+
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
@@ -272,7 +276,7 @@ audit_list_next (struct audit_list *list)
}
}
-/* Count audit modules before they are loaded so GLRO(dl_naudit)
+/* Count audit modules before they are loaded so GL(dl_naudit)
is not yet usable. */
static size_t
audit_list_count (struct audit_list *list)
@@ -375,6 +379,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_error_free = _dl_error_free,
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
._dl_libc_freeres = __rtld_libc_freeres,
+ ._dlload_audit_module = _dlload_audit_module,
};
/* If we would use strong_alias here the compiler would see a
non-hidden definition. This would undo the effect of the previous
@@ -930,8 +935,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
}
/* Load one audit module. */
-static void
-load_audit_module (const char *name, struct audit_ifaces **last_audit)
+static void *
+_load_audit_module (const char *name, const void *caller_dlopen,
+ struct audit_ifaces **last_audit)
{
int original_tls_idx = GL(dl_tls_max_dtv_idx);
@@ -946,7 +952,7 @@ load_audit_module (const char *name, struct audit_ifaces **last_audit)
if (__glibc_unlikely (err_str != NULL))
{
report_audit_module_load_error (name, err_str, malloced);
- return;
+ return NULL;
}
struct lookup_args largs;
@@ -957,7 +963,7 @@ load_audit_module (const char *name, struct audit_ifaces **last_audit)
{
unload_audit_module (dlmargs.map, original_tls_idx);
report_audit_module_load_error (name, err_str, malloced);
- return;
+ return NULL;
}
unsigned int (*laversion) (unsigned int) = largs.result;
@@ -977,7 +983,7 @@ load_audit_module (const char *name, struct audit_ifaces **last_audit)
file=%s [%lu]; audit interface function la_version returned zero; ignored.\n",
dlmargs.map->l_name, dlmargs.map->l_ns);
unload_audit_module (dlmargs.map, original_tls_idx);
- return;
+ return NULL;
}
if (!_dl_audit_check_version (lav))
@@ -986,7 +992,7 @@ file=%s [%lu]; audit interface function la_version returned zero; ignored.\n",
ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n",
name, lav, LAV_CURRENT);
unload_audit_module (dlmargs.map, original_tls_idx);
- return;
+ return NULL;
}
enum { naudit_ifaces = 8 };
@@ -1032,19 +1038,53 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
/* Now append the new auditing interface to the list. */
newp->ifaces.next = NULL;
if (*last_audit == NULL)
- *last_audit = GLRO(dl_audit) = &newp->ifaces;
+ *last_audit = GL(dl_audit) = &newp->ifaces;
else
*last_audit = (*last_audit)->next = &newp->ifaces;
/* The dynamic linker link map is statically allocated, so the
cookie in _dl_new_object has not happened. */
- link_map_audit_state (&GL (dl_rtld_map), GLRO (dl_naudit))->cookie
+ link_map_audit_state (&GL (dl_rtld_map), GL (dl_naudit))->cookie
= (intptr_t) &GL (dl_rtld_map);
- ++GLRO(dl_naudit);
+ ++GL(dl_naudit);
/* Mark the DSO as being used for auditing. */
dlmargs.map->l_auditing = 1;
+ return dlmargs.map;
+}
+
+static void
+load_audit_module (const char *name, struct audit_ifaces **last_audit)
+{
+ if (_load_audit_module (name, dl_main, last_audit))
+ {
+ struct link_map *l;
+
+ /* Global audit module can audit all existing objects. */
+ for (l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l; l = l->l_next)
+ l->l_naudit++;
+ }
+}
+
+static void *
+_dlload_audit_module (const char *name, int flags)
+{
+ struct link_map *l;
+ struct audit_ifaces *last_audit = GL(dl_audit);
+
+ /* Find last audit list entry. */
+ while (last_audit && last_audit->next)
+ last_audit = last_audit->next;
+ l = _load_audit_module (name, _dlload_audit_module, &last_audit);
+ if (l)
+ {
+ /* These are not allowed for dynamically-loaded auditors. */
+ last_audit->symbind = NULL;
+ last_audit->ARCH_LA_PLTENTER = NULL;
+ last_audit->ARCH_LA_PLTEXIT = NULL;
+ }
+ return l;
}
/* Load all audit modules. */
@@ -1063,7 +1103,7 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
/* Notify audit modules of the initially loaded modules (the main
program and the dynamic linker itself). */
- if (GLRO(dl_naudit) > 0)
+ if (GL(dl_naudit) > 0)
{
_dl_audit_objopen (main_map, LM_ID_BASE);
_dl_audit_objopen (&GL(dl_rtld_map), LM_ID_BASE);
@@ -1822,7 +1862,7 @@ dl_main (const ElfW(Phdr) *phdr,
/* The count based on audit strings may overestimate the number
of audit modules that got loaded, but not underestimate. */
- assert (GLRO(dl_naudit) <= naudit);
+ assert (GL(dl_naudit) <= naudit);
}
/* Keep track of the currently loaded modules to count how many
new file mode 100644
@@ -0,0 +1,190 @@
+/* Audit mod for dlload_audit_module.
+ Copyright (C) 2021-2023 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 <link.h>
+#include <assert.h>
+
+/* la_objopen() sets the cookie to this value. Other call-backs check
+ * the value to see if la_objopen() was not somehow skipped. */
+#define TST_COOKIE_VAL 12
+
+unsigned int
+la_version (unsigned int version)
+{
+ fprintf (stderr, "%s\n", __func__);
+ return LAV_CURRENT;
+}
+
+char *
+la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ fprintf (stderr, "%s\n", __func__);
+ assert (*cookie == TST_COOKIE_VAL);
+ return (char *) name;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+ struct link_map *map = (void *) *cookie;
+ fprintf (stderr, "%s\n", __func__);
+ if (*cookie != TST_COOKIE_VAL)
+ fprintf (stderr, "%s\n", map->l_name);
+ *cookie = TST_COOKIE_VAL;
+}
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
+{
+ fprintf (stderr, "%s\n", __func__);
+ fprintf (stderr, "%s\n", map->l_name);
+ *cookie = TST_COOKIE_VAL;
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+}
+
+unsigned int
+la_objclose (uintptr_t *cookie)
+{
+ fprintf (stderr, "%s\n", __func__);
+ if (*cookie != TST_COOKIE_VAL)
+ {
+ struct link_map *map = (void *) *cookie;
+ fprintf (stderr, "%s\n", map->l_name);
+ }
+ assert (*cookie == TST_COOKIE_VAL);
+ return 0;
+}
+
+void
+la_preinit (uintptr_t *cookie)
+{
+ fprintf (stderr, "%s\n", __func__);
+ assert (*cookie == TST_COOKIE_VAL);
+}
+
+uintptr_t
+#if __ELF_NATIVE_CLASS == 32
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+#else
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+#endif
+{
+ fprintf (stderr, "%s\n", __func__);
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return sym->st_value;
+}
+
+#ifdef __i386__
+Elf32_Addr
+la_i86_gnu_pltenter (Elf32_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_i86_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return sym->st_value;
+}
+#elif defined __x86_64__
+Elf64_Addr
+la_x86_64_gnu_pltenter (Elf64_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_x86_64_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return sym->st_value;
+}
+#elif defined __sparc__ && !defined __arch64__
+Elf32_Addr
+la_sparc32_gnu_pltenter (Elf32_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_sparc32_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return sym->st_value;
+}
+#elif defined __sparc__ && defined __arch64__
+Elf64_Addr
+la_sparc64_gnu_pltenter (Elf64_Sym *sym __attribute__ ((unused)),
+ unsigned int ndx __attribute__ ((unused)),
+ uintptr_t *refcook, uintptr_t *defcook,
+ La_sparc64_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return sym->st_value;
+}
+#elif !defined HAVE_ARCH_PLTENTER
+# warning "pltenter for architecture not supported"
+#endif
+
+#ifdef __i386__
+unsigned int
+la_i86_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_i86_regs *inregs,
+ struct La_i86_retval *outregs, const char *symname)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return 0;
+}
+#elif defined __x86_64__
+unsigned int
+la_x86_64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_x86_64_regs *inregs,
+ struct La_x86_64_retval *outregs, const char *symname)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return 0;
+}
+#elif defined __sparc__ && !defined __arch64__
+unsigned int
+la_sparc32_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_sparc32_regs *inregs,
+ struct La_sparc32_retval *outregs, const char *symname)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return 0;
+}
+#elif defined __sparc__ && defined __arch64__
+unsigned int
+la_sparc64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const struct La_sparc64_regs *inregs,
+ struct La_sparc64_retval *outregs, const char *symname)
+{
+ /* Should not be here in dynamically loaded auditmod. */
+ assert (0);
+ return 0;
+}
+#elif !defined HAVE_ARCH_PLTEXIT
+# warning "pltexit for architecture not supported"
+#endif
new file mode 100644
@@ -0,0 +1,138 @@
+/* Check dlload_audit_module.
+ Copyright (C) 2021-2023 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 <array_length.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <gnu/lib-names.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <support/xstdio.h>
+#include <support/support.h>
+
+static int restart;
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+void *
+dlload_audit_module (const char *file, int flags);
+
+static int
+handle_restart (void)
+{
+ void *ah = dlload_audit_module ("tst-dynauditmod.so", 0);
+
+ TEST_VERIFY (ah != NULL);
+
+ {
+ void *h = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+
+ pid_t (*s) (void) = xdlsym (h, "getpid");
+ TEST_COMPARE (s (), getpid ());
+
+ xdlclose (h);
+ }
+
+ {
+ void *h = xdlmopen (LM_ID_NEWLM, "tst-audit18mod.so", RTLD_NOW);
+
+ int (*foo) (void) = xdlsym (h, "foo");
+ TEST_COMPARE (foo (), 10);
+
+ xdlclose (h);
+ }
+
+ return 0;
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+ /* We must have either:
+ - One our fource parameters left if called initially:
+ + path to ld.so optional
+ + "--library-path" optional
+ + the library path optional
+ + the application name */
+
+ if (restart)
+ return handle_restart ();
+
+ char *spargv[9];
+ int i = 0;
+ for (; i < argc - 1; i++)
+ spargv[i] = argv[i + 1];
+ spargv[i++] = (char *) "--direct";
+ spargv[i++] = (char *) "--restart";
+ spargv[i] = NULL;
+
+ struct support_capture_subprocess result
+ = support_capture_subprogram (spargv[0], spargv);
+ support_capture_subprocess_check (&result, "tst-loadaudit", 0, sc_allow_stderr);
+
+ struct
+ {
+ const char *name;
+ bool found;
+ } audit_iface[] =
+ {
+ { "la_version", false },
+ { "la_objsearch", false },
+ { "la_activity", false },
+ { "la_objopen", false },
+ { "la_objclose", false },
+#if __WORDSIZE == 32
+ { "la_symbind32", false },
+#elif __WORDSIZE == 64
+ { "la_symbind64", false },
+#endif
+#define STRING(s) __STRING (s)
+ { "la_" STRING (ARCH_LA_PLTENTER), false },
+ { "la_" STRING (ARCH_LA_PLTEXIT), false },
+ };
+
+ /* Some hooks are called more than once but the test only check if any
+ is called at least once. */
+ FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
+ TEST_VERIFY (out != NULL);
+ char *buffer = NULL;
+ size_t buffer_length = 0;
+ while (xgetline (&buffer, &buffer_length, out))
+ {
+ for (int i = 0; i < array_length (audit_iface); i++)
+ if (strncmp (buffer, audit_iface[i].name,
+ strlen (audit_iface[i].name)) == 0)
+ audit_iface[i].found = true;
+ }
+ free (buffer);
+ xfclose (out);
+
+ /* Check that symbols are resolved, except for the last 3.
+ symbind, pltenter, pltexit are not allowed for dynamically loaded mod. */
+ for (int i = 0; i < array_length (audit_iface); i++)
+ TEST_COMPARE (audit_iface[i].found, i < array_length (audit_iface) - 3);
+
+ support_capture_subprocess_free (&result);
+
+ return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
@@ -347,6 +347,7 @@ struct link_map
size_t l_relro_size;
unsigned long long int l_serial;
+ unsigned int l_naudit;
};
#include <dl-relocate-ld.h>
@@ -209,6 +209,7 @@ This function is a GNU extension.
@c dladdr1
@c dlclose
@c dlerror
+@c dlload_audit_module
@c dlmopen
@c dlopen
@c dlsym
@@ -399,6 +399,10 @@ struct rtld_global
/* Used to store the audit information for the link map of the
dynamic loader. */
struct auditstate _dl_rtld_auditstate[DL_NNS];
+
+ /* List of auditing interfaces. */
+ struct audit_ifaces *_dl_audit;
+ unsigned int _dl_naudit;
#endif
#if !PTHREAD_IN_LIBC && defined SHARED \
@@ -689,12 +693,11 @@ struct rtld_global_ro
dlopen. */
int (*_dl_find_object) (void *, struct dl_find_object *);
+ /* Loads audit module. */
+ void *(*_dlload_audit_module) (const char *name, int flags);
+
/* Dynamic linker operations used after static dlopen. */
const struct dlfcn_hook *_dl_dlfcn_hook;
-
- /* List of auditing interfaces. */
- struct audit_ifaces *_dl_audit;
- unsigned int _dl_naudit;
};
# define __rtld_global_attribute__
# if IS_IN (rtld)
@@ -2314,6 +2314,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2653,3 +2653,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2750,6 +2750,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2414,3 +2414,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -534,6 +534,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -531,6 +531,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -2690,3 +2690,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2639,6 +2639,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2823,6 +2823,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2588,6 +2588,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2174,3 +2174,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -535,6 +535,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
@@ -2766,6 +2766,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2739,3 +2739,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2736,3 +2736,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2731,6 +2731,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2729,6 +2729,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2737,6 +2737,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2639,6 +2639,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2778,3 +2778,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2160,3 +2160,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2793,6 +2793,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2826,6 +2826,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2547,6 +2547,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2849,3 +2849,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2416,3 +2416,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2616,3 +2616,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
@@ -2791,6 +2791,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2584,6 +2584,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2646,6 +2646,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2643,6 +2643,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2786,6 +2786,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2611,6 +2611,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2562,6 +2562,7 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2668,3 +2668,4 @@ GLIBC_2.38 __isoc23_wcstoul_l F
GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
+GLIBC_2.38 dlload_audit_module F
This patch is an impl of dlload_audit_module() function discussed in BZ #30127, and the test-case for it, called tst-loadaudit. It checks the loading of audit module at run-time and makes sure no "unrecognized" cookie is passed to the module call-backs. dlload_audit_module (const char *file, int flags) "file" is a module file name "flags" are reserved for future use. As mentioned in BZ #30134, audit module list was in RELRO so this patch makes it writable. To not compromise the hardening, several call-backs are disabled for dynamically loaded modules. Namely symbind, pltenter and pltexit. They have to be disabled also because the dynamically loaded audit module cannot interract with any object loaded before it, which is possible in case of these 3 call-backs. Test-suite run on x86_64 revealed no regressions. Signed-off-by: Stas Sergeev <stsp2@yandex.ru> --- dlfcn/Makefile | 4 +- dlfcn/Versions | 3 + dlfcn/dlaudit.c | 62 ++++++ elf/Makefile | 6 + elf/dl-audit.c | 47 +++-- elf/dl-fini.c | 2 +- elf/dl-load.c | 7 +- elf/dl-object.c | 4 +- elf/dl-reloc.c | 4 +- elf/dl-runtime.c | 2 +- elf/dl-sym-post.h | 2 +- elf/do-rel.h | 4 +- elf/rtld.c | 64 ++++-- elf/tst-dynauditmod.c | 190 ++++++++++++++++++ elf/tst-loadaudit.c | 138 +++++++++++++ include/link.h | 1 + manual/dynlink.texi | 1 + sysdeps/generic/ldsodefs.h | 11 +- sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 + .../sysv/linux/loongarch/lp64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 + sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 53 files changed, 535 insertions(+), 52 deletions(-) create mode 100644 dlfcn/dlaudit.c create mode 100644 elf/tst-dynauditmod.c create mode 100644 elf/tst-loadaudit.c