From daf2156b5a768e7157c501c00cd60c53551c4d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C5=8Dshin?= Date: Thu, 14 Dec 2023 19:32:49 -0500 Subject: [PATCH] New new style program path passing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The M1 loader now passes the program executable name directly as x2, which is the third argument to `cosmo()`. From there it is assigned to `__myname`. `GetProgramExecutableName` now always returns `__myname`, and it is `InitProgramExecutableName`’s job to set that variable if it is not already assigned. `InitProgramExecutableName` now dies if `issetugid()` and `__myname` is null, pending a rework of the path-finding logic. --- ape/ape-m1.c | 34 ++++------------- libc/calls/getprogramexecutablename.greg.c | 38 +++++++++++-------- libc/crt/crt.S | 2 + libc/nexgen32e/myname2.c | 21 ++++++++++ libc/runtime/cosmo2.c | 3 +- libc/runtime/runtime.h | 1 + .../calls/getprogramexecutablename_test.c | 6 --- 7 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 libc/nexgen32e/myname2.c diff --git a/ape/ape-m1.c b/ape/ape-m1.c index 677bf3545..1169338de 100644 --- a/ape/ape-m1.c +++ b/ape/ape-m1.c @@ -36,8 +36,6 @@ #include #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) @@ -203,11 +201,8 @@ struct PathSearcher { unsigned long namelen; const char *name; const char *syspath; - char varname[VARSIZE]; char path[PATHSIZE]; }; -_Static_assert(offsetof(struct PathSearcher, varname) + VARSIZE == - offsetof(struct PathSearcher, path), "struct layout"); struct ApeLoader { struct PathSearcher ps; @@ -563,7 +558,8 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds, __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, long *sp, struct ElfEhdr *e, struct ElfPhdr *p, - struct Syslib *lib) { + struct Syslib *lib, + char *path) { long rc; int prot; int flags; @@ -734,10 +730,10 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, close(fd); register long *x0 __asm__("x0") = sp; + register char *x2 __asm__("x2") = path; register struct Syslib *x15 __asm__("x15") = lib; register long x16 __asm__("x16") = e->e_entry; __asm__ volatile("mov\tx1,#0\n\t" - "mov\tx2,#0\n\t" "mov\tx3,#0\n\t" "mov\tx4,#0\n\t" "mov\tx5,#0\n\t" @@ -767,7 +763,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, "mov\tx0,#0\n\t" "br\tx16" : /* no outputs */ - : "r"(x0), "r"(x15), "r"(x16) + : "r"(x0), "r"(x2), "r"(x15), "r"(x16) : "memory"); __builtin_unreachable(); } @@ -891,7 +887,7 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf, auxv[28] = 0; /* we're now ready to load */ - Spawn(exe, fd, sp, e, p, &M->lib); + Spawn(exe, fd, sp, e, p, &M->lib, M->ps.path); } int main(int argc, char **argv, char **envp) { @@ -901,7 +897,7 @@ int main(int argc, char **argv, char **envp) { long *sp, *sp2, *auxv; union ElfEhdrBuf *ebuf; char *p, *pe, *exe, *prog, - *execfn, *shell, **varpos; + *execfn, *shell; /* allocate loader memory in program's arg block */ n = sizeof(struct ApeLoader); @@ -965,13 +961,9 @@ int main(int argc, char **argv, char **envp) { /* getenv("_") is close enough to at_execfn */ execfn = argc > 0 ? argv[0] : 0; - varpos = 0; for (i = 0; envp[i]; ++i) { if (envp[i][0] == '_' && envp[i][1] == '=') { execfn = envp[i] + 2; - } else if (!memcmp(VARNAME, envp[i], VARSIZE)) { - assert(!varpos); - varpos = envp + i; } } @@ -982,7 +974,7 @@ int main(int argc, char **argv, char **envp) { /* create new bottom of stack for spawned program system v abi aligns this on a 16-byte boundary grows down the alloc by poking the guard pages */ - n = (auxv - sp + !varpos + AUXV_WORDS + 1) * sizeof(long); + n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long); sp2 = (long *)__builtin_alloca(n); if ((long)sp2 & 15) ++sp2; for (; n > 0; n -= pagesz) { @@ -991,12 +983,6 @@ int main(int argc, char **argv, char **envp) { memmove(sp2, sp, (auxv - sp) * sizeof(long)); argv = (char **)(sp2 + 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); sp = sp2; @@ -1061,12 +1047,6 @@ int main(int argc, char **argv, char **envp) { } pe = ebuf->buf + rc; - /* inject program executable as first environment variable, - swapping the old first variable for it. */ - memmove(M->ps.varname, VARNAME, VARSIZE); - *varpos = *envp; - *envp = M->ps.varname; - /* generate some hard random data */ if ((rc = sys_getentropy(M->rando, sizeof(M->rando))) < 0) { Pexit(argv[0], rc, "getentropy"); diff --git a/libc/calls/getprogramexecutablename.greg.c b/libc/calls/getprogramexecutablename.greg.c index 247f2fae6..84a030953 100644 --- a/libc/calls/getprogramexecutablename.greg.c +++ b/libc/calls/getprogramexecutablename.greg.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/atomic.h" #include "libc/calls/calls.h" #include "libc/calls/metalfile.internal.h" @@ -51,6 +52,11 @@ static inline int IsAlpha(int c) { } static inline void InitProgramExecutableNameImpl(void) { + if (__myname) { + return; + } + npassert(!issetugid()); // TODO(mrdomino): pathname security + // https://github.com/jart/cosmopolitan/issues/991 if (IsWindows()) { int n = GetModuleFileName(0, g_prog.u.buf16, ARRAYLEN(g_prog.u.buf16)); @@ -69,21 +75,20 @@ static inline void InitProgramExecutableNameImpl(void) { g_prog.u.buf16[2] = '/'; } tprecode16to8(g_prog.u.buf, sizeof(g_prog.u.buf), g_prog.u.buf16); - return; + goto UseBuf; } char c, *q; if (IsMetal()) { - q = APE_COM_NAME; - goto CopyString; + __myname = APE_COM_NAME; + return; } - /* the new-style loader supplies the full program path as the first - environment variable. in the spirit of Postel's Law ("be liberal - in what you accept"), we use __getenv to read it. */ + /* the previous loader supplied the full program path as the first + environment variable. */ if ((q = __getenv(__envp, "COSMOPOLITAN_PROGRAM_EXECUTABLE").s)) { strlcpy(g_prog.u.buf, q, sizeof(g_prog.u.buf)); - return; + goto UseBuf; } // if argv[0] exists then turn it into an absolute path. we also try @@ -107,10 +112,10 @@ static inline void InitProgramExecutableNameImpl(void) { } } *p = 0; - if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return; + if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) goto UseBuf; p = WRITE32LE(p, READ32LE(".com")); *p = 0; - if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return; + if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) goto UseBuf; } // if getenv("_") exists then use that @@ -127,7 +132,7 @@ static inline void InitProgramExecutableNameImpl(void) { if ((got = sys_readlinkat(AT_FDCWD, "/proc/self/exe", b, n)) > 0 || (got = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", b, n)) > 0) { b[got] = 0; - return; + goto UseBuf; } if (IsFreebsd() || IsNetbsd()) { int cmd[4]; @@ -140,7 +145,7 @@ static inline void InitProgramExecutableNameImpl(void) { } cmd[3] = -1; // current process if (sys_sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) { - return; + goto UseBuf; } } @@ -155,14 +160,17 @@ static inline void InitProgramExecutableNameImpl(void) { } } *p = 0; - return; + goto UseBuf; } // if we don't even have that then empty the string g_prog.u.buf[0] = 0; + +UseBuf: + __myname = g_prog.u.buf; } -void __InitProgramExecutableName(void) { +static void InitProgramExecutableName(void) { int e = errno; InitProgramExecutableNameImpl(); errno = e; @@ -172,6 +180,6 @@ void __InitProgramExecutableName(void) { * Returns absolute path of program. */ char *GetProgramExecutableName(void) { - cosmo_once(&g_prog.once, __InitProgramExecutableName); - return g_prog.u.buf; + cosmo_once(&g_prog.once, InitProgramExecutableName); + return __myname; } diff --git a/libc/crt/crt.S b/libc/crt/crt.S index b37ded5e1..6d2a798df 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -140,6 +140,8 @@ _start: // should be set to zero on other platforms mov x1,x15 +// third arg (x2) is the program path passed by ape-m1.c + // switch to c code bl cosmo .unreachable diff --git a/libc/nexgen32e/myname2.c b/libc/nexgen32e/myname2.c new file mode 100644 index 000000000..e95a67ddf --- /dev/null +++ b/libc/nexgen32e/myname2.c @@ -0,0 +1,21 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/runtime.h" + +char *__myname; diff --git a/libc/runtime/cosmo2.c b/libc/runtime/cosmo2.c index 5832dfcd6..06289578c 100644 --- a/libc/runtime/cosmo2.c +++ b/libc/runtime/cosmo2.c @@ -78,7 +78,7 @@ static const char *DecodeMagnum(const char *p, long *r) { return *r = x, p; } -wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) { +wontreturn textstartup void cosmo(long *sp, struct Syslib *m1, char *myname) { // get startup timestamp as early as possible // its used by --strace and also kprintf() %T @@ -110,6 +110,7 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) { environ = envp; program_invocation_name = argv[0]; __oldstack = (intptr_t)sp; + __myname = myname; // detect apple m1 environment const char *magnums; diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index 364f4d26d..30fa713e3 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -71,6 +71,7 @@ extern char **__argv; extern char **__envp; extern unsigned long *__auxv; extern intptr_t __oldstack; +extern char *__myname; extern uint64_t __nosync; extern int __strace; extern int __ftrace; diff --git a/test/libc/calls/getprogramexecutablename_test.c b/test/libc/calls/getprogramexecutablename_test.c index 38945bd66..61c9ed914 100644 --- a/test/libc/calls/getprogramexecutablename_test.c +++ b/test/libc/calls/getprogramexecutablename_test.c @@ -108,9 +108,3 @@ TEST(GetProgramExecutableName, movedSelf) { abort(); EXITS(0); } - -void __InitProgramExecutableName(void); - -BENCH(GetProgramExecutableName, bench) { - EZBENCH2("Init", donothing, __InitProgramExecutableName()); -}