@@ -397,7 +397,8 @@ extern struct rtld_global_ro _rtld_local_ro
static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
- ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv);
+ ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv,
+ void **start_argptr);
/* These two variables cannot be moved into .data.rel.ro. */
static struct libname_list _dl_rtld_libname;
@@ -1306,11 +1307,60 @@ rtld_setup_main_map (struct link_map *main_map)
return has_interp;
}
+static void
+_dl_start_args_adjust (void **start_argptr, int skip_args)
+{
+ void **sp = start_argptr;
+ void **p;
+ long argc;
+ char **argv;
+
+ if (skip_args == 0)
+ return;
+
+ /* Adjust argc on stack. */
+ argc = (long) sp[0] - skip_args;
+ sp[0] = (void *) argc;
+
+ argv = (char **) (sp + 1); /* Necessary aliasing violation. */
+ p = sp + skip_args;
+ /* Shuffle argv down. */
+ do
+ *++sp = *++p;
+ while (*p != NULL);
+
+ /* Shuffle envp down. */
+ do
+ *++sp = *++p;
+ while (*p != NULL);
+
+ /* Update globals in rtld. */
+ _dl_argv = argv;
+ _environ = argv + argc + 1;
+#ifdef HAVE_AUX_VECTOR
+ GLRO(dl_auxv) = (ElfW(auxv_t) *) (sp + 1); /* Aliasing violation. */
+
+ /* Shuffle auxv down. */
+ void *a, *b; /* Use a pair of pointers for an auxv entry. */
+ unsigned long a_type;
+ do
+ {
+ a_type = ((ElfW(auxv_t) *) (p + 1))->a_type;
+ a = *++p;
+ b = *++p;
+ *++sp = a;
+ *++sp = b;
+ }
+ while (a_type != AT_NULL);
+#endif
+}
+
static void
dl_main (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
ElfW(Addr) *user_entry,
- ElfW(auxv_t) *auxv)
+ ElfW(auxv_t) *auxv,
+ void **start_argptr)
{
struct link_map *main_map;
size_t file_size;
@@ -1359,6 +1409,7 @@ dl_main (const ElfW(Phdr) *phdr,
rtld_is_main = true;
char *argv0 = NULL;
+ int skip_args = 0;
/* Note the place where the dynamic linker actually came from. */
GL(dl_rtld_map).l_name = rtld_progname;
@@ -1373,7 +1424,7 @@ dl_main (const ElfW(Phdr) *phdr,
GLRO(dl_lazy) = -1;
}
- ++_dl_skip_args;
+ ++skip_args;
--_dl_argc;
++_dl_argv;
}
@@ -1382,14 +1433,14 @@ dl_main (const ElfW(Phdr) *phdr,
if (state.mode != rtld_mode_help)
state.mode = rtld_mode_verify;
- ++_dl_skip_args;
+ ++skip_args;
--_dl_argc;
++_dl_argv;
}
else if (! strcmp (_dl_argv[1], "--inhibit-cache"))
{
GLRO(dl_inhibit_cache) = 1;
- ++_dl_skip_args;
+ ++skip_args;
--_dl_argc;
++_dl_argv;
}
@@ -1399,7 +1450,7 @@ dl_main (const ElfW(Phdr) *phdr,
state.library_path = _dl_argv[2];
state.library_path_source = "--library-path";
- _dl_skip_args += 2;
+ skip_args += 2;
_dl_argc -= 2;
_dl_argv += 2;
}
@@ -1408,7 +1459,7 @@ dl_main (const ElfW(Phdr) *phdr,
{
GLRO(dl_inhibit_rpath) = _dl_argv[2];
- _dl_skip_args += 2;
+ skip_args += 2;
_dl_argc -= 2;
_dl_argv += 2;
}
@@ -1416,14 +1467,14 @@ dl_main (const ElfW(Phdr) *phdr,
{
audit_list_add_string (&state.audit_list, _dl_argv[2]);
- _dl_skip_args += 2;
+ 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;
+ skip_args += 2;
_dl_argc -= 2;
_dl_argv += 2;
}
@@ -1431,7 +1482,7 @@ dl_main (const ElfW(Phdr) *phdr,
{
argv0 = _dl_argv[2];
- _dl_skip_args += 2;
+ skip_args += 2;
_dl_argc -= 2;
_dl_argv += 2;
}
@@ -1439,7 +1490,7 @@ dl_main (const ElfW(Phdr) *phdr,
&& _dl_argc > 2)
{
state.glibc_hwcaps_prepend = _dl_argv[2];
- _dl_skip_args += 2;
+ skip_args += 2;
_dl_argc -= 2;
_dl_argv += 2;
}
@@ -1447,7 +1498,7 @@ dl_main (const ElfW(Phdr) *phdr,
&& _dl_argc > 2)
{
state.glibc_hwcaps_mask = _dl_argv[2];
- _dl_skip_args += 2;
+ skip_args += 2;
_dl_argc -= 2;
_dl_argv += 2;
}
@@ -1456,7 +1507,7 @@ dl_main (const ElfW(Phdr) *phdr,
{
state.mode = rtld_mode_list_tunables;
- ++_dl_skip_args;
+ ++skip_args;
--_dl_argc;
++_dl_argv;
}
@@ -1465,7 +1516,7 @@ dl_main (const ElfW(Phdr) *phdr,
{
state.mode = rtld_mode_list_diagnostics;
- ++_dl_skip_args;
+ ++skip_args;
--_dl_argc;
++_dl_argv;
}
@@ -1511,7 +1562,7 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_usage (ld_so_name, NULL);
}
- ++_dl_skip_args;
+ ++skip_args;
--_dl_argc;
++_dl_argv;
@@ -1610,6 +1661,8 @@ 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 (start_argptr, skip_args);
}
else
{
@@ -1165,7 +1165,8 @@ extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
ElfW(Addr) *user_entry,
- ElfW(auxv_t) *auxv))
+ ElfW(auxv_t) *auxv,
+ void **start_argptr))
attribute_hidden;
extern void _dl_sysdep_start_cleanup (void) attribute_hidden;
@@ -72,10 +72,11 @@ ElfW(Addr)
_dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
ElfW(Addr) *user_entry,
- ElfW(auxv_t) *auxv))
+ ElfW(auxv_t) *auxv, 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;
@@ -169,34 +172,29 @@ _dl_sysdep_start (void **start_argptr,
up and leave us to transfer control to USER_ENTRY. */
(*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
_dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
- (ElfW(Addr) *) &_dl_hurd_data->user_entry, NULL);
+ (ElfW(Addr) *) &_dl_hurd_data->user_entry, NULL,
+ (void **) argdata);
/* 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
+ or in secure mode it can remove dangerous 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])
{
@@ -98,7 +98,8 @@ _dl_sysdep_parse_arguments (void **start_argptr,
ElfW(Addr)
_dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
- ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv))
+ ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv,
+ void **start_argptr))
{
__libc_stack_end = DL_STACK_END (start_argptr);
@@ -138,7 +139,7 @@ _dl_sysdep_start (void **start_argptr,
__libc_check_standard_fds ();
(*dl_main) (dl_main_args.phdr, dl_main_args.phnum,
- &dl_main_args.user_entry, GLRO(dl_auxv));
+ &dl_main_args.user_entry, GLRO(dl_auxv), start_argptr);
return dl_main_args.user_entry;
}