diff --git a/elf/rtld.c b/elf/rtld.c index 8dafaf61f4..9cc9e5fd4c 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1312,6 +1312,62 @@ rtld_setup_main_map (struct link_map *main_map) return has_interp; } +/* 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, @@ -1366,6 +1422,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; @@ -1380,7 +1437,6 @@ dl_main (const ElfW(Phdr) *phdr, GLRO(dl_lazy) = -1; } - ++_dl_skip_args; --_dl_argc; ++_dl_argv; } @@ -1389,14 +1445,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; } @@ -1406,7 +1460,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; } @@ -1415,7 +1468,6 @@ dl_main (const ElfW(Phdr) *phdr, { GLRO(dl_inhibit_rpath) = _dl_argv[2]; - _dl_skip_args += 2; _dl_argc -= 2; _dl_argv += 2; } @@ -1423,14 +1475,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; } @@ -1438,7 +1488,6 @@ dl_main (const ElfW(Phdr) *phdr, { argv0 = _dl_argv[2]; - _dl_skip_args += 2; _dl_argc -= 2; _dl_argv += 2; } @@ -1446,7 +1495,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; } @@ -1454,7 +1502,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; } @@ -1463,7 +1510,6 @@ dl_main (const ElfW(Phdr) *phdr, { state.mode = rtld_mode_list_tunables; - ++_dl_skip_args; --_dl_argc; ++_dl_argv; } @@ -1472,7 +1518,6 @@ dl_main (const ElfW(Phdr) *phdr, { state.mode = rtld_mode_list_diagnostics; - ++_dl_skip_args; --_dl_argc; ++_dl_argv; } @@ -1518,7 +1563,6 @@ dl_main (const ElfW(Phdr) *phdr, _dl_usage (ld_so_name, NULL); } - ++_dl_skip_args; --_dl_argc; ++_dl_argv; @@ -1617,6 +1661,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 3cbe075615..8373962e62 100644 --- a/sysdeps/mach/hurd/dl-sysdep.c +++ b/sysdeps/mach/hurd/dl-sysdep.c @@ -76,6 +76,7 @@ _dl_sysdep_start (void **start_argptr, { void go (intptr_t *argdata) { + char *orig_argv0; char **p; /* Cache the information in various global variables. */ @@ -84,6 +85,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; @@ -173,30 +176,23 @@ _dl_sysdep_start (void **start_argptr, /* 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++;); + + if (newp != p || _dl_argv[0] != orig_argv0) { - char **newp; - - for (newp = _environ; *newp++;); - - if (_dl_argv[-_dl_skip_args] == (char *) p) + if (orig_argv0 == (char *) p) { if ((char *) newp != _dl_argv[0]) {