mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Add fexecve() and map O_EXEC to O_PATH on Linux
This commit is contained in:
parent
6c60793f3a
commit
acd8900071
9 changed files with 161 additions and 5 deletions
|
@ -84,6 +84,7 @@ int execv(const char *, char *const[]);
|
|||
int execve(const char *, char *const[], char *const[]);
|
||||
int execvp(const char *, char *const[]);
|
||||
int execvpe(const char *, char *const[], char *const[]);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int faccessat(int, const char *, int, uint32_t);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
|
|
78
libc/calls/fexecve.c
Normal file
78
libc/calls/fexecve.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fexecve(int, char *const[], char *const[]);
|
||||
|
||||
/**
|
||||
* Executes binary executable at file descriptor.
|
||||
*
|
||||
* This is only supported on Linux and FreeBSD. APE binaries currently
|
||||
* aren't supported.
|
||||
*
|
||||
* @param fd is opened executable and current file position is ignored
|
||||
* @return doesn't return on success, otherwise -1 w/ errno
|
||||
* @raise ENOEXEC if file at `fd` isn't an assimilated ELF executable
|
||||
* @raise ENOSYS on Windows, XNU, OpenBSD, NetBSD, and Metal
|
||||
*/
|
||||
int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
int rc;
|
||||
size_t i;
|
||||
if (!argv || !envp ||
|
||||
(IsAsan() &&
|
||||
(!__asan_is_valid_strlist(argv) || !__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
kprintf(STRACE_PROLOGUE "fexecve(%d, {", fd);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", argv[i]);
|
||||
}
|
||||
kprintf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", envp[i]);
|
||||
}
|
||||
kprintf("})\n");
|
||||
}
|
||||
#endif
|
||||
if (IsLinux()) {
|
||||
char path[14 + 12];
|
||||
FormatInt32(stpcpy(path, "/proc/self/fd/"), fd);
|
||||
rc = __sys_execve(path, argv, envp);
|
||||
} else if (IsFreebsd()) {
|
||||
rc = sys_fexecve(fd, argv, envp);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
}
|
||||
STRACE("fexecve(%d) failed %d% m", fd, rc);
|
||||
return rc;
|
||||
}
|
2
libc/sysv/calls/sys_fexecve.s
Normal file
2
libc/sysv/calls/sys_fexecve.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_fexecve,0xffffff1ecfffffff,globl,hidden
|
|
@ -204,7 +204,7 @@ syscon open O_NOFOLLOW_ANY 0 0x20000000 0 0 0 0 #
|
|||
syscon open O_SYNC 0x00101000 0x00000080 0x00000080 0x00000080 0x00000080 0 # bsd consensus
|
||||
syscon open O_NOCTTY 0x00000100 0x00020000 0x00008000 0x00008000 0x00008000 0 # used for remote viewing (default behavior on freebsd)
|
||||
syscon open O_NOATIME 0x00040000 0 0 0 0 0 # optimize away access time update
|
||||
syscon open O_EXEC 0 0 0x00040000 0 0x04000000 0 # it's specified by posix what does it mean
|
||||
syscon open O_EXEC 0x00200000 0 0x00040000 0 0x04000000 0 # open only for executing (POSIX.1 hack for when file mode is 0111); see fexecve(); O_PATH on Linux
|
||||
syscon open O_SEARCH 0 0 0x00040000 0 0x00800000 0 # it's specified by posix what does it mean
|
||||
syscon open O_DSYNC 0x00001000 0x00400000 0 0x00000080 0x00010000 0 #
|
||||
syscon open O_RSYNC 0x00101000 0 0 0x00000080 0x00020000 0 #
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/consts/syscon.internal.inc"
|
||||
.syscon open,O_EXEC,0,0,0x00040000,0,0x04000000,0
|
||||
.syscon open,O_EXEC,0x00200000,0,0x00040000,0,0x04000000,0
|
||||
|
|
|
@ -673,7 +673,7 @@ scall sys_bsdthread_register 0xfffffffff216efff globl hidden
|
|||
#scall extattr_set_file 0x169fff164fffffff globl
|
||||
#scall extattr_set_link 0x16ffff19cfffffff globl
|
||||
#scall extattrctl 0x168fff163fffffff globl
|
||||
#scall fexecve 0x1d1fff1ecfffffff globl
|
||||
scall sys_fexecve 0xffffff1ecfffffff globl hidden
|
||||
#scall ffclock_getcounter 0xffffff0f1fffffff globl
|
||||
#scall ffclock_getestimate 0xffffff0f3fffffff globl
|
||||
#scall ffclock_setestimate 0xffffff0f2fffffff globl
|
||||
|
|
66
test/libc/calls/fexecve_test.c
Normal file
66
test/libc/calls/fexecve_test.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
int fds[2];
|
||||
char buf[8];
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(fexecve, elfIsUnreadable_mayBeExecuted) {
|
||||
if (!IsLinux() && !IsFreebsd()) 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, 5, open("echo", O_EXEC | O_CLOEXEC));
|
||||
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;
|
||||
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);
|
||||
}
|
|
@ -88,6 +88,16 @@ o/$(MODE)/test/libc/calls/life-nomod.com.dbg: \
|
|||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/calls/fexecve_test.com.dbg: \
|
||||
$(TEST_LIBC_CALLS_DEPS) \
|
||||
o/$(MODE)/test/libc/calls/fexecve_test.o \
|
||||
o/$(MODE)/test/libc/calls/calls.pkg \
|
||||
o/$(MODE)/tool/build/echo.zip.o \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
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: private \
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
STATIC_YOINK("libc/testlib/hyperion.txt");
|
||||
|
|
Loading…
Add table
Reference in a new issue