This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
runtime loader replaces argv[0]
- From: Patrick Donnelly <batrick at batbytes dot com>
- To: libc-help at sourceware dot org
- Date: Fri, 15 May 2015 18:04:16 -0400
- Subject: runtime loader replaces argv[0]
- Authentication-results: sourceware.org; auth=none
Hi,
My colleagues and I are using the runtime loader in preservation
software for scientific applications. To be specific, we preserve the
runtime loader implicitly used by the software so that it can be run
again in the future, possibly on a completely different platform (but
using the same or newer kernel). In this context, we are using Linux
but the problems exists for all kernels.
The problem we see is that the glibc loader unconditionally replaces
argv[0]. So if I want to run an application on a different platform
that uses a different loader, I would do this instead:
execve("./preserved/ld-linux.so", ["argv[0]" /* from original
experiment */, "./preserved/application.exe" /* physical exe */,
"argv[1]", ...], [...]);
I would expect the loader to simply strip off its argv[1] and leave
the rest alone. Unfortunately, it sets argv[0] to argv[1], as if we
ran:
execve("./preserved/application.exe", ["./preserved/application.exe",
"argv[1]", ...], [...]);
This prevents us from passing the original argv[0] to the application.
I have attached two C programs that exhibit the problem.
Ironically enough, the software that is most affected by this is the
loader itself. If argv[0] is not a real path (i.e. beginning with ./
or /), then it will readlink("/proc/self/exe") to determine the
physical path. In the original experiment with an argv[0] of "foo",
that's exactly what it does. In the rerun experiment with the
preserved loader, argv[0] is "./preserved/application.exe". So the
loader uses this path incorrectly in subsequent library lookups,
ultimately causing the application to fail.
So as for my question, is there a viable workaround for this or does
anyone have some other suggestion?
--
Patrick Donnelly
#include <glob.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
glob_t g;
if (glob("/usr/lib/ld-[0-9]*so", GLOB_ERR|GLOB_NOSORT, NULL, &g) != 0) {
perror("glob");
exit(EXIT_FAILURE);
}
char *bargv[] = {
"b", /* as if it was run as "$ b 1 2" */
"./b", /* the program ld-[0-9]*.so should load */
"1", /* first arg */
"2", /* second arg */
NULL
};
if (execv(g.gl_pathv[0], bargv) == -1) {
perror("execl");
exit(EXIT_FAILURE);
}
globfree(&g);
return 0;
}
#include <stdio.h>
int main (int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
printf("[%d] '%s'\n", i, argv[i]);
return 0;
}