diff --git a/libc/calls/getprogramexecutablename.greg.c b/libc/calls/getprogramexecutablename.greg.c index 88b631e8a..8908a1af6 100644 --- a/libc/calls/getprogramexecutablename.greg.c +++ b/libc/calls/getprogramexecutablename.greg.c @@ -43,6 +43,7 @@ __static_yoink("_init_program_executable_name"); #define CTL_KERN 1 #define KERN_PROC 14 +#define KERN_PROC_ARGS 48 #define KERN_PROC_PATHNAME_FREEBSD 12 #define KERN_PROC_PATHNAME_NETBSD 5 @@ -173,13 +174,15 @@ static inline void InitProgramExecutableNameImpl(void) { if (IsFreebsd() || IsNetbsd()) { int cmd[4]; cmd[0] = CTL_KERN; - cmd[1] = KERN_PROC; if (IsFreebsd()) { + cmd[1] = KERN_PROC; cmd[2] = KERN_PROC_PATHNAME_FREEBSD; + cmd[3] = -1; // current process } else { - cmd[2] = KERN_PROC_PATHNAME_NETBSD; + cmd[1] = KERN_PROC_ARGS; + cmd[2] = -1; // current process + cmd[3] = KERN_PROC_PATHNAME_NETBSD; } - cmd[3] = -1; // current process if (sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) { if (!OldApeLoader(b)) { goto UseBuf; diff --git a/test/libc/calls/BUILD.mk b/test/libc/calls/BUILD.mk index f76d79b71..4ccc53e61 100644 --- a/test/libc/calls/BUILD.mk +++ b/test/libc/calls/BUILD.mk @@ -73,6 +73,7 @@ o/$(MODE)/test/libc/calls/getprogramexecutablename_test.dbg: \ $(TEST_LIBC_CALLS_DEPS) \ o/$(MODE)/test/libc/calls/getprogramexecutablename_test.o \ o/$(MODE)/test/libc/calls/ape.elf.zip.o \ + o/$(MODE)/test/libc/calls/gpenchild.elf.zip.o \ o/$(MODE)/test/libc/calls/calls.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ @@ -125,14 +126,25 @@ o/$(MODE)/test/libc/calls/life-nomod.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) -o/$(MODE)/test/libc/calls/zipread.dbg: \ - $(LIBC_RUNTIME) \ - o/$(MODE)/test/libc/calls/zipread.o \ - o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \ - $(CRT) \ +o/$(MODE)/test/libc/calls/gpenchild.dbg: \ + $(LIBC_RUNTIME) \ + o/$(MODE)/test/libc/calls/gpenchild.o \ + $(CRT) \ $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/test/libc/calls/gpenchild.elf: \ + o/$(MODE)/tool/build/assimilate \ + o/$(MODE)/test/libc/calls/gpenchild \ + o/$(MODE)/tool/build/cp + @$(COMPILE) -wACP -T$@ \ + o/$(MODE)/tool/build/cp \ + o/$(MODE)/test/libc/calls/gpenchild \ + o/$(MODE)/test/libc/calls/gpenchild.elf + @$(COMPILE) -wAASSIMILATE -T$@ \ + o/$(MODE)/tool/build/assimilate -bcef \ + o/$(MODE)/test/libc/calls/gpenchild.elf + o/$(MODE)/test/libc/calls/ape.elf: \ o/$(MODE)/tool/build/cp \ o/$(MODE)/ape/ape.elf @@ -142,6 +154,7 @@ o/$(MODE)/test/libc/calls/ape.elf: \ o/$(MODE)/test/libc/calls/ape.elf o/$(MODE)/test/libc/calls/ape.elf.zip.o \ +o/$(MODE)/test/libc/calls/gpenchild.elf.zip.o \ o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \ o/$(MODE)/test/libc/calls/life-nomod.zip.o \ o/$(MODE)/test/libc/calls/life-classic.zip.o: private \ diff --git a/test/libc/calls/getprogramexecutablename_test.c b/test/libc/calls/getprogramexecutablename_test.c index 2461bacc8..c9e7fd80f 100644 --- a/test/libc/calls/getprogramexecutablename_test.c +++ b/test/libc/calls/getprogramexecutablename_test.c @@ -19,6 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/metalfile.internal.h" +#include "libc/calls/struct/stat.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" @@ -70,6 +71,18 @@ void SetUpOnce(void) { } } +static bool isAbsPath(const char *path) { + return strlen(path) >= 2 && path[0] == '/' && path[1] != '/'; +} + +static bool isSameFile(const char *a, const char *b) { + struct stat st_a, st_b; + if (stat(a, &st_a) || stat(b, &st_b)) { + return false; + } + return (st_a.st_dev == st_b.st_dev) && (st_a.st_ino == st_b.st_ino); +} + __attribute__((__constructor__)) static void Child(int argc, char *argv[]) { loaded = !!__program_executable_name; if (argc >= 2 && !strcmp(argv[1], "Child")) { @@ -82,7 +95,8 @@ __attribute__((__constructor__)) static void Child(int argc, char *argv[]) { if (rc) { exit(122); } - if (strcmp(argv[2], GetProgramExecutableName())) { + const char *path = GetProgramExecutableName(); + if (!path || !isAbsPath(path) || !isSameFile(argv[2], path)) { exit(123); } if (argc >= 4) { @@ -192,3 +206,23 @@ TEST(GetProgramExecutableName, nullArgvAPELoader) { abort(); EXITS(0); } + +TEST(GetProgramExecutableName, elf) { + if (skiptests || IsOpenbsd() || IsXnu() || IsWindows() || IsMetal()) + return; + char buf[BUFSIZ]; + testlib_extract("/zip/gpenchild.elf", "test.elf", 0555); + ASSERT_NE(NULL, getcwd(buf, BUFSIZ - 5)); + stpcpy(buf + strlen(buf), "/test.elf"); + SPAWN(fork); + execve(buf, (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0}, + (char *[]){0}); + abort(); + EXITS(0); + SPAWN(fork); + execve("./test.elf", + (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0}, + (char *[]){0}); + abort(); + EXITS(0); +} diff --git a/test/libc/calls/gpenchild.c b/test/libc/calls/gpenchild.c new file mode 100644 index 000000000..c72313c88 --- /dev/null +++ b/test/libc/calls/gpenchild.c @@ -0,0 +1,63 @@ +/*-*- 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 │ +│ Copyright 2026 Gavin Arthur Hayes │ +│ │ +│ 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/calls/calls.h" +#include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/dce.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" + +static bool isAbsPath(const char *path) { + return strlen(path) >= 2 && path[0] == '/' && path[1] != '/'; +} + +static bool isSameFile(const char *a, const char *b) { + struct stat st_a, st_b; + if (stat(a, &st_a) || stat(b, &st_b)) { + return false; + } + return (st_a.st_dev == st_b.st_dev) && (st_a.st_ino == st_b.st_ino); +} + +int main(int argc, char *argv[]) { + if (argc >= 2 && !strcmp(argv[1], "Child")) { + int rc; + if (!IsWindows()) { + rc = sys_chdir("/"); + } else { + rc = sys_chdir_nt("/"); + } + if (rc) { + exit(122); + } + const char *path = GetProgramExecutableName(); + if (!path || !isAbsPath(path) || !isSameFile(argv[2], path)) { + exit(123); + } + if (argc >= 4) { + if (strcmp(argv[3], argv[0])) { + exit(124); + } + } + exit(0); + } + exit(128); +}