reimplement zipos fexecve/execve ontop of APE fexecve implementation

This commit is contained in:
Gavin Hayes 2023-02-23 21:06:22 -05:00
parent 00c4485a1d
commit 16e380d7e0
3 changed files with 59 additions and 27 deletions

View file

@ -75,28 +75,21 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
int sys_execve(const char *prog, char *const argv[], char *const envp[]) { int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
size_t i; size_t i;
int e, rc, fd, flags; int e, rc;
char *buf, *newprog; char *buf;
char **shargs; char **shargs;
const char *ape; const char *ape;
struct ZiposUri uri; struct ZiposUri uri;
if (_weaken(__zipos_parseuri)(prog, &uri) != -1) { if (_weaken(__zipos_parseuri) && (_weaken(__zipos_parseuri)(prog, &uri) != -1)) {
if (IsLinux()) { rc = _weaken(__zipos_open)(&uri, O_RDONLY, 0);
newprog = alloca(PATH_MAX); if (rc != -1) {
fd = _weaken(__zipos_uri_to_mem_file)(&uri, newprog); const int zipFD = rc;
prog = newprog; strace_enabled(-1);
} else if (IsFreebsd()) { rc = fexecve(zipFD, argv, envp);
if ((fd = _weaken(__zipos_uri_to_mem_file)(&uri, NULL)) != -1) { close(zipFD);
return sys_fexecve(fd, argv, envp); strace_enabled(+1);
}
} else {
return enosys();
} }
if (fd == -1) { return rc;
return -1;
}
} else {
fd = -1;
} }
e = errno; e = errno;
__sys_execve(prog, argv, envp); __sys_execve(prog, argv, envp);

View file

@ -22,6 +22,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h" #include "libc/calls/cp.internal.h"
#include "libc/calls/execve-sysv.internal.h" #include "libc/calls/execve-sysv.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.internal.h" #include "libc/calls/struct/stat.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -105,13 +106,18 @@ static bool ape_to_elf(void *ape, const size_t apesize) {
return false; return false;
} }
static int ape_fd_to_mem_elf_fd(const int infd, char *path) { /**
* Creates a memfd and copies fd to it.
*
* This does an inplace conversion of APE to ELF when detected!!!!
*/
static int fd_to_mem_fd(const int infd, char *path) {
if (!IsLinux() && !IsFreebsd() || !_weaken(mmap) || !_weaken(munmap)) { if (!IsLinux() && !IsFreebsd() || !_weaken(mmap) || !_weaken(munmap)) {
return enosys(); return enosys();
} }
struct stat st; struct stat st;
if (sys_fstat(infd, &st) == -1) { if (fstat(infd, &st) == -1) {
return -1; return -1;
} }
int fd; int fd;
@ -133,7 +139,7 @@ static int ape_fd_to_mem_elf_fd(const int infd, char *path) {
((space = _weaken(mmap)(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, ((space = _weaken(mmap)(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0)) != MAP_FAILED)) { fd, 0)) != MAP_FAILED)) {
ssize_t readRc; ssize_t readRc;
readRc = sys_pread(infd, space, st.st_size, 0, 0); readRc = pread(infd, space, st.st_size, 0);
bool success = readRc != -1; bool success = readRc != -1;
if (success && (st.st_size > 8) && IsAPEMagic(space)) { if (success && (st.st_size > 8) && IsAPEMagic(space)) {
success = ape_to_elf(space, st.st_size); success = ape_to_elf(space, st.st_size);
@ -156,7 +162,7 @@ static int ape_fd_to_mem_elf_fd(const int infd, char *path) {
* Executes binary executable at file descriptor. * Executes binary executable at file descriptor.
* *
* This is only supported on Linux and FreeBSD. APE binaries are * This is only supported on Linux and FreeBSD. APE binaries are
* supported. * supported. Zipos is supported.
* *
* @param fd is opened executable and current file position is ignored * @param fd is opened executable and current file position is ignored
* @return doesn't return on success, otherwise -1 w/ errno * @return doesn't return on success, otherwise -1 w/ errno
@ -172,14 +178,35 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
} else { } else {
STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv), STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv),
DescribeStringList(envp)); DescribeStringList(envp));
rc = fexecve_impl(fd, argv, envp); do {
if ((errno == ENOEXEC) && (IsLinux() || IsFreebsd())) { int fexecvefd = fd;
if (__isfdkind(fd, kFdZip)) {
if(!IsLinux() && !IsFreebsd()) {
rc = enosys();
break;
}
BEGIN_CANCELLATION_POINT;
BLOCK_SIGNALS;
strace_enabled(-1);
rc = fd_to_mem_fd(fd, NULL);
strace_enabled(+1);
ALLOW_SIGNALS;
END_CANCELLATION_POINT;
if(rc == -1) {
break;
}
fexecvefd = rc;
}
rc = fexecve_impl(fexecvefd, argv, envp);
if ((errno != ENOEXEC) || (!IsLinux() && !IsFreebsd())) {
break;
}
int newfd = -1; int newfd = -1;
BEGIN_CANCELLATION_POINT; BEGIN_CANCELLATION_POINT;
BLOCK_SIGNALS; BLOCK_SIGNALS;
strace_enabled(-1); strace_enabled(-1);
if (IsAPEFd(fd)) { if (IsAPEFd(fexecvefd)) {
newfd = ape_fd_to_mem_elf_fd(fd, NULL); newfd = fd_to_mem_fd(fexecvefd, NULL);
} }
strace_enabled(+1); strace_enabled(+1);
ALLOW_SIGNALS; ALLOW_SIGNALS;
@ -187,7 +214,7 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
if (newfd != -1) { if (newfd != -1) {
rc = fexecve_impl(newfd, argv, envp); rc = fexecve_impl(newfd, argv, envp);
} }
} } while (0);
} }
STRACE("fexecve(%d) failed %d% m", fd, rc); STRACE("fexecve(%d) failed %d% m", fd, rc);
return rc; return rc;

View file

@ -107,4 +107,16 @@ TEST(fexecve, zipos) {
if (fd == -1 && errno == ENOSYS) _Exit(42); if (fd == -1 && errno == ENOSYS) _Exit(42);
fexecve(fd, (char *const[]){0}, (char *const[]){0}); fexecve(fd, (char *const[]){0}, (char *const[]){0});
EXITS(42); EXITS(42);
close(fd);
}
TEST(fexecve, ziposAPE) {
if (!IsLinux() && !IsFreebsd()) return;
int fd = open("/zip/life-nomod.com", O_RDONLY);
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);
} }