mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 10:50:28 +00:00
reimplement zipos fexecve/execve ontop of APE fexecve implementation
This commit is contained in:
parent
00c4485a1d
commit
16e380d7e0
3 changed files with 59 additions and 27 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue