From 38f876aee70117424ed04dc2f41868c269134081 Mon Sep 17 00:00:00 2001 From: Gavin Hayes Date: Wed, 1 Feb 2023 01:17:46 -0500 Subject: [PATCH] implement zipos mmap --- libc/runtime/mmap.c | 4 +++ libc/zipos/mmap.c | 58 +++++++++++++++++++++++++++++++++++ libc/zipos/open.c | 4 +-- libc/zipos/zipos.S | 1 + libc/zipos/zipos.internal.h | 1 + test/libc/runtime/mmap_test.c | 13 ++++++++ test/libc/runtime/test.mk | 1 + 7 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 libc/zipos/mmap.c diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 946169be9..89e61c02d 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -50,6 +50,7 @@ #include "libc/sysv/consts/prot.h" #include "libc/sysv/errfuns.h" #include "libc/thread/thread.h" +#include "libc/zipos/zipos.internal.h" #define MAP_ANONYMOUS_linux 0x00000020 #define MAP_ANONYMOUS_openbsd 0x00001000 @@ -485,6 +486,9 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { void *res; size_t toto; + if (__isfdkind(fd, kFdZip)) { + return _weaken(__zipos_mmap)(addr, size, prot, flags, (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, off); + } #if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE) if (IsWindows()) { STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size, diff --git a/libc/zipos/mmap.c b/libc/zipos/mmap.c new file mode 100644 index 000000000..c94077867 --- /dev/null +++ b/libc/zipos/mmap.c @@ -0,0 +1,58 @@ +/*-*- 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 2023 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/struct/iovec.h" +#include "libc/dce.h" +#include "libc/intrin/likely.h" +#include "libc/intrin/strace.internal.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/errfuns.h" +#include "libc/zipos/zipos.internal.h" + +#define IP(X) (intptr_t)(X) +#define VIP(X) (void *)IP(X) + +void *__zipos_mmap(void *addr, size_t size, int prot, int flags, struct ZiposHandle *h, int64_t off) { + if (VERY_UNLIKELY(!!(flags & MAP_ANONYMOUS))) { + STRACE("fd anonymous mismatch"); + return VIP(einval()); + } + + if (VERY_UNLIKELY(!(!!(prot & PROT_WRITE) ^ !!(flags & MAP_SHARED)))) { + STRACE("PROT_WRITE and MAP_SHARED on zipos"); + return VIP(eacces()); + } + + const int tempProt = !IsXnu() ? prot | PROT_WRITE : PROT_WRITE; + void *outAddr = mmap(addr, size, tempProt, flags | MAP_ANONYMOUS, -1, 0); + if (outAddr == MAP_FAILED) { + return MAP_FAILED; + } + const int64_t beforeOffset = __zipos_lseek(h, 0, SEEK_CUR); + if ((beforeOffset == -1) || (__zipos_read(h, &(struct iovec){outAddr, size}, 1, off) == -1)) { + munmap(outAddr, size); + return MAP_FAILED; + } + __zipos_lseek(h, beforeOffset, SEEK_SET); + if(prot != tempProt) { + mprotect(outAddr, size, prot); + } + return outAddr; +} diff --git a/libc/zipos/open.c b/libc/zipos/open.c index f4bf473af..930e5d285 100644 --- a/libc/zipos/open.c +++ b/libc/zipos/open.c @@ -48,7 +48,7 @@ static char *mapend; static size_t maptotal; -static void *__zipos_mmap(size_t mapsize) { +static void *__zipos_mmap_space(size_t mapsize) { char *start; size_t offset; _unassert(mapsize); @@ -78,7 +78,7 @@ StartOver: ph = &h->next; } if (!h) { - h = __zipos_mmap(mapsize); + h = __zipos_mmap_space(mapsize); } __zipos_unlock(); if (IsAsan()) { diff --git a/libc/zipos/zipos.S b/libc/zipos/zipos.S index 71cb51978..e0ef33ff3 100644 --- a/libc/zipos/zipos.S +++ b/libc/zipos/zipos.S @@ -34,6 +34,7 @@ .yoink __zipos_read .yoink __zipos_stat .yoink __zipos_notat + .yoink __zipos_mmap // TODO(jart): why does corruption happen when zip has no assets? .yoink .cosmo diff --git a/libc/zipos/zipos.internal.h b/libc/zipos/zipos.internal.h index ccc2aeaf8..6cb78404d 100644 --- a/libc/zipos/zipos.internal.h +++ b/libc/zipos/zipos.internal.h @@ -48,6 +48,7 @@ ssize_t __zipos_write(struct ZiposHandle *, const struct iovec *, size_t, int64_t __zipos_lseek(struct ZiposHandle *, int64_t, unsigned) _Hide; int __zipos_fcntl(int, int, uintptr_t) _Hide; int __zipos_notat(int, const char *) _Hide; +void *__zipos_mmap(void *, uint64_t, int32_t, int32_t, struct ZiposHandle *, int64_t) _Hide; #ifdef _NOPL0 #define __zipos_lock() _NOPL0("__threadcalls", __zipos_lock) diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index ee4a6371f..876a484b7 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -46,6 +46,8 @@ #include "libc/x/xspawn.h" #include "third_party/xed/x86.h" +STATIC_YOINK("zip_uri_support"); + char testlib_enable_tmp_setup_teardown; void SetUpOnce(void) { @@ -219,6 +221,17 @@ TEST(isheap, mallocOffset) { ASSERT_TRUE(_isheap(p + 100000)); } +TEST(mmap, ziposMapFiles) { + int fd; + const char *lifepath = "/zip/life.elf"; + void *p; + + ASSERT_NE(-1, (fd = open(lifepath, O_RDONLY), "%s", lifepath)); + ASSERT_NE(NULL, (p = mmap(NULL, 0x00010000, PROT_READ, MAP_SHARED, fd, 0))); + EXPECT_STREQN("ELF", ((const char *)p)+1, 3); + close(fd); +} + //////////////////////////////////////////////////////////////////////////////// // NON-SHARED READ-ONLY FILE MEMORY diff --git a/test/libc/runtime/test.mk b/test/libc/runtime/test.mk index e1678f71f..f42075df3 100644 --- a/test/libc/runtime/test.mk +++ b/test/libc/runtime/test.mk @@ -51,6 +51,7 @@ o/$(MODE)/test/libc/runtime/runtime.pkg: \ o/$(MODE)/test/libc/runtime/%.com.dbg: \ $(TEST_LIBC_RUNTIME_DEPS) \ + o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \ o/$(MODE)/test/libc/runtime/%.o \ o/$(MODE)/test/libc/runtime/runtime.pkg \ $(LIBC_TESTMAIN) \