You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
314 lines
10 KiB
314 lines
10 KiB
commit d1b9bee29a1c4e0b80db53f228e22550c3604894 |
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> |
|
Date: Mon Jul 19 18:42:26 2021 -0300 |
|
|
|
elf: Issue audit la_objopen for vDSO |
|
|
|
The vDSO is is listed in the link_map chain, but is never the subject of |
|
an la_objopen call. A new internal flag __RTLD_VDSO is added that |
|
acts as __RTLD_OPENEXEC to allocate the required 'struct auditstate' |
|
extra space for the 'struct link_map'. |
|
|
|
The return value from the callback is currently ignored, since there |
|
is no PLT call involved by glibc when using the vDSO, neither the vDSO |
|
are exported directly. |
|
|
|
Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. |
|
|
|
Reviewed-by: Florian Weimer <fweimer@redhat.com> |
|
(cherry picked from commit f0e23d34a7bdf6b90fba954ee741419171ac41b2) |
|
|
|
Resolved conflicts: |
|
elf/Makefile |
|
|
|
diff --git a/elf/Makefile b/elf/Makefile |
|
index 29f545d2272bf6e2..465442bf59fa9794 100644 |
|
--- a/elf/Makefile |
|
+++ b/elf/Makefile |
|
@@ -366,6 +366,7 @@ tests += \ |
|
tst-audit17 \ |
|
tst-audit18 \ |
|
tst-audit19b \ |
|
+ tst-audit22 \ |
|
tst-auditmany \ |
|
tst-auxobj \ |
|
tst-auxobj-dlopen \ |
|
@@ -649,6 +650,7 @@ modules-names = \ |
|
tst-auditmod18 \ |
|
tst-auditmod19a \ |
|
tst-auditmod19b \ |
|
+ tst-auditmod22 \ |
|
tst-auxvalmod \ |
|
tst-big-note-lib \ |
|
tst-deep1mod1 \ |
|
@@ -2035,6 +2037,9 @@ $(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so |
|
$(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so |
|
tst-audit19b-ARGS = -- $(host-test-program-cmd) |
|
|
|
+$(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so |
|
+tst-audit22-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 \ |
|
diff --git a/elf/dl-object.c b/elf/dl-object.c |
|
index 1875599eb274dc35..dee49a32d4fdf07d 100644 |
|
--- a/elf/dl-object.c |
|
+++ b/elf/dl-object.c |
|
@@ -59,16 +59,19 @@ _dl_new_object (char *realname, const char *libname, int type, |
|
{ |
|
#ifdef SHARED |
|
unsigned int naudit; |
|
- if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0)) |
|
+ if (__glibc_unlikely ((mode & (__RTLD_OPENEXEC | __RTLD_VDSO)) != 0)) |
|
{ |
|
- assert (type == lt_executable); |
|
- assert (nsid == LM_ID_BASE); |
|
+ if (mode & __RTLD_OPENEXEC) |
|
+ { |
|
+ assert (type == lt_executable); |
|
+ assert (nsid == LM_ID_BASE); |
|
|
|
- /* Ignore the specified libname for the main executable. It is |
|
- only known with an explicit loader invocation. */ |
|
- libname = ""; |
|
+ /* Ignore the specified libname for the main executable. It is |
|
+ only known with an explicit loader invocation. */ |
|
+ libname = ""; |
|
+ } |
|
|
|
- /* We create the map for the executable before we know whether |
|
+ /* We create the map for the executable and vDSO before we know whether |
|
we have auditing libraries and if yes, how many. Assume the |
|
worst. */ |
|
naudit = DL_NNS; |
|
diff --git a/elf/rtld.c b/elf/rtld.c |
|
index f632a767d7a269ef..b089e5cf4740443e 100644 |
|
--- a/elf/rtld.c |
|
+++ b/elf/rtld.c |
|
@@ -1922,6 +1922,12 @@ dl_main (const ElfW(Phdr) *phdr, |
|
assert (i == npreloads); |
|
} |
|
|
|
+#ifdef NEED_DL_SYSINFO_DSO |
|
+ /* Now that the audit modules are opened, call la_objopen for the vDSO. */ |
|
+ if (GLRO(dl_sysinfo_map) != NULL) |
|
+ _dl_audit_objopen (GLRO(dl_sysinfo_map), LM_ID_BASE); |
|
+#endif |
|
+ |
|
/* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD |
|
specified some libraries to load, these are inserted before the actual |
|
dependencies in the executable's searchlist for symbol resolution. */ |
|
diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h |
|
index 3f20578046de76ed..2b013d974a377a83 100644 |
|
--- a/elf/setup-vdso.h |
|
+++ b/elf/setup-vdso.h |
|
@@ -30,7 +30,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), |
|
We just want our data structures to describe it as if we had just |
|
mapped and relocated it normally. */ |
|
struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL, |
|
- 0, LM_ID_BASE); |
|
+ __RTLD_VDSO, LM_ID_BASE); |
|
if (__glibc_likely (l != NULL)) |
|
{ |
|
l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso) |
|
diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c |
|
new file mode 100644 |
|
index 0000000000000000..18fd22a760ddc3d8 |
|
--- /dev/null |
|
+++ b/elf/tst-audit22.c |
|
@@ -0,0 +1,124 @@ |
|
+/* Check DTAUDIT and vDSO interaction. |
|
+ Copyright (C) 2021 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 <errno.h> |
|
+#include <getopt.h> |
|
+#include <limits.h> |
|
+#include <inttypes.h> |
|
+#include <string.h> |
|
+#include <stdlib.h> |
|
+#include <support/capture_subprocess.h> |
|
+#include <support/check.h> |
|
+#include <support/xstdio.h> |
|
+#include <support/support.h> |
|
+#include <sys/auxv.h> |
|
+ |
|
+static int restart; |
|
+#define CMDLINE_OPTIONS \ |
|
+ { "restart", no_argument, &restart, 1 }, |
|
+ |
|
+static uintptr_t vdso_addr; |
|
+ |
|
+static int |
|
+handle_restart (void) |
|
+{ |
|
+ fprintf (stderr, "vdso: %p\n", (void*) vdso_addr); |
|
+ return 0; |
|
+} |
|
+ |
|
+static uintptr_t |
|
+parse_address (const char *str) |
|
+{ |
|
+ void *r; |
|
+ TEST_COMPARE (sscanf (str, "%p\n", &r), 1); |
|
+ return (uintptr_t) r; |
|
+} |
|
+ |
|
+static inline bool |
|
+startswith (const char *str, const char *pre) |
|
+{ |
|
+ size_t lenpre = strlen (pre); |
|
+ size_t lenstr = strlen (str); |
|
+ return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0; |
|
+} |
|
+ |
|
+static int |
|
+do_test (int argc, char *argv[]) |
|
+{ |
|
+ vdso_addr = getauxval (AT_SYSINFO_EHDR); |
|
+ if (vdso_addr == 0) |
|
+ FAIL_UNSUPPORTED ("getauxval (AT_SYSINFO_EHDR) returned 0"); |
|
+ |
|
+ /* 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; |
|
+ |
|
+ setenv ("LD_AUDIT", "tst-auditmod22.so", 0); |
|
+ struct support_capture_subprocess result |
|
+ = support_capture_subprogram (spargv[0], spargv); |
|
+ support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr); |
|
+ |
|
+ /* The respawned process should always print the vDSO address (otherwise it |
|
+ will fails as unsupported). However, on some architectures the audit |
|
+ module might see the vDSO with l_addr being 0, meaning a fixed mapping |
|
+ (linux-gate.so). In this case we don't check its value against |
|
+ AT_SYSINFO_EHDR one. */ |
|
+ uintptr_t vdso_process = 0; |
|
+ bool vdso_audit_found = false; |
|
+ uintptr_t vdso_audit = 0; |
|
+ |
|
+ 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)) |
|
+ { |
|
+ if (startswith (buffer, "vdso: ")) |
|
+ vdso_process = parse_address (buffer + strlen ("vdso: ")); |
|
+ else if (startswith (buffer, "vdso found: ")) |
|
+ { |
|
+ vdso_audit = parse_address (buffer + strlen ("vdso found: ")); |
|
+ vdso_audit_found = true; |
|
+ } |
|
+ } |
|
+ |
|
+ TEST_COMPARE (vdso_audit_found, true); |
|
+ if (vdso_audit != 0) |
|
+ TEST_COMPARE (vdso_process, vdso_audit); |
|
+ |
|
+ free (buffer); |
|
+ xfclose (out); |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+#define TEST_FUNCTION_ARGV do_test |
|
+#include <support/test-driver.c> |
|
diff --git a/elf/tst-auditmod22.c b/elf/tst-auditmod22.c |
|
new file mode 100644 |
|
index 0000000000000000..8e05ce8cbb215dd5 |
|
--- /dev/null |
|
+++ b/elf/tst-auditmod22.c |
|
@@ -0,0 +1,51 @@ |
|
+/* Check DTAUDIT and vDSO interaction. |
|
+ Copyright (C) 2021 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 <link.h> |
|
+#include <inttypes.h> |
|
+#include <stdbool.h> |
|
+#include <string.h> |
|
+#include <stdio.h> |
|
+#include <sys/auxv.h> |
|
+ |
|
+static inline bool |
|
+startswith (const char *str, const char *pre) |
|
+{ |
|
+ size_t lenpre = strlen (pre); |
|
+ size_t lenstr = strlen (str); |
|
+ return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0; |
|
+} |
|
+ |
|
+unsigned int |
|
+la_version (unsigned int version) |
|
+{ |
|
+ return LAV_CURRENT; |
|
+} |
|
+ |
|
+unsigned int |
|
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) |
|
+{ |
|
+ /* The linux-gate.so is placed at a fixed address, thus l_addr being 0, |
|
+ and it might be the value reported as the AT_SYSINFO_EHDR. */ |
|
+ if (map->l_addr == 0 && startswith (map->l_name, "linux-gate.so")) |
|
+ fprintf (stderr, "vdso found: %p\n", NULL); |
|
+ else if (map->l_addr == getauxval (AT_SYSINFO_EHDR)) |
|
+ fprintf (stderr, "vdso found: %p\n", (void*) map->l_addr); |
|
+ |
|
+ return 0; |
|
+} |
|
diff --git a/include/dlfcn.h b/include/dlfcn.h |
|
index a4c283728f94deb4..e73294b0af587913 100644 |
|
--- a/include/dlfcn.h |
|
+++ b/include/dlfcn.h |
|
@@ -12,6 +12,8 @@ |
|
#define __RTLD_AUDIT 0x08000000 |
|
#define __RTLD_SECURE 0x04000000 /* Apply additional security checks. */ |
|
#define __RTLD_NOIFUNC 0x02000000 /* Suppress calling ifunc functions. */ |
|
+#define __RTLD_VDSO 0x01000000 /* Tell _dl_new_object the object is |
|
+ system-loaded. */ |
|
|
|
#define __LM_ID_CALLER -2 |
|
|
|
|