mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-07 18:30:28 +00:00
Inject path as COSMOPOLITAN_PROGRAM_EXECUTABLE
`argv[0]` was previously being used as a communication channel between the loader and the binary, giving the binary its full path for use e.g. in `GetProgramExecutableName`. But `argv[0]` is not a good channel for this; much of what made2a3813c6
so gross is due to that. This change fixes the issue by preserving `argv[0]` and establishing a new communication channel: `COSMOPOLITAN_PROGRAM_EXECUTABLE`. The M1 loader will always set this as the first variable. Linux should soon follow. On the other side, `GetProgramExecutableName` checks that variable first. If it sees it, it trusts it as-is. A lot of the churn in `ape/ape-m1.c` in this change is actually backing out hacks introduced in2a3813c6
; the best comparison is: git diff 2a3813c6^..
This commit is contained in:
parent
6446a8b6a7
commit
2c204c5907
2 changed files with 54 additions and 38 deletions
78
ape/ape-m1.c
78
ape/ape-m1.c
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include <assert.h>
|
||||||
#include <dispatch/dispatch.h>
|
#include <dispatch/dispatch.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -35,6 +36,10 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define pagesz 16384
|
#define pagesz 16384
|
||||||
|
#define VARNAME "COSMOPOLITAN_PROGRAM_EXECUTABLE="
|
||||||
|
#define VARSIZE (sizeof(VARNAME) - 1)
|
||||||
|
/* maximum path size that cosmo can take */
|
||||||
|
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
|
||||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||||
#define SYSLIB_VERSION 8
|
#define SYSLIB_VERSION 8
|
||||||
|
|
||||||
|
@ -198,8 +203,11 @@ struct PathSearcher {
|
||||||
unsigned long namelen;
|
unsigned long namelen;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *syspath;
|
const char *syspath;
|
||||||
char path[1024];
|
char varname[VARSIZE]; // stores "$VARNAME=". must immediately precede path.
|
||||||
|
char path[PATHSIZE];
|
||||||
};
|
};
|
||||||
|
_Static_assert(sizeof(struct PathSearcher) == PATHSIZE + 64,
|
||||||
|
"struct layout");
|
||||||
|
|
||||||
struct ApeLoader {
|
struct ApeLoader {
|
||||||
struct PathSearcher ps;
|
struct PathSearcher ps;
|
||||||
|
@ -313,7 +321,14 @@ __attribute__((__noreturn__)) static void Pexit(const char *c, int failed,
|
||||||
}
|
}
|
||||||
|
|
||||||
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
if (!pathlen && *ps->name != '/') {
|
||||||
|
if (!getcwd(ps->path, sizeof(ps->path) - 1 - ps->namelen)) {
|
||||||
|
Pexit("getcwd", -errno, "failed");
|
||||||
|
}
|
||||||
|
pathlen = strlen(ps->path);
|
||||||
|
} else if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||||
ps->path[pathlen + ps->namelen] = 0;
|
ps->path[pathlen + ps->namelen] = 0;
|
||||||
|
@ -884,8 +899,9 @@ int main(int argc, char **argv, char **envp) {
|
||||||
struct ApeLoader *M;
|
struct ApeLoader *M;
|
||||||
long *sp, *sp2, *auxv;
|
long *sp, *sp2, *auxv;
|
||||||
union ElfEhdrBuf *ebuf;
|
union ElfEhdrBuf *ebuf;
|
||||||
int c, islogin, n, fd, rc;
|
int c, n, fd, rc;
|
||||||
char *p, *pe, *dash_l, *exe, *prog, *shell, *execfn;
|
char *p, *pe, *exe, *prog, *shell, *execfn;
|
||||||
|
char **varpos;
|
||||||
|
|
||||||
/* allocate loader memory in program's arg block */
|
/* allocate loader memory in program's arg block */
|
||||||
n = sizeof(struct ApeLoader);
|
n = sizeof(struct ApeLoader);
|
||||||
|
@ -947,24 +963,15 @@ int main(int argc, char **argv, char **envp) {
|
||||||
M->lib.dlclose = dlclose;
|
M->lib.dlclose = dlclose;
|
||||||
M->lib.dlerror = dlerror;
|
M->lib.dlerror = dlerror;
|
||||||
|
|
||||||
/* there is a common convention of shells being told that they
|
|
||||||
are login shells via the OS prepending a - to their argv[0].
|
|
||||||
the APE system doesn't like it when argv[0] is not the full
|
|
||||||
path of the binary. to rectify this, the loader puts a "-l"
|
|
||||||
flag in argv[1] and ignores the dash. */
|
|
||||||
if ((islogin = argc > 0 && *argv[0] == '-' && (shell = GetEnv(envp, "SHELL"))
|
|
||||||
&& !StrCmp(argv[0] + 1, BaseName(shell)))) {
|
|
||||||
execfn = shell;
|
|
||||||
dash_l = __builtin_alloca(3);
|
|
||||||
memmove(dash_l, "-l", 3);
|
|
||||||
} else {
|
|
||||||
execfn = argc > 0 ? argv[0] : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* getenv("_") is close enough to at_execfn */
|
/* getenv("_") is close enough to at_execfn */
|
||||||
|
execfn = argc > 0 ? argv[0] : 0;
|
||||||
|
varpos = 0;
|
||||||
for (i = 0; envp[i]; ++i) {
|
for (i = 0; envp[i]; ++i) {
|
||||||
if (envp[i][0] == '_' && envp[i][1] == '=') {
|
if (envp[i][0] == '_' && envp[i][1] == '=') {
|
||||||
execfn = envp[i] + 2;
|
execfn = envp[i] + 2;
|
||||||
|
} else if (!memcmp(VARNAME, envp[i], VARSIZE)) {
|
||||||
|
assert(!varpos);
|
||||||
|
varpos = envp + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,24 +982,22 @@ int main(int argc, char **argv, char **envp) {
|
||||||
/* create new bottom of stack for spawned program
|
/* create new bottom of stack for spawned program
|
||||||
system v abi aligns this on a 16-byte boundary
|
system v abi aligns this on a 16-byte boundary
|
||||||
grows down the alloc by poking the guard pages */
|
grows down the alloc by poking the guard pages */
|
||||||
n = (auxv - sp + islogin + AUXV_WORDS + 1) * sizeof(long);
|
n = (auxv - sp + !varpos + AUXV_WORDS + 1) * sizeof(long);
|
||||||
sp2 = (long *)__builtin_alloca(n);
|
sp2 = (long *)__builtin_alloca(n);
|
||||||
if ((long)sp2 & 15) ++sp2;
|
if ((long)sp2 & 15) ++sp2;
|
||||||
for (; n > 0; n -= pagesz) {
|
for (; n > 0; n -= pagesz) {
|
||||||
((char *)sp2)[n - 1] = 0;
|
((char *)sp2)[n - 1] = 0;
|
||||||
}
|
}
|
||||||
if (islogin) {
|
|
||||||
memmove(sp2, sp, 2 * sizeof(long));
|
|
||||||
*((char **)sp2 + 2) = dash_l;
|
|
||||||
memmove(sp2 + 3, sp + 2, (auxv - sp - 2) * sizeof(long));
|
|
||||||
++argc;
|
|
||||||
sp2[0] = argc;
|
|
||||||
} else {
|
|
||||||
memmove(sp2, sp, (auxv - sp) * sizeof(long));
|
memmove(sp2, sp, (auxv - sp) * sizeof(long));
|
||||||
}
|
|
||||||
|
|
||||||
argv = (char **)(sp2 + 1);
|
argv = (char **)(sp2 + 1);
|
||||||
envp = (char **)(sp2 + 1 + argc + 1);
|
envp = (char **)(sp2 + 1 + argc + 1);
|
||||||
|
if (varpos) {
|
||||||
|
varpos = (char **)((long *)varpos - sp + sp2);
|
||||||
|
} else {
|
||||||
|
varpos = envp + i++;
|
||||||
|
*(envp + i) = 0;
|
||||||
|
}
|
||||||
auxv = (long *)(envp + i + 1);
|
auxv = (long *)(envp + i + 1);
|
||||||
sp = sp2;
|
sp = sp2;
|
||||||
|
|
||||||
|
@ -1008,13 +1013,14 @@ int main(int argc, char **argv, char **envp) {
|
||||||
but it will if you say:
|
but it will if you say:
|
||||||
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
|
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
|
||||||
and then use #!/opt/cosmos/bin/bash.ape instead. */
|
and then use #!/opt/cosmos/bin/bash.ape instead. */
|
||||||
|
if (*argv[0] == '-' && (shell = GetEnv(envp, "SHELL")) &&
|
||||||
|
!StrCmp(argv[0] + 1, BaseName(shell))) {
|
||||||
|
execfn = prog = shell;
|
||||||
|
} else {
|
||||||
prog = (char *)sp[1];
|
prog = (char *)sp[1];
|
||||||
|
}
|
||||||
argc = sp[0];
|
argc = sp[0];
|
||||||
argv = (char **)(sp + 1);
|
argv = (char **)(sp + 1);
|
||||||
if (islogin) {
|
|
||||||
++argv[0];
|
|
||||||
prog = shell;
|
|
||||||
}
|
|
||||||
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||||
/* if the first argument is a hyphen then we give the user the
|
/* if the first argument is a hyphen then we give the user the
|
||||||
power to change argv[0] or omit it entirely. most operating
|
power to change argv[0] or omit it entirely. most operating
|
||||||
|
@ -1056,11 +1062,11 @@ int main(int argc, char **argv, char **envp) {
|
||||||
}
|
}
|
||||||
pe = ebuf->buf + rc;
|
pe = ebuf->buf + rc;
|
||||||
|
|
||||||
/* resolve argv[0] to reflect path search */
|
/* inject program executable as first environment variable,
|
||||||
if (argc > 0 && ((*prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) ||
|
swapping the old first variable for it. */
|
||||||
M->ps.indirect || !StrCmp(BaseName(prog), argv[0]))) {
|
memmove(M->ps.varname, VARNAME, VARSIZE);
|
||||||
argv[0] = exe;
|
*varpos = *envp;
|
||||||
}
|
*envp = M->ps.varname;
|
||||||
|
|
||||||
/* generate some hard random data */
|
/* generate some hard random data */
|
||||||
if ((rc = sys_getentropy(M->rando, sizeof(M->rando))) < 0) {
|
if ((rc = sys_getentropy(M->rando, sizeof(M->rando))) < 0) {
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#define KERN_PROC 14
|
#define KERN_PROC 14
|
||||||
#define KERN_PROC_PATHNAME_FREEBSD 12
|
#define KERN_PROC_PATHNAME_FREEBSD 12
|
||||||
#define KERN_PROC_PATHNAME_NETBSD 5
|
#define KERN_PROC_PATHNAME_NETBSD 5
|
||||||
|
#define VARNAME "COSMOPOLITAN_PROGRAM_EXECUTABLE="
|
||||||
|
#define VARSIZE (sizeof(VARNAME) - 1)
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
atomic_uint once;
|
atomic_uint once;
|
||||||
|
@ -77,6 +79,13 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
goto CopyString;
|
goto CopyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* new-style loader supplies the full program path as the first
|
||||||
|
environment variable; if it is defined, trust it as-is. */
|
||||||
|
if (*__envp && !strncmp(*__envp, VARNAME, VARSIZE)) {
|
||||||
|
strlcpy(g_prog.u.buf, *__envp + VARSIZE, sizeof(g_prog.u.buf));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// if argv[0] exists then turn it into an absolute path. we also try
|
// if argv[0] exists then turn it into an absolute path. we also try
|
||||||
// adding a .com suffix since the ape auto-appends it when resolving
|
// adding a .com suffix since the ape auto-appends it when resolving
|
||||||
if ((q = __argv[0])) {
|
if ((q = __argv[0])) {
|
||||||
|
@ -146,6 +155,7 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*p = 0;
|
*p = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't even have that then empty the string
|
// if we don't even have that then empty the string
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue