mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-06 01:40:28 +00:00
Merge 24d1e0865c
into c8383f25b4
This commit is contained in:
commit
d89acf79cd
9 changed files with 259 additions and 152 deletions
|
@ -28,3 +28,11 @@ bool IsApeLoadable(char buf[8]) {
|
|||
READ64LE(buf) == READ64LE("jartsr='") ||
|
||||
READ64LE(buf) == READ64LE("APEDBG='");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if executable image is an APE
|
||||
*/
|
||||
bool IsApeMagic(const char buf[8]) {
|
||||
return READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
READ64LE(buf) == READ64LE("JTqFpD='");
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
rc = _weaken(sys_pledge_linux)(__execpromises, __pledge_mode);
|
||||
}
|
||||
if (!rc) {
|
||||
if (0 && _weaken(__zipos_parseuri) &&
|
||||
if (_weaken(__zipos_parseuri) &&
|
||||
(_weaken(__zipos_parseuri)(prog, &uri) != -1)) {
|
||||
rc = _weaken(__zipos_open)(&uri, O_RDONLY | O_CLOEXEC);
|
||||
if (rc != -1) {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#define COSMOPOLITAN_LIBC_CALLS_EXECVE_SYSV_H_
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
bool IsApeLoadable(char[8]) libcesque;
|
||||
bool IsApeLoadable(char[8]);
|
||||
bool IsApeMagic(const char[8]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_EXECVE_SYSV_H_ */
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -34,6 +35,7 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/proc/execve.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
|
@ -42,12 +44,14 @@
|
|||
#include "libc/sysv/consts/mfd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/shm.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static bool IsAPEFd(const int fd) {
|
||||
char buf[8];
|
||||
return (sys_pread(fd, buf, 8, 0, 0) == 8) && IsApeLoadable(buf);
|
||||
return (sys_pread(fd, buf, 8, 0, 0) == 8) && IsApeMagic(buf);
|
||||
}
|
||||
|
||||
static int fexecve_impl(const int fd, char *const argv[], char *const envp[]) {
|
||||
|
@ -64,50 +68,74 @@ static int fexecve_impl(const int fd, char *const argv[], char *const envp[]) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
PTF_NUM = 1 << 0,
|
||||
PTF_NUM2 = 1 << 1,
|
||||
PTF_NUM3 = 1 << 2,
|
||||
PTF_ANY = 1 << 3
|
||||
} PTF_PARSE;
|
||||
#define defer(fn) __attribute__((cleanup(fn)))
|
||||
|
||||
static bool ape_to_elf(void *ape, const size_t apesize) {
|
||||
static const char printftok[] = "printf '";
|
||||
static const size_t printftoklen = sizeof(printftok) - 1;
|
||||
const char *tok = memmem(ape, apesize, printftok, printftoklen);
|
||||
if (tok) {
|
||||
tok += printftoklen;
|
||||
uint8_t *dest = ape;
|
||||
PTF_PARSE state = PTF_ANY;
|
||||
uint8_t value = 0;
|
||||
for (; tok < (const char *)(dest + apesize); tok++) {
|
||||
if ((state & (PTF_NUM | PTF_NUM2 | PTF_NUM3)) &&
|
||||
(*tok >= '0' && *tok <= '7')) {
|
||||
value = (value << 3) | (*tok - '0');
|
||||
state <<= 1;
|
||||
if (state & PTF_ANY) {
|
||||
*dest++ = value;
|
||||
}
|
||||
} else if (state & PTF_NUM) {
|
||||
break;
|
||||
} else {
|
||||
if (state & (PTF_NUM2 | PTF_NUM3)) {
|
||||
*dest++ = value;
|
||||
}
|
||||
if (*tok == '\\') {
|
||||
state = PTF_NUM;
|
||||
value = 0;
|
||||
} else if (*tok == '\'') {
|
||||
return true;
|
||||
} else {
|
||||
*dest++ = *tok;
|
||||
state = PTF_ANY;
|
||||
}
|
||||
}
|
||||
}
|
||||
void cleanup_close(int *pFD) {
|
||||
STRACE("time to close");
|
||||
if (*pFD != -1) {
|
||||
close(*pFD);
|
||||
}
|
||||
errno = ENOEXEC;
|
||||
return false;
|
||||
}
|
||||
#define defer_close defer(cleanup_close)
|
||||
|
||||
void cleanup_unlink(const char **path) {
|
||||
STRACE("time to unlink");
|
||||
if (*path != NULL) {
|
||||
sys_unlink(*path);
|
||||
}
|
||||
}
|
||||
#define defer_unlink defer(cleanup_unlink)
|
||||
|
||||
#undef defer_unlink
|
||||
#undef defer_close
|
||||
#undef defer
|
||||
|
||||
static inline int isZipFile(const void *data, size_t data_size) {
|
||||
if (!_weaken(GetZipEocd)) {
|
||||
return enosys();
|
||||
}
|
||||
int ziperror;
|
||||
return _weaken(GetZipEocd)(data, data_size, &ziperror) != NULL;
|
||||
}
|
||||
|
||||
static int isFdAZipFile(const int fd) {
|
||||
if (!_weaken(mmap) || !_weaken(munmap) || !_weaken(GetZipEocd) || __vforked) {
|
||||
return enosys();
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1) {
|
||||
return -1;
|
||||
}
|
||||
void *space = _weaken(mmap)(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (space == MAP_FAILED) {
|
||||
return -1;
|
||||
}
|
||||
int rc = isZipFile(space, st.st_size);
|
||||
if(_weaken(munmap)(space, st.st_size) == -1) {
|
||||
return -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FEXEF_ZIP = 1 << 0,
|
||||
FEXEF_APE = 1 << 1
|
||||
} FEXEF;
|
||||
|
||||
static inline int getFexeFlags(const void *data, size_t data_size) {
|
||||
if (!_weaken(GetZipEocd)) {
|
||||
return enosys();
|
||||
}
|
||||
int rc = isZipFile(data, data_size);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
int flags = rc << 0;
|
||||
if (data_size >= 8) {
|
||||
flags |= (int)IsApeMagic(data) << 1;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,7 +143,7 @@ static bool ape_to_elf(void *ape, const size_t apesize) {
|
|||
*
|
||||
* This does an inplace conversion of APE to ELF when detected!!!!
|
||||
*/
|
||||
static int fd_to_mem_fd(const int infd, char *path) {
|
||||
static int fd_to_mem_fd(const int infd, FEXEF *flags) {
|
||||
if ((!IsLinux() && !IsFreebsd()) || !_weaken(mmap) || !_weaken(munmap)) {
|
||||
return enosys();
|
||||
}
|
||||
|
@ -142,23 +170,13 @@ static int fd_to_mem_fd(const int infd, char *path) {
|
|||
ssize_t readRc;
|
||||
readRc = pread(infd, space, st.st_size, 0);
|
||||
bool success = readRc != -1;
|
||||
if (success && (st.st_size > 8) && IsApeLoadable(space)) {
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
if ((success = (flags != -1) &&
|
||||
(fcntl(fd, F_SETFD, flags & (~FD_CLOEXEC)) != -1) &&
|
||||
ape_to_elf(space, st.st_size))) {
|
||||
const int newfd = fcntl(fd, F_DUPFD, 9001);
|
||||
if (newfd != -1) {
|
||||
close(fd);
|
||||
fd = newfd;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
int fexe_flags = getFexeFlags(space, st.st_size);
|
||||
success = fexe_flags != -1;
|
||||
*flags = fexe_flags;
|
||||
}
|
||||
const int e = errno;
|
||||
if ((_weaken(munmap)(space, st.st_size) != -1) && success) {
|
||||
if (path) {
|
||||
FormatInt32(stpcpy(path, "COSMOPOLITAN_INIT_ZIPOS="), fd);
|
||||
}
|
||||
unassert(readRc == st.st_size);
|
||||
return fd;
|
||||
} else if (!success) {
|
||||
|
@ -175,9 +193,9 @@ static int fd_to_mem_fd(const int infd, char *path) {
|
|||
* Executes binary executable at file descriptor.
|
||||
*
|
||||
* This is only supported on Linux and FreeBSD. APE binaries are
|
||||
* supported. Zipos is supported. Zipos fds or FD_CLOEXEC APE fds or
|
||||
* fds that fail fexecve with ENOEXEC are copied to a new memfd (with
|
||||
* in-memory APE to ELF conversion) and fexecve is (re)attempted.
|
||||
* supported. Zipos is supported. Zipos fds are copied to a new memfd. Zip files
|
||||
* and APE files are F_DUPFD to a high number with FD_CLOEXEC turned off. APE
|
||||
* files are ran with execve.
|
||||
*
|
||||
* @param fd is opened executable and current file position is ignored
|
||||
* @return doesn't return on success, otherwise -1 w/ errno
|
||||
|
@ -193,55 +211,91 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
|
|||
} else {
|
||||
STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
int savedErr = 0;
|
||||
int newfd = fd;
|
||||
do {
|
||||
if (!IsLinux() && !IsFreebsd()) {
|
||||
rc = enosys();
|
||||
break;
|
||||
}
|
||||
if (!__isfdkind(fd, kFdZip)) {
|
||||
bool memfdReq;
|
||||
FEXEF fflags;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
memfdReq = ((rc = fcntl(fd, F_GETFD)) != -1) && (rc & FD_CLOEXEC) &&
|
||||
IsAPEFd(fd);
|
||||
newfd = fd_to_mem_fd(fd, &fflags);
|
||||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
if (rc == -1) {
|
||||
if (newfd == -1) {
|
||||
break;
|
||||
} else if (!memfdReq) {
|
||||
fexecve_impl(fd, argv, envp);
|
||||
if (errno != ENOEXEC) {
|
||||
}
|
||||
} else {
|
||||
if (!__vforked) {
|
||||
int isFdAZipFileRc;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
isFdAZipFileRc = isFdAZipFile(newfd);
|
||||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
if (isFdAZipFileRc == -1) {
|
||||
break;
|
||||
}
|
||||
savedErr = ENOEXEC;
|
||||
fflags = isFdAZipFileRc << 0;
|
||||
}
|
||||
bool isAPE;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
isAPE = IsAPEFd(newfd);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
fflags |= (int)isAPE << 1;
|
||||
}
|
||||
int newfd;
|
||||
char *path = alloca(PATH_MAX);
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
newfd = fd_to_mem_fd(fd, path);
|
||||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
if (newfd == -1) {
|
||||
if (fflags) {
|
||||
int flags;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
flags = fcntl(newfd, F_GETFD);
|
||||
if (flags != -1) {
|
||||
flags = fcntl(newfd, F_SETFD, flags & (~FD_CLOEXEC));
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
if (flags == -1) {
|
||||
break;
|
||||
}
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
const int highfd = fcntl(newfd, F_DUPFD, 9001);
|
||||
if (highfd != -1) {
|
||||
close(newfd);
|
||||
newfd = highfd;
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
}
|
||||
if (fflags & FEXEF_ZIP) {
|
||||
char *path = alloca(PATH_MAX);
|
||||
FormatInt32(stpcpy(path, "COSMOPOLITAN_INIT_ZIPOS="), newfd);
|
||||
size_t numenvs;
|
||||
for (numenvs = 0; envp[numenvs];) ++numenvs;
|
||||
static _Thread_local char *envs[500];
|
||||
memcpy(envs, envp, numenvs * sizeof(char *));
|
||||
envs[numenvs] = path;
|
||||
envs[numenvs + 1] = NULL;
|
||||
envp = envs;
|
||||
}
|
||||
if (fflags & FEXEF_APE) {
|
||||
char path[14 + 12];
|
||||
FormatInt32(stpcpy(path, "/dev/fd/"), newfd);
|
||||
sys_execve(path, argv, envp);
|
||||
break;
|
||||
}
|
||||
size_t numenvs;
|
||||
for (numenvs = 0; envp[numenvs];) ++numenvs;
|
||||
// const size_t desenvs = min(500, max(numenvs + 1, 2));
|
||||
static _Thread_local char *envs[500];
|
||||
memcpy(envs, envp, numenvs * sizeof(char *));
|
||||
envs[numenvs] = path;
|
||||
envs[numenvs + 1] = NULL;
|
||||
fexecve_impl(newfd, argv, envs);
|
||||
if (!savedErr) {
|
||||
savedErr = errno;
|
||||
}
|
||||
fexecve_impl(newfd, argv, envp);
|
||||
} while (0);
|
||||
if (newfd != fd) {
|
||||
int keepErrno = errno;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
|
@ -249,9 +303,7 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
|
|||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
} while (0);
|
||||
if (savedErr) {
|
||||
errno = savedErr;
|
||||
errno = keepErrno;
|
||||
}
|
||||
rc = -1;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,7 @@ TEST_LIBC_CALLS_BINS = \
|
|||
$(TEST_LIBC_CALLS_COMS) \
|
||||
$(TEST_LIBC_CALLS_COMS:%=%.dbg) \
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com \
|
||||
o/$(MODE)/test/libc/calls/life-classic.com \
|
||||
o/$(MODE)/test/libc/calls/zipread.com.dbg \
|
||||
o/$(MODE)/test/libc/calls/zipread.com
|
||||
o/$(MODE)/test/libc/calls/life-classic.com
|
||||
|
||||
TEST_LIBC_CALLS_TESTS = \
|
||||
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
|
||||
|
@ -118,8 +116,7 @@ o/$(MODE)/test/libc/calls/life-nomod.com.dbg: \
|
|||
|
||||
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o \
|
||||
o/$(MODE)/test/libc/calls/life-classic.com.zip.o \
|
||||
o/$(MODE)/test/libc/calls/zipread.com.zip.o: private \
|
||||
o/$(MODE)/test/libc/calls/life-classic.com.zip.o: private \
|
||||
ZIPOBJ_FLAGS += \
|
||||
-B
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ TEST_LIBC_PROC_COMS = \
|
|||
|
||||
TEST_LIBC_PROC_BINS = \
|
||||
$(TEST_LIBC_PROC_COMS) \
|
||||
$(TEST_LIBC_PROC_COMS:%=%.dbg)
|
||||
$(TEST_LIBC_PROC_COMS:%=%.dbg) \
|
||||
o/$(MODE)/test/libc/proc/zipread.com.dbg \
|
||||
o/$(MODE)/test/libc/proc/zipread.com
|
||||
|
||||
TEST_LIBC_PROC_TESTS = \
|
||||
$(TEST_LIBC_PROC_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
|
||||
|
@ -90,6 +92,7 @@ o/$(MODE)/test/libc/proc/execve_test.com.dbg: \
|
|||
o/$(MODE)/test/libc/proc/execve_test.o \
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o \
|
||||
o/$(MODE)/test/libc/proc/execve_test_prog1.com.zip.o \
|
||||
o/$(MODE)/test/libc/proc/echo.elf.zip.o \
|
||||
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
|
||||
o/$(MODE)/test/libc/mem/prog/sock.elf.zip.o \
|
||||
o/$(MODE)/test/libc/proc/proc.pkg \
|
||||
|
@ -102,16 +105,38 @@ o/$(MODE)/test/libc/proc/fexecve_test.com.dbg: \
|
|||
$(TEST_LIBC_PROC_DEPS) \
|
||||
o/$(MODE)/test/libc/proc/fexecve_test.o \
|
||||
o/$(MODE)/test/libc/proc/proc.pkg \
|
||||
o/$(MODE)/test/libc/proc/echo.elf.zip.o \
|
||||
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o \
|
||||
o/$(MODE)/test/libc/calls/zipread.com.zip.o \
|
||||
o/$(MODE)/test/libc/proc/zipread.com.zip.o \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/proc/zipread.com.dbg: \
|
||||
$(LIBC_RUNTIME) \
|
||||
o/$(MODE)/test/libc/proc/zipread.o \
|
||||
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/proc/echo.elf: \
|
||||
o/$(MODE)/tool/build/assimilate.com \
|
||||
o/$(MODE)/tool/build/echo.com
|
||||
@$(COMPILE) -wACP -T$@ \
|
||||
build/bootstrap/cp.com \
|
||||
o/$(MODE)/tool/build/echo.com \
|
||||
o/$(MODE)/test/libc/proc/echo.elf
|
||||
@$(COMPILE) -wAASSIMILATE -T$@ \
|
||||
o/$(MODE)/tool/build/assimilate.com -bcef \
|
||||
o/$(MODE)/test/libc/proc/echo.elf
|
||||
|
||||
o/$(MODE)/test/libc/proc/echo.elf.zip.o \
|
||||
o/$(MODE)/test/libc/proc/execve_test_prog1.com.zip.o \
|
||||
o/$(MODE)/test/libc/proc/life-pe.com.zip.o: private \
|
||||
o/$(MODE)/test/libc/proc/life-pe.com.zip.o \
|
||||
o/$(MODE)/test/libc/proc/zipread.com.zip.o: private \
|
||||
ZIPOBJ_FLAGS += \
|
||||
-B
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -26,6 +27,8 @@
|
|||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/temp.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
|
@ -35,6 +38,9 @@ __static_yoink("zipos");
|
|||
|
||||
#define N 16
|
||||
|
||||
int fds[2];
|
||||
char buf[8];
|
||||
bool SupportsFexecve = false;
|
||||
void SetUpOnce(void) {
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
}
|
||||
|
@ -48,6 +54,21 @@ void GenBuf(char buf[8], int x) {
|
|||
}
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
char buf[8];
|
||||
if (__argc == 4 && !strcmp(__argv[1], "-")) {
|
||||
GenBuf(buf, atoi(__argv[2]));
|
||||
ASSERT_STREQ(buf, __argv[3]);
|
||||
exit(0);
|
||||
}
|
||||
if (IsLinux()) {
|
||||
if (!__is_linux_2_6_23()) return;
|
||||
// TODO check for memfd
|
||||
struct stat st;
|
||||
SupportsFexecve = stat("/proc/self/fd", &st) == 0 && S_ISDIR(st.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(execve, testArgPassing) {
|
||||
int i;
|
||||
char ibuf[12], buf[8];
|
||||
|
@ -64,11 +85,27 @@ TEST(execve, testArgPassing) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(execve, elfIsUnreadable_mayBeExecuted) {
|
||||
if (IsWindows() || IsXnu()) return;
|
||||
testlib_extract("/zip/echo.elf", "echo", 0111);
|
||||
ASSERT_SYS(0, 0, pipe2(fds, O_CLOEXEC));
|
||||
SPAWN(vfork);
|
||||
ASSERT_SYS(0, 1, dup2(4, 1));
|
||||
ASSERT_SYS(
|
||||
0, 0,
|
||||
execve("echo", (char *const[]){"echo", "hi", 0}, (char *const[]){0}));
|
||||
exit(1);
|
||||
EXITS(0);
|
||||
bzero(buf, 8);
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 3, read(3, buf, 7));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
ASSERT_STREQ("hi\n", buf);
|
||||
}
|
||||
|
||||
TEST(execve, ziposELF) {
|
||||
if (1) return; // TODO: rewrite
|
||||
if (IsFreebsd()) return; // TODO: fixme on freebsd
|
||||
if (IsLinux() && !__is_linux_2_6_23()) return; // TODO: fixme on old linux
|
||||
if (!IsLinux() && !IsFreebsd()) {
|
||||
if (IsWindows()) return;
|
||||
if (!SupportsFexecve) {
|
||||
EXPECT_SYS(ENOSYS, -1,
|
||||
execve("/zip/life.elf", (char *const[]){0}, (char *const[]){0}));
|
||||
return;
|
||||
|
@ -80,10 +117,7 @@ TEST(execve, ziposELF) {
|
|||
}
|
||||
|
||||
TEST(execve, ziposAPE) {
|
||||
if (1) return; // TODO: rewrite
|
||||
if (IsFreebsd()) return; // TODO: fixme on freebsd
|
||||
if (IsLinux() && !__is_linux_2_6_23()) return; // TODO: fixme on old linux
|
||||
if (!IsLinux() && !IsFreebsd()) {
|
||||
if (!SupportsFexecve) {
|
||||
EXPECT_EQ(-1, execve("/zip/life-nomod.com", (char *const[]){0},
|
||||
(char *const[]){0}));
|
||||
return;
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#if 0 // TODO(G4Vi): improve reliability of fexecve() implementation
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -25,6 +25,7 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/mfd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
// clang-format off
|
||||
|
@ -33,6 +34,7 @@ __static_yoink("zipos");
|
|||
|
||||
int fds[2];
|
||||
char buf[8];
|
||||
uint8_t elf_buf[4096];
|
||||
|
||||
void SetUpOnce(void) {
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
|
@ -41,29 +43,18 @@ void SetUpOnce(void) {
|
|||
void SetUp(void) {
|
||||
if (IsFreebsd()) exit(0); // TODO: fixme on freebsd
|
||||
if (IsLinux() && !__is_linux_2_6_23()) exit(0); // TODO: fixme on old linux
|
||||
}
|
||||
|
||||
TEST(execve, elfIsUnreadable_mayBeExecuted) {
|
||||
if (IsWindows() || IsXnu()) return;
|
||||
testlib_extract("/zip/echo", "echo", 0111);
|
||||
ASSERT_SYS(0, 0, pipe2(fds, O_CLOEXEC));
|
||||
SPAWN(vfork);
|
||||
ASSERT_SYS(0, 1, dup2(4, 1));
|
||||
ASSERT_SYS(
|
||||
0, 0,
|
||||
execve("echo", (char *const[]){"echo", "hi", 0}, (char *const[]){0}));
|
||||
notpossible;
|
||||
EXITS(0);
|
||||
bzero(buf, 8);
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 3, read(3, buf, 7));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
ASSERT_STREQ("hi\n", buf);
|
||||
// linux fexecve relies on execve from /proc
|
||||
if (IsLinux()) {
|
||||
struct stat st;
|
||||
if (stat("/proc/self/fd", &st) != 0 || !S_ISDIR(st.st_mode)) {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(fexecve, elfIsUnreadable_mayBeExecuted) {
|
||||
if (!IsLinux() && !IsFreebsd()) return;
|
||||
testlib_extract("/zip/echo", "echo", 0111);
|
||||
testlib_extract("/zip/echo.elf", "echo", 0111);
|
||||
ASSERT_SYS(0, 0, pipe2(fds, O_CLOEXEC));
|
||||
SPAWN(vfork);
|
||||
ASSERT_SYS(0, 1, dup2(4, 1));
|
||||
|
@ -71,7 +62,7 @@ TEST(fexecve, elfIsUnreadable_mayBeExecuted) {
|
|||
if (IsFreebsd()) ASSERT_SYS(0, 1, lseek(5, 1, SEEK_SET));
|
||||
ASSERT_SYS(0, 0,
|
||||
fexecve(5, (char *const[]){"echo", "hi", 0}, (char *const[]){0}));
|
||||
notpossible;
|
||||
exit(1);
|
||||
EXITS(0);
|
||||
bzero(buf, 8);
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
|
@ -81,23 +72,27 @@ TEST(fexecve, elfIsUnreadable_mayBeExecuted) {
|
|||
}
|
||||
|
||||
TEST(fexecve, memfd_create) {
|
||||
if (1) return; // TODO: fixme
|
||||
if (!IsLinux()) return;
|
||||
SPAWN(vfork);
|
||||
#define TINY_ELF_PROGRAM "\
|
||||
\177\105\114\106\002\001\001\000\000\000\000\000\000\000\000\000\
|
||||
\002\000\076\000\001\000\000\000\170\000\100\000\000\000\000\000\
|
||||
\100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
|
||||
\000\000\000\000\100\000\070\000\001\000\000\000\000\000\000\000\
|
||||
\001\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000\
|
||||
\000\000\100\000\000\000\000\000\000\000\100\000\000\000\000\000\
|
||||
\200\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\
|
||||
\000\020\000\000\000\000\000\000\152\052\137\152\074\130\017\005"
|
||||
int life_fd = open("/zip/life.elf", O_RDONLY);
|
||||
ASSERT_NE(-1, life_fd);
|
||||
int fd = memfd_create("foo", MFD_CLOEXEC);
|
||||
if (fd == -1 && errno == ENOSYS) _Exit(42);
|
||||
write(fd, TINY_ELF_PROGRAM, sizeof(TINY_ELF_PROGRAM) - 1);
|
||||
if(fd == -1) {
|
||||
ASSERT_EQ(ENOSYS, errno);
|
||||
return;
|
||||
}
|
||||
while(1) {
|
||||
const ssize_t bytes_read = read(life_fd, elf_buf, sizeof(elf_buf));
|
||||
if (bytes_read <= 0) {
|
||||
ASSERT_LE(0, bytes_read);
|
||||
break;
|
||||
}
|
||||
ASSERT_EQ(bytes_read, write(fd, elf_buf, bytes_read));
|
||||
}
|
||||
ASSERT_SYS(0, 0, close(life_fd));
|
||||
SPAWN(vfork);
|
||||
fexecve(fd, (char *const[]){0}, (char *const[]){0});
|
||||
EXITS(42);
|
||||
ASSERT_SYS(0, 0, close(fd));
|
||||
}
|
||||
|
||||
TEST(fexecve, APE) {
|
||||
|
@ -141,16 +136,11 @@ TEST(fexecve, ziposAPE) {
|
|||
}
|
||||
|
||||
TEST(fexecve, ziposAPEHasZipos) {
|
||||
if (1) return; // TODO: fixme
|
||||
if (!IsLinux() && !IsFreebsd()) return;
|
||||
int fd = open("/zip/zipread.com", O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
SPAWN(fork);
|
||||
ASSERT_NE(-1, fd);
|
||||
if (fd == -1 && errno == ENOSYS) _Exit(42);
|
||||
fexecve(fd, (char *const[]){0}, (char *const[]){0});
|
||||
EXITS(42);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue