diff --git a/ape/sections.internal.h b/ape/sections.internal.h index 3e40e8762..8852f8dd1 100644 --- a/ape/sections.internal.h +++ b/ape/sections.internal.h @@ -10,6 +10,10 @@ extern unsigned char _edata[]; extern unsigned char _ezip[]; extern unsigned char _end[]; extern unsigned char _ereal[]; +extern unsigned char _tdata_start[]; +extern unsigned char _tdata_end[]; +extern unsigned char _tbss_start[]; +extern unsigned char _tbss_end[]; extern unsigned char __privileged_start[]; extern unsigned char __privileged_addr[]; extern unsigned char __privileged_size[]; diff --git a/libc/calls/getfiledescriptorsize.c b/libc/calls/getfiledescriptorsize.c index 47721d27c..71eea095b 100644 --- a/libc/calls/getfiledescriptorsize.c +++ b/libc/calls/getfiledescriptorsize.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/metalfile.internal.h" #include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/stat.h" #include "libc/calls/syscall-sysv.internal.h" @@ -60,7 +61,14 @@ ssize_t getfiledescriptorsize(int fd) { rc = -1; } } else if (IsMetal()) { - rc = -1; + if (fd < 0 || fd >= g_fds.n) + rc = ebadf(); + else if (g_fds.p[fd].kind != kFdFile) + rc = eacces(); + else { + struct MetalFile *state = (struct MetalFile *)g_fds.p[fd].handle; + rc = state->size; + } } else if (!IsWindows()) { if (!__sys_fstat(fd, &st)) { rc = METASTAT(st, st_size); diff --git a/libc/calls/metalfile.c b/libc/calls/metalfile.c new file mode 100644 index 000000000..5188ff968 --- /dev/null +++ b/libc/calls/metalfile.c @@ -0,0 +1,70 @@ +/*-*- 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│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ This is free and unencumbered software released into the public domain. │ +│ │ +│ Anyone is free to copy, modify, publish, use, compile, sell, or │ +│ distribute this software, either in source code form or as a compiled │ +│ binary, for any purpose, commercial or non-commercial, and by any │ +│ means. │ +│ │ +│ In jurisdictions that recognize copyright laws, the author or authors │ +│ of this software dedicate any and all copyright interest in the │ +│ software to the public domain. We make this dedication for the benefit │ +│ of the public at large and to the detriment of our heirs and │ +│ successors. We intend this dedication to be an overt act of │ +│ relinquishment in perpetuity of all present and future rights to this │ +│ software under copyright law. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │ +│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │ +│ OTHER DEALINGS IN THE SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/relocations.h" +#include "ape/sections.internal.h" +#include "libc/assert.h" +#include "libc/calls/internal.h" +#include "libc/calls/metalfile.internal.h" +#include "libc/intrin/weaken.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/directmap.internal.h" +#include "libc/runtime/pc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/at.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/errfuns.h" + +#define MAP_ANONYMOUS_linux 0x00000020 +#define MAP_FIXED_linux 0x00000010 +#define MAP_SHARED_linux 0x00000001 + +STATIC_YOINK("_init_metalfile"); + +void *__ape_com_base; +size_t __ape_com_size = 0; + +textstartup void InitializeMetalFile(void) { + if (IsMetal()) { + /* + * Copy out a pristine image of the program — before the program might + * decide to modify its own .data section. Do this only if needed. + */ + size_t size = ROUNDUP(_tdata_end - _base, 4096); + void *copied_base; + struct DirectMap dm; + dm = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0); + copied_base = dm.addr; + _npassert(copied_base != (void *)-1); + memcpy(copied_base, (void *)(BANE + IMAGE_BASE_REAL), size); + __ape_com_base = copied_base; + __ape_com_size = size; + } +} diff --git a/libc/calls/metalfile.internal.h b/libc/calls/metalfile.internal.h index a74a7cd3b..17563585b 100644 --- a/libc/calls/metalfile.internal.h +++ b/libc/calls/metalfile.internal.h @@ -9,9 +9,14 @@ struct MetalFile { size_t pos; }; +extern void *__ape_com_base; +extern size_t __ape_com_size; + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#define APE_COM_NAME "/ape.com" +#define APE_COM_NAME "/ape.com" +#define APE_COM_ALT_NAME "/proc/self/exe" +#define APE_COM_URI "file:/proc/self/exe" #endif /* COSMOPOLITAN_LIBC_CALLS_METALFILE_INTERNAL_H_ */ diff --git a/libc/calls/metalfile_init.S b/libc/calls/metalfile_init.S new file mode 100644 index 000000000..aa6a41b1b --- /dev/null +++ b/libc/calls/metalfile_init.S @@ -0,0 +1,38 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ This is free and unencumbered software released into the public domain. │ +│ │ +│ Anyone is free to copy, modify, publish, use, compile, sell, or │ +│ distribute this software, either in source code form or as a compiled │ +│ binary, for any purpose, commercial or non-commercial, and by any │ +│ means. │ +│ │ +│ In jurisdictions that recognize copyright laws, the author or authors │ +│ of this software dedicate any and all copyright interest in the │ +│ software to the public domain. We make this dedication for the benefit │ +│ of the public at large and to the detriment of our heirs and │ +│ successors. We intend this dedication to be an overt act of │ +│ relinquishment in perpetuity of all present and future rights to this │ +│ software under copyright law. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │ +│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │ +│ OTHER DEALINGS IN THE SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" +#include "libc/calls/metalfile.internal.h" + + .init.start 101,_init_metalfile + push %rdi + push %rsi + call InitializeMetalFile + pop %rsi + pop %rdi + .init.end 101,_init_metalfile +APE_COM_URI: + .endobj APE_COM_URI,globl,hidden diff --git a/libc/calls/openat-metal.c b/libc/calls/openat-metal.c index a3889e377..c49dab405 100644 --- a/libc/calls/openat-metal.c +++ b/libc/calls/openat-metal.c @@ -16,13 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/relocations.h" #include "ape/sections.internal.h" +#include "libc/assert.h" #include "libc/calls/internal.h" #include "libc/calls/metalfile.internal.h" #include "libc/intrin/weaken.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/directmap.internal.h" +#include "libc/runtime/pc.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/at.h" @@ -30,12 +33,16 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/errfuns.h" +#include "libc/zipos/zipos.internal.h" int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) { int fd; struct MetalFile *state; - if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME)) return enoent(); + if (dirfd != AT_FDCWD || (strcmp(file, APE_COM_NAME) && + strcmp(file, APE_COM_ALT_NAME))) return enoent(); if (flags != O_RDONLY) return eacces(); + if (!_weaken(__ape_com_base) || !_weaken(__ape_com_size)) + return eopnotsupp(); if ((fd = __reservefd(-1)) == -1) return -1; if (!_weaken(calloc) || !_weaken(free)) { struct DirectMap dm; @@ -48,8 +55,8 @@ int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) { state = _weaken(calloc)(1, sizeof(struct MetalFile)); if (!state) return -1; } - state->base = (char *)_base; - state->size = _end - _base; + state->base = (char *)__ape_com_base; + state->size = __ape_com_size; g_fds.p[fd].kind = kFdFile; g_fds.p[fd].flags = flags; g_fds.p[fd].mode = mode; diff --git a/libc/zipos/get.c b/libc/zipos/get.c index c08c3d18f..76ffbc5e9 100644 --- a/libc/zipos/get.c +++ b/libc/zipos/get.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/metalfile.internal.h" #include "libc/intrin/cmpxchg.h" #include "libc/intrin/promises.internal.h" #include "libc/intrin/strace.internal.h" @@ -29,6 +30,8 @@ #include "libc/zip.h" #include "libc/zipos/zipos.internal.h" +STATIC_YOINK(APE_COM_URI); + static uint64_t __zipos_get_min_offset(const uint8_t *base, const uint8_t *cdir) { uint64_t i, n, c, r, o;