New new style program path passing

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.
This commit is contained in:
Jōshin 2023-12-14 19:32:49 -05:00
parent 8dbfb77890
commit daf2156b5a
No known key found for this signature in database
7 changed files with 56 additions and 49 deletions

View file

@ -36,8 +36,6 @@
#include <unistd.h>
#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");

View file

@ -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;
}

View file

@ -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

21
libc/nexgen32e/myname2.c Normal file
View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -108,9 +108,3 @@ TEST(GetProgramExecutableName, movedSelf) {
abort();
EXITS(0);
}
void __InitProgramExecutableName(void);
BENCH(GetProgramExecutableName, bench) {
EZBENCH2("Init", donothing, __InitProgramExecutableName());
}