aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-11-29 10:44:59 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-01-03 11:22:07 -0300
commit1bdda52fe92fd01b424cd6fbb63e3df96a95015c (patch)
treed25214e63bf5c96ab48c11ec0df28b5d96ca99da
parent57013650f7e796428ac2c0b7512757e99327bfc9 (diff)
downloadglibc-1bdda52fe92fd01b424cd6fbb63e3df96a95015c.tar.xz
glibc-1bdda52fe92fd01b424cd6fbb63e3df96a95015c.zip
elf: Move vDSO setup to rtld (BZ#24967)
This patch moves the vDSO setup from libc to loader code, just after the vDSO link_map setup. For static case the initialization is moved to _dl_non_dynamic_init instead. Instead of using the mangled pointer, the vDSO data is set as attribute_relro (on _rtld_global_ro for shared or _dl_vdso_* for static). It is read-only even with partial relro. It fixes BZ#24967 now that the vDSO pointer is setup earlier than malloc interposition is called. Also, vDSO calls should not be a problem for static dlopen as indicated by BZ#20802. The vDSO pointer would be zero-initialized and the syscall will be issued instead. Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, arm-linux-gnueabihf, powerpc64le-linux-gnu, powerpc64-linux-gnu, powerpc-linux-gnu, s390x-linux-gnu, sparc64-linux-gnu, and sparcv9-linux-gnu. I also run some tests on mips. Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
-rw-r--r--csu/init-first.c4
-rw-r--r--elf/dl-support.c7
-rw-r--r--elf/rtld.c7
-rw-r--r--malloc/tst-interpose-aux.c5
-rw-r--r--sysdeps/generic/dl-vdso-setup.c1
-rw-r--r--sysdeps/generic/dl-vdso-setup.h28
-rw-r--r--sysdeps/generic/dl-vdso.h30
-rw-r--r--sysdeps/generic/ldsodefs.h6
-rw-r--r--sysdeps/powerpc/powerpc32/backtrace.c16
-rw-r--r--sysdeps/powerpc/powerpc64/backtrace.c8
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/Makefile1
-rw-r--r--sysdeps/unix/sysv/linux/arm/Makefile1
-rw-r--r--sysdeps/unix/sysv/linux/dl-vdso-setup.c81
-rw-r--r--sysdeps/unix/sysv/linux/dl-vdso-setup.h55
-rw-r--r--sysdeps/unix/sysv/linux/dl-vdso.c48
-rw-r--r--sysdeps/unix/sysv/linux/dl-vdso.h30
-rw-r--r--sysdeps/unix/sysv/linux/gettimeofday.c3
-rw-r--r--sysdeps/unix/sysv/linux/init-first.c90
-rw-r--r--sysdeps/unix/sysv/linux/libc-vdso.h30
-rw-r--r--sysdeps/unix/sysv/linux/mips/Makefile2
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/Makefile1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c5
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/init-first.c50
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/libc-vdso.h10
-rw-r--r--sysdeps/unix/sysv/linux/riscv/Makefile4
-rw-r--r--sysdeps/unix/sysv/linux/riscv/flush-icache.c2
-rw-r--r--sysdeps/unix/sysv/linux/s390/Makefile4
-rw-r--r--sysdeps/unix/sysv/linux/sparc/Makefile4
-rw-r--r--sysdeps/unix/sysv/linux/sysdep-vdso.h6
-rw-r--r--sysdeps/unix/sysv/linux/time.c3
-rw-r--r--sysdeps/unix/sysv/linux/x86/Makefile4
31 files changed, 257 insertions, 289 deletions
diff --git a/csu/init-first.c b/csu/init-first.c
index 669b779b70..1cd8a75098 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -74,10 +74,6 @@ _init (int argc, char **argv, char **envp)
_dl_non_dynamic_init ();
#endif
-#ifdef VDSO_SETUP
- VDSO_SETUP ();
-#endif
-
__init_misc (argc, argv, envp);
/* Initialize ctype data. */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 508a5c1196..ad791ab6ab 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -34,6 +34,8 @@
#include <unsecvars.h>
#include <hp-timing.h>
#include <stackinfo.h>
+#include <dl-vdso.h>
+#include <dl-vdso-setup.h>
extern char *__progname;
char **_dl_argv = &__progname; /* This is checked for some error messages. */
@@ -201,6 +203,8 @@ struct link_map *_dl_sysinfo_map;
# include "get-dynamic-info.h"
#endif
#include "setup-vdso.h"
+/* Define the vDSO function pointers. */
+#include <dl-vdso-setup.c>
/* During the program run we must not modify the global data of
loaded shared object simultanously in two threads. Therefore we
@@ -315,6 +319,9 @@ _dl_non_dynamic_init (void)
so they can influence _dl_init_paths. */
setup_vdso (NULL, NULL);
+ /* With vDSO setup we can initialize the function pointers. */
+ setup_vdso_pointers ();
+
/* Initialize the data structures for the search paths for shared
objects. */
_dl_init_paths (getenv ("LD_LIBRARY_PATH"));
diff --git a/elf/rtld.c b/elf/rtld.c
index 817fb86eac..553cfbd1b7 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -39,6 +39,8 @@
#include <dl-osinfo.h>
#include <dl-procinfo.h>
#include <dl-prop.h>
+#include <dl-vdso.h>
+#include <dl-vdso-setup.h>
#include <tls.h>
#include <stap-probe.h>
#include <stackinfo.h>
@@ -833,7 +835,7 @@ security_init (void)
_dl_random = NULL;
}
-#include "setup-vdso.h"
+#include <setup-vdso.h>
/* The library search path. */
static const char *library_path attribute_relro;
@@ -1538,6 +1540,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
so they can influence _dl_init_paths. */
setup_vdso (main_map, &first_preload);
+ /* With vDSO setup we can initialize the function pointers. */
+ setup_vdso_pointers ();
+
#ifdef DL_SYSDEP_OSCHECK
DL_SYSDEP_OSCHECK (_dl_fatal_printf);
#endif
diff --git a/malloc/tst-interpose-aux.c b/malloc/tst-interpose-aux.c
index 52696e92d3..a0ab2e5903 100644
--- a/malloc/tst-interpose-aux.c
+++ b/malloc/tst-interpose-aux.c
@@ -28,6 +28,7 @@
#include <sys/mman.h>
#include <sys/uio.h>
#include <unistd.h>
+#include <time.h>
#if INTERPOSE_THREADS
#include <pthread.h>
@@ -96,6 +97,7 @@ struct __attribute__ ((aligned (__alignof__ (max_align_t)))) allocation_header
{
size_t allocation_index;
size_t allocation_size;
+ struct timespec ts;
};
/* Array of known allocations, to track invalid frees. */
@@ -166,6 +168,9 @@ malloc_internal (size_t size)
.allocation_index = index,
.allocation_size = allocation_size
};
+ /* BZ#24967: Check if calling a symbol which may use the vDSO does not fail.
+ The CLOCK_REALTIME should be supported on all systems. */
+ clock_gettime (CLOCK_REALTIME, &allocations[index]->ts);
return allocations[index] + 1;
}
diff --git a/sysdeps/generic/dl-vdso-setup.c b/sysdeps/generic/dl-vdso-setup.c
new file mode 100644
index 0000000000..6e25b021ab
--- /dev/null
+++ b/sysdeps/generic/dl-vdso-setup.c
@@ -0,0 +1 @@
+/* Empty. */
diff --git a/sysdeps/generic/dl-vdso-setup.h b/sysdeps/generic/dl-vdso-setup.h
new file mode 100644
index 0000000000..5ef7531fac
--- /dev/null
+++ b/sysdeps/generic/dl-vdso-setup.h
@@ -0,0 +1,28 @@
+/* ELF symbol initialization functions for VDSO objects.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _DL_VDSO_INIT_H
+#define _DL_VDSO_INIT_H
+
+/* Initialize the VDSO functions pointers. */
+static inline void __attribute__ ((always_inline))
+setup_vdso_pointers (void)
+{
+}
+
+#endif
diff --git a/sysdeps/generic/dl-vdso.h b/sysdeps/generic/dl-vdso.h
new file mode 100644
index 0000000000..70379a82a1
--- /dev/null
+++ b/sysdeps/generic/dl-vdso.h
@@ -0,0 +1,30 @@
+/* ELF symbol resolve functions for VDSO objects.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _DL_VDSO_H
+#define _DL_VDSO_H 1
+
+/* Function for resolving symbols in the VDSO link map. Return the
+ address of the vdso symbol NAME. */
+static inline void *
+dl_vdso_vsym (const char *name)
+{
+ return NULL;
+}
+
+#endif
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 0a5d3473f5..497938ffa2 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -608,6 +608,12 @@ struct rtld_global_ro
/* At startup time we set up the normal DSO data structure for it,
and this points to it. */
EXTERN struct link_map *_dl_sysinfo_map;
+
+# define PROCINFO_DECL
+# ifndef PROCINFO_CLASS
+# define PROCINFO_CLASS EXTERN
+# endif
+# include <dl-vdso-setup.c>
#endif
/* Mask for more hardware capabilities that are available on some
diff --git a/sysdeps/powerpc/powerpc32/backtrace.c b/sysdeps/powerpc/powerpc32/backtrace.c
index 4a35588671..7c2d4726f8 100644
--- a/sysdeps/powerpc/powerpc32/backtrace.c
+++ b/sysdeps/powerpc/powerpc32/backtrace.c
@@ -51,14 +51,14 @@ struct signal_frame_32 {
/* We don't care about the rest, since IP value is at 'mctx' field. */
};
-static inline int
+static inline bool
is_sigtramp_address (void *nip)
{
#ifdef HAVE_SIGTRAMP_RT32
- if (nip == VDSO_SYMBOL (sigtramp32))
- return 1;
+ if (nip == GLRO (dl_vdso_sigtramp_32))
+ return true;
#endif
- return 0;
+ return false;
}
struct rt_signal_frame_32 {
@@ -68,14 +68,14 @@ struct rt_signal_frame_32 {
/* We don't care about the rest, since IP value is at 'uc' field. */
};
-static inline int
+static inline bool
is_sigtramp_address_rt (void * nip)
{
#ifdef HAVE_SIGTRAMP_32
- if (nip == VDSO_SYMBOL (sigtramp_rt32))
- return 1;
+ if (nip == GLRO (dl_vdso_sigtramp_rt32))
+ return true;
#endif
- return 0;
+ return false;
}
int
diff --git a/sysdeps/powerpc/powerpc64/backtrace.c b/sysdeps/powerpc/powerpc64/backtrace.c
index ee8ba21f27..65c260ab76 100644
--- a/sysdeps/powerpc/powerpc64/backtrace.c
+++ b/sysdeps/powerpc/powerpc64/backtrace.c
@@ -54,14 +54,14 @@ struct signal_frame_64 {
/* We don't care about the rest, since the IP value is at 'uc' field. */
};
-static inline int
+static inline bool
is_sigtramp_address (void *nip)
{
#ifdef HAVE_SIGTRAMP_RT64
- if (nip == VDSO_SYMBOL (sigtramp_rt64))
- return 1;
+ if (nip == GLRO (dl_vdso_sigtramp_rt64))
+ return true;
#endif
- return 0;
+ return false;
}
int
diff --git a/sysdeps/unix/sysv/linux/aarch64/Makefile b/sysdeps/unix/sysv/linux/aarch64/Makefile
index 57bbfeaac6..4bcae85bca 100644
--- a/sysdeps/unix/sysv/linux/aarch64/Makefile
+++ b/sysdeps/unix/sysv/linux/aarch64/Makefile
@@ -5,7 +5,6 @@ shared-only-routines += libc-__read_tp
endif
ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
sysdep-rtld-routines += __read_tp
ifeq ($(build-shared),yes)
# This is needed for DSO loading from static binaries.
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
index d7a2f6a8a7..abdf01f00c 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -1,5 +1,4 @@
ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
endif
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.c b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
new file mode 100644
index 0000000000..352fcae529
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
@@ -0,0 +1,81 @@
+/* Data for vDSO support. Linux version.
+ Copyright (C) 2020 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/>. */
+
+/* This file is included in three different modes for both static (libc.a)
+ and shared (rtld) modes:
+
+ 1. PROCINFO_DECL is defined, meaning we are only interested in
+ declarations. For static it requires use the extern keywork along with
+ the attribute_relro while for shared it will be embedded in the
+ rtld_global_ro.
+
+ 2. PROCINFO_DECL and SHARED are not defined. Nothing to do, the default
+ zero initializion is suffice.
+
+ 3. PROCINFO_DECL is not defined while SHARED is. Similar to 2., the zero
+ initialization of rtld_global_ro is suffice. */
+
+#ifndef PROCINFO_CLASS
+# define PROCINFO_CLASS
+#endif
+
+#ifndef SHARED
+# define RELRO attribute_relro
+#else
+# define RELRO
+#endif
+
+#if defined PROCINFO_DECL || !defined SHARED
+# ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_clock_gettime) (clockid_t,
+ struct timespec *) RELRO;
+#endif
+# ifdef HAVE_GETTIMEOFDAY_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_gettimeofday) (struct timeval *, void *) RELRO;
+#endif
+# ifdef HAVE_TIME_VSYSCALL
+PROCINFO_CLASS time_t (*_dl_vdso_time) (time_t *) RELRO;
+# endif
+# ifdef HAVE_GETCPU_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_getcpu) (unsigned *, unsigned *, void *) RELRO;
+# endif
+# ifdef HAVE_CLOCK_GETRES_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_clock_getres) (clockid_t,
+ struct timespec *) RELRO;
+# endif
+
+/* PowerPC specific ones. */
+# ifdef HAVE_GET_TBFREQ
+PROCINFO_CLASS uint64_t (*_dl_vdso_get_tbfreq)(void) RELRO;
+# endif
+/* The sigtramp are used on powerpc backtrace without using
+ INLINE_VSYSCALL, so there is no need to set their type. */
+# ifdef HAVE_SIGTRAMP_RT64
+PROCINFO_CLASS void *_dl_vdso_sigtramp_rt64 RELRO;
+# endif
+# ifdef HAVE_SIGTRAMP_RT32
+PROCINFO_CLASS void *_dl_vdso_sigtramp_rt32 RELRO;
+# endif
+# ifdef HAVE_SIGTRAMP_32
+PROCINFO_CLASS void *_dl_vdso_sigtramp_32 RELRO;
+# endif
+#endif
+
+#undef RELRO
+#undef PROCINFO_DECL
+#undef PROCINFO_CLASS
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.h b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
new file mode 100644
index 0000000000..9f5e4a3b0b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
@@ -0,0 +1,55 @@
+/* ELF symbol initialization functions for VDSO objects. Linux version.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _DL_VDSO_INIT_H
+#define _DL_VDSO_INIT_H
+
+/* Initialize the VDSO functions pointers. */
+static inline void __attribute__ ((always_inline))
+setup_vdso_pointers (void)
+{
+#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+ GLRO(dl_vdso_clock_gettime) = dl_vdso_vsym (HAVE_CLOCK_GETTIME_VSYSCALL);
+#endif
+#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
+ GLRO(dl_vdso_gettimeofday) = dl_vdso_vsym (HAVE_GETTIMEOFDAY_VSYSCALL);
+#endif
+#ifdef HAVE_TIME_VSYSCALL
+ GLRO(dl_vdso_time) = dl_vdso_vsym (HAVE_TIME_VSYSCALL);
+#endif
+#ifdef HAVE_GETCPU_VSYSCALL
+ GLRO(dl_vdso_getcpu) = dl_vdso_vsym (HAVE_GETCPU_VSYSCALL);
+#endif
+#ifdef HAVE_CLOCK_GETRES_VSYSCALL
+ GLRO(dl_vdso_clock_getres) = dl_vdso_vsym (HAVE_CLOCK_GETRES_VSYSCALL);
+#endif
+#ifdef HAVE_GET_TBFREQ
+ GLRO(dl_vdso_get_tbfreq) = dl_vdso_vsym (HAVE_GET_TBFREQ);
+#endif
+#ifdef HAVE_SIGTRAMP_RT64
+ GLRO(dl_vdso_sigtramp_rt64) = dl_vdso_vsym (HAVE_SIGTRAMP_RT64);
+#endif
+#ifdef HAVE_SIGTRAMP_RT32
+ GLRO(dl_vdso_sigtramp_rt32) = dl_vdso_vsym (HAVE_SIGTRAMP_RT32);
+#endif
+#ifdef HAVE_SIGTRAMP_32
+ GLRO(dl_vdso_sigtramp_32) = dl_vdso_vsym (HAVE_SIGTRAMP_32);
+#endif
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/dl-vdso.c b/sysdeps/unix/sysv/linux/