diff --git a/libc/calls/fexecve.c b/libc/calls/fexecve.c index 9b26dfed280e..8374fad1cfbc 100644 --- a/libc/calls/fexecve.c +++ b/libc/calls/fexecve.c @@ -33,6 +33,7 @@ #include "libc/intrin/safemacros.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" +#include "libc/paths.h" #include "libc/str/str.h" #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/fd.h" @@ -40,6 +41,7 @@ #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" @@ -63,6 +65,57 @@ static int fexecve_impl(const int fd, char *const argv[], char *const envp[]) { return rc; } +#define defer(fn) __attribute__((cleanup(fn))) + +void cleanup_close(int *pFD) { + STRACE("time to close"); + if (*pFD != -1) { + close(*pFD); + } +} +#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) + +static bool ape_to_elf_execve(void *ape, const size_t apesize) { + if (!_weaken(fork) || !_weaken(exit) || !IsLinux()) { + return false; + } + defer_unlink const char *tempfile = "/dev/shm/ape_to_elf_execve_XXXXXX"; + defer_close int fd = open(tempfile, O_RDWR | O_CREAT | O_EXCL, S_IRWXU); + if (fd == -1) { + tempfile = NULL; + return false; + } + if ((sys_ftruncate(fd, apesize, apesize) == -1) || (write(fd, ape, apesize) != apesize)) { + return false; + } + close(fd); + fd = -1; + int child = _weaken(fork)(); + if (child == -1) { + return false; + } else if (child == 0) { + __sys_execve(_PATH_BSHELL, (char *const[]){_PATH_BSHELL, tempfile, "--assimilate", NULL}, (char *const[]){NULL}); + _weaken(exit)(1); + } + int wstatus; + if ((child != waitpid(child, &wstatus, 0)) || !WIFEXITED(wstatus) || (WEXITSTATUS(wstatus) != 0)) { + return false; + } + return ((fd = open(tempfile, O_RDWR, S_IRWXU)) != -1) && (pread(fd, ape, apesize, 0) == apesize); +} + +#undef defer_unlink +#undef defer_close +#undef defer + typedef enum { PTF_NUM = 1 << 0, PTF_NUM2 = 1 << 1, @@ -71,6 +124,7 @@ typedef enum { } PTF_PARSE; static bool ape_to_elf(void *ape, const size_t apesize) { + return ape_to_elf_execve(ape, apesize); static const char printftok[] = "printf '"; static const size_t printftoklen = sizeof(printftok) - 1; const char *tok = memmem(ape, apesize, printftok, printftoklen);