601650f878
* Tue May 31 2022 Arjun Shankar <arjun@redhat.com> - 2.34-35 - Sync with upstream branch release/2.34/master, commit ff450cdbdee0b8cb6b9d653d6d2fa892de29be31: - Fix deadlock when pthread_atfork handler calls pthread_atfork or dlclose - x86: Fallback {str|wcs}cmp RTM in the ncmp overflow case [BZ #29127] - string.h: fix __fortified_attr_access macro call [BZ #29162] - linux: Add a getauxval test [BZ #23293] - rtld: Use generic argv adjustment in ld.so [BZ #23293] - S390: Enable static PIE * Thu May 19 2022 Florian Weimer <fweimer@redhat.com> - 2.34-34 - Sync with upstream branch release/2.34/master, commit ede8d94d154157d269b18f3601440ac576c1f96a: - csu: Implement and use _dl_early_allocate during static startup - Linux: Introduce __brk_call for invoking the brk system call - Linux: Implement a useful version of _startup_fatal - ia64: Always define IA64_USE_NEW_STUB as a flag macro - Linux: Define MMAP_CALL_INTERNAL - i386: Honor I386_USE_SYSENTER for 6-argument Linux system calls - i386: Remove OPTIMIZE_FOR_GCC_5 from Linux libc-do-syscall.S - elf: Remove __libc_init_secure - Linux: Consolidate auxiliary vector parsing (redo) - Linux: Include <dl-auxv.h> in dl-sysdep.c only for SHARED - Revert "Linux: Consolidate auxiliary vector parsing" - Linux: Consolidate auxiliary vector parsing - Linux: Assume that NEED_DL_SYSINFO_DSO is always defined - Linux: Remove DL_FIND_ARG_COMPONENTS - Linux: Remove HAVE_AUX_SECURE, HAVE_AUX_XID, HAVE_AUX_PAGESIZE - elf: Merge dl-sysdep.c into the Linux version - elf: Remove unused NEED_DL_BASE_ADDR and _dl_base_addr - x86: Optimize {str|wcs}rchr-evex - x86: Optimize {str|wcs}rchr-avx2 - x86: Optimize {str|wcs}rchr-sse2 - x86: Cleanup page cross code in memcmp-avx2-movbe.S - x86: Remove memcmp-sse4.S - x86: Small improvements for wcslen - x86: Remove AVX str{n}casecmp - x86: Add EVEX optimized str{n}casecmp - x86: Add AVX2 optimized str{n}casecmp - x86: Optimize str{n}casecmp TOLOWER logic in strcmp-sse42.S - x86: Optimize str{n}casecmp TOLOWER logic in strcmp.S - x86: Remove strspn-sse2.S and use the generic implementation - x86: Remove strpbrk-sse2.S and use the generic implementation - x87: Remove strcspn-sse2.S and use the generic implementation - x86: Optimize strspn in strspn-c.c - x86: Optimize strcspn and strpbrk in strcspn-c.c - x86: Code cleanup in strchr-evex and comment justifying branch - x86: Code cleanup in strchr-avx2 and comment justifying branch - x86_64: Remove bcopy optimizations - x86-64: Remove bzero weak alias in SS2 memset - x86_64/multiarch: Sort sysdep_routines and put one entry per line - x86: Improve L to support L(XXX_SYMBOL (YYY, ZZZ)) - fortify: Ensure that __glibc_fortify condition is a constant [BZ #29141] * Thu May 12 2022 Florian Weimer <fweimer@redhat.com> - 2.34-33 - Sync with upstream branch release/2.34/master, commit 91c2e6c3db44297bf4cb3a2e3c40236c5b6a0b23: - dlfcn: Implement the RTLD_DI_PHDR request type for dlinfo - manual: Document the dlinfo function - x86: Fix fallback for wcsncmp_avx2 in strcmp-avx2.S [BZ #28896] - x86: Fix bug in strncmp-evex and strncmp-avx2 [BZ #28895] - x86: Set .text section in memset-vec-unaligned-erms - x86-64: Optimize bzero - x86: Remove SSSE3 instruction for broadcast in memset.S (SSE2 Only) - x86: Improve vec generation in memset-vec-unaligned-erms.S - x86-64: Fix strcmp-evex.S - x86-64: Fix strcmp-avx2.S - x86: Optimize strcmp-evex.S - x86: Optimize strcmp-avx2.S - manual: Clarify that abbreviations of long options are allowed - Add HWCAP2_AFP, HWCAP2_RPRES from Linux 5.17 to AArch64 bits/hwcap.h - aarch64: Add HWCAP2_ECV from Linux 5.16 - Add SOL_MPTCP, SOL_MCTP from Linux 5.16 to bits/socket.h - Update kernel version to 5.17 in tst-mman-consts.py - Update kernel version to 5.16 in tst-mman-consts.py - Update syscall lists for Linux 5.17 - Add ARPHRD_CAN, ARPHRD_MCTP to net/if_arp.h - Update kernel version to 5.15 in tst-mman-consts.py - Add PF_MCTP, AF_MCTP from Linux 5.15 to bits/socket.h Resolves: #2091541
302 lines
9.1 KiB
Diff
302 lines
9.1 KiB
Diff
commit c73c79af7d6f1124fbfa5d935b4f620217d6a2ec
|
|
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
|
|
Date: Fri Jun 15 16:14:58 2018 +0100
|
|
|
|
rtld: Use generic argv adjustment in ld.so [BZ #23293]
|
|
|
|
When an executable is invoked as
|
|
|
|
./ld.so [ld.so-args] ./exe [exe-args]
|
|
|
|
then the argv is adujusted in ld.so before calling the entry point of
|
|
the executable so ld.so args are not visible to it. On most targets
|
|
this requires moving argv, env and auxv on the stack to ensure correct
|
|
stack alignment at the entry point. This had several issues:
|
|
|
|
- The code for this adjustment on the stack is written in asm as part
|
|
of the target specific ld.so _start code which is hard to maintain.
|
|
|
|
- The adjustment is done after _dl_start returns, where it's too late
|
|
to update GLRO(dl_auxv), as it is already readonly, so it points to
|
|
memory that was clobbered by the adjustment. This is bug 23293.
|
|
|
|
- _environ is also wrong in ld.so after the adjustment, but it is
|
|
likely not used after _dl_start returns so this is not user visible.
|
|
|
|
- _dl_argv was updated, but for this it was moved out of relro, which
|
|
changes security properties across targets unnecessarily.
|
|
|
|
This patch introduces a generic _dl_start_args_adjust function that
|
|
handles the argument adjustments after ld.so processed its own args
|
|
and before relro protection is applied.
|
|
|
|
The same algorithm is used on all targets, _dl_skip_args is now 0, so
|
|
existing target specific adjustment code is no longer used. The bug
|
|
affects aarch64, alpha, arc, arm, csky, ia64, nios2, s390-32 and sparc,
|
|
other targets don't need the change in principle, only for consistency.
|
|
|
|
The GNU Hurd start code relied on _dl_skip_args after dl_main returned,
|
|
now it checks directly if args were adjusted and fixes the Hurd startup
|
|
data accordingly.
|
|
|
|
Follow up patches can remove _dl_skip_args and DL_ARGV_NOT_RELRO.
|
|
|
|
Tested on aarch64-linux-gnu and cross tested on i686-gnu.
|
|
|
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
(cherry picked from commit ad43cac44a6860eaefcadadfb2acb349921e96bf)
|
|
|
|
Conflicts:
|
|
elf/rtld.c
|
|
(Downstream-only backport of glibc-rh2023422-1.patch)
|
|
|
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
|
index 434fbeddd5cce74d..9de53ccaed420a57 100644
|
|
--- a/elf/rtld.c
|
|
+++ b/elf/rtld.c
|
|
@@ -1121,6 +1121,62 @@ rtld_chain_load (struct link_map *main_map, char *argv0)
|
|
rtld_soname, pathname, errcode);
|
|
}
|
|
|
|
+/* Adjusts the contents of the stack and related globals for the user
|
|
+ entry point. The ld.so processed skip_args arguments and bumped
|
|
+ _dl_argv and _dl_argc accordingly. Those arguments are removed from
|
|
+ argv here. */
|
|
+static void
|
|
+_dl_start_args_adjust (int skip_args)
|
|
+{
|
|
+ void **sp = (void **) (_dl_argv - skip_args - 1);
|
|
+ void **p = sp + skip_args;
|
|
+
|
|
+ if (skip_args == 0)
|
|
+ return;
|
|
+
|
|
+ /* Sanity check. */
|
|
+ intptr_t argc = (intptr_t) sp[0] - skip_args;
|
|
+ assert (argc == _dl_argc);
|
|
+
|
|
+ /* Adjust argc on stack. */
|
|
+ sp[0] = (void *) (intptr_t) _dl_argc;
|
|
+
|
|
+ /* Update globals in rtld. */
|
|
+ _dl_argv -= skip_args;
|
|
+ _environ -= skip_args;
|
|
+
|
|
+ /* Shuffle argv down. */
|
|
+ do
|
|
+ *++sp = *++p;
|
|
+ while (*p != NULL);
|
|
+
|
|
+ assert (_environ == (char **) (sp + 1));
|
|
+
|
|
+ /* Shuffle envp down. */
|
|
+ do
|
|
+ *++sp = *++p;
|
|
+ while (*p != NULL);
|
|
+
|
|
+#ifdef HAVE_AUX_VECTOR
|
|
+ void **auxv = (void **) GLRO(dl_auxv) - skip_args;
|
|
+ GLRO(dl_auxv) = (ElfW(auxv_t) *) auxv; /* Aliasing violation. */
|
|
+ assert (auxv == sp + 1);
|
|
+
|
|
+ /* Shuffle auxv down. */
|
|
+ ElfW(auxv_t) ax;
|
|
+ char *oldp = (char *) (p + 1);
|
|
+ char *newp = (char *) (sp + 1);
|
|
+ do
|
|
+ {
|
|
+ memcpy (&ax, oldp, sizeof (ax));
|
|
+ memcpy (newp, &ax, sizeof (ax));
|
|
+ oldp += sizeof (ax);
|
|
+ newp += sizeof (ax);
|
|
+ }
|
|
+ while (ax.a_type != AT_NULL);
|
|
+#endif
|
|
+}
|
|
+
|
|
static void
|
|
dl_main (const ElfW(Phdr) *phdr,
|
|
ElfW(Word) phnum,
|
|
@@ -1177,6 +1233,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
rtld_is_main = true;
|
|
|
|
char *argv0 = NULL;
|
|
+ char **orig_argv = _dl_argv;
|
|
|
|
/* Note the place where the dynamic linker actually came from. */
|
|
GL(dl_rtld_map).l_name = rtld_progname;
|
|
@@ -1191,7 +1248,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
GLRO(dl_lazy) = -1;
|
|
}
|
|
|
|
- ++_dl_skip_args;
|
|
--_dl_argc;
|
|
++_dl_argv;
|
|
}
|
|
@@ -1200,14 +1256,12 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
if (state.mode != rtld_mode_help)
|
|
state.mode = rtld_mode_verify;
|
|
|
|
- ++_dl_skip_args;
|
|
--_dl_argc;
|
|
++_dl_argv;
|
|
}
|
|
else if (! strcmp (_dl_argv[1], "--inhibit-cache"))
|
|
{
|
|
GLRO(dl_inhibit_cache) = 1;
|
|
- ++_dl_skip_args;
|
|
--_dl_argc;
|
|
++_dl_argv;
|
|
}
|
|
@@ -1217,7 +1271,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
state.library_path = _dl_argv[2];
|
|
state.library_path_source = "--library-path";
|
|
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
@@ -1226,7 +1279,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
{
|
|
GLRO(dl_inhibit_rpath) = _dl_argv[2];
|
|
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
@@ -1234,14 +1286,12 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
{
|
|
audit_list_add_string (&state.audit_list, _dl_argv[2]);
|
|
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2)
|
|
{
|
|
state.preloadarg = _dl_argv[2];
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
@@ -1249,7 +1299,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
{
|
|
argv0 = _dl_argv[2];
|
|
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
@@ -1257,7 +1306,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
&& _dl_argc > 2)
|
|
{
|
|
state.glibc_hwcaps_prepend = _dl_argv[2];
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
@@ -1265,7 +1313,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
&& _dl_argc > 2)
|
|
{
|
|
state.glibc_hwcaps_mask = _dl_argv[2];
|
|
- _dl_skip_args += 2;
|
|
_dl_argc -= 2;
|
|
_dl_argv += 2;
|
|
}
|
|
@@ -1274,7 +1321,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
{
|
|
state.mode = rtld_mode_list_tunables;
|
|
|
|
- ++_dl_skip_args;
|
|
--_dl_argc;
|
|
++_dl_argv;
|
|
}
|
|
@@ -1283,7 +1329,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
{
|
|
state.mode = rtld_mode_list_diagnostics;
|
|
|
|
- ++_dl_skip_args;
|
|
--_dl_argc;
|
|
++_dl_argv;
|
|
}
|
|
@@ -1329,7 +1374,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
_dl_usage (ld_so_name, NULL);
|
|
}
|
|
|
|
- ++_dl_skip_args;
|
|
--_dl_argc;
|
|
++_dl_argv;
|
|
|
|
@@ -1428,6 +1472,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
/* Set the argv[0] string now that we've processed the executable. */
|
|
if (argv0 != NULL)
|
|
_dl_argv[0] = argv0;
|
|
+
|
|
+ /* Adjust arguments for the application entry point. */
|
|
+ _dl_start_args_adjust (_dl_argv - orig_argv);
|
|
}
|
|
else
|
|
{
|
|
diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c
|
|
index 4b2072e5d5e3bfd2..5c0f8e46bfbd4753 100644
|
|
--- a/sysdeps/mach/hurd/dl-sysdep.c
|
|
+++ b/sysdeps/mach/hurd/dl-sysdep.c
|
|
@@ -106,6 +106,7 @@ _dl_sysdep_start (void **start_argptr,
|
|
{
|
|
void go (intptr_t *argdata)
|
|
{
|
|
+ char *orig_argv0;
|
|
char **p;
|
|
|
|
/* Cache the information in various global variables. */
|
|
@@ -114,6 +115,8 @@ _dl_sysdep_start (void **start_argptr,
|
|
_environ = &_dl_argv[_dl_argc + 1];
|
|
for (p = _environ; *p++;); /* Skip environ pointers and terminator. */
|
|
|
|
+ orig_argv0 = _dl_argv[0];
|
|
+
|
|
if ((void *) p == _dl_argv[0])
|
|
{
|
|
static struct hurd_startup_data nodata;
|
|
@@ -204,30 +207,23 @@ unfmh(); /* XXX */
|
|
|
|
/* The call above might screw a few things up.
|
|
|
|
- First of all, if _dl_skip_args is nonzero, we are ignoring
|
|
- the first few arguments. However, if we have no Hurd startup
|
|
- data, it is the magical convention that ARGV[0] == P. The
|
|
+ P is the location after the terminating NULL of the list of
|
|
+ environment variables. It has to point to the Hurd startup
|
|
+ data or if that's missing then P == ARGV[0] must hold. The
|
|
startup code in init-first.c will get confused if this is not
|
|
the case, so we must rearrange things to make it so. We'll
|
|
- overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
|
|
+ recompute P and move the Hurd data or the new ARGV[0] there.
|
|
|
|
- Secondly, if we need to be secure, it removes some dangerous
|
|
- environment variables. If we have no Hurd startup date this
|
|
- changes P (since that's the location after the terminating
|
|
- NULL in the list of environment variables). We do the same
|
|
- thing as in the first case but make sure we recalculate P.
|
|
- If we do have Hurd startup data, we have to move the data
|
|
- such that it starts just after the terminating NULL in the
|
|
- environment list.
|
|
+ Note: directly invoked ld.so can move arguments and env vars.
|
|
|
|
We use memmove, since the locations might overlap. */
|
|
- if (__libc_enable_secure || _dl_skip_args)
|
|
- {
|
|
- char **newp;
|
|
|
|
- for (newp = _environ; *newp++;);
|
|
+ char **newp;
|
|
+ for (newp = _environ; *newp++;);
|
|
|
|
- if (_dl_argv[-_dl_skip_args] == (char *) p)
|
|
+ if (newp != p || _dl_argv[0] != orig_argv0)
|
|
+ {
|
|
+ if (orig_argv0 == (char *) p)
|
|
{
|
|
if ((char *) newp != _dl_argv[0])
|
|
{
|