mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 10:50:28 +00:00
zipos mmap disallow MAP_SHARED, propgate original errno, add more tests
This commit is contained in:
parent
38f876aee7
commit
7f87f0cc59
2 changed files with 97 additions and 14 deletions
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
|
@ -29,14 +30,32 @@
|
|||
#define IP(X) (intptr_t)(X)
|
||||
#define VIP(X) (void *)IP(X)
|
||||
|
||||
/**
|
||||
* Map zipos file into memory. See mmap.
|
||||
*
|
||||
* @param addr should be 0 or a compatible address
|
||||
* @param size must be >0 and will be rounded up to FRAMESIZE
|
||||
* automatically.
|
||||
* @param prot can have PROT_READ/PROT_WRITE/PROT_EXEC/PROT_NONE/etc.
|
||||
* @param flags cannot have `MAP_SHARED` or `MAP_ANONYMOUS`, there is
|
||||
* no actual file backing for zipos files. `MAP_SHARED` could be
|
||||
* simulated for non-writable mappings, but that would require
|
||||
* tracking zipos mappings to prevent making it PROT_WRITE.
|
||||
* @param h is a zip store object
|
||||
* @param off specifies absolute byte index of h's file for mapping,
|
||||
* it does not need to be 64kb aligned.
|
||||
* @return virtual base address of new mapping, or MAP_FAILED w/ errno
|
||||
*/
|
||||
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");
|
||||
STRACE("MAP_ANONYMOUS zipos mismatch");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (VERY_UNLIKELY(!(!!(prot & PROT_WRITE) ^ !!(flags & MAP_SHARED)))) {
|
||||
STRACE("PROT_WRITE and MAP_SHARED on zipos");
|
||||
// MAP_SHARED for non-writeable pages could be implemented, but would require
|
||||
// keeping track of zipos pages to prevent mprotect(addr,len,PROT_WRITE)
|
||||
if (VERY_UNLIKELY(!!(flags & MAP_SHARED))) {
|
||||
STRACE("MAP_SHARED on zipos");
|
||||
return VIP(eacces());
|
||||
}
|
||||
|
||||
|
@ -46,13 +65,13 @@ void *__zipos_mmap(void *addr, size_t size, int prot, int flags, struct ZiposHan
|
|||
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)) {
|
||||
if ((beforeOffset == -1) || (__zipos_read(h, &(struct iovec){outAddr, size}, 1, off) == -1) ||
|
||||
(__zipos_lseek(h, beforeOffset, SEEK_SET) == -1) ||
|
||||
((prot != tempProt) && (mprotect(outAddr, size, prot) == -1))) {
|
||||
const int e = errno;
|
||||
munmap(outAddr, size);
|
||||
errno = e;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
__zipos_lseek(h, beforeOffset, SEEK_SET);
|
||||
if(prot != tempProt) {
|
||||
mprotect(outAddr, size, prot);
|
||||
}
|
||||
return outAddr;
|
||||
}
|
||||
|
|
|
@ -221,17 +221,81 @@ TEST(isheap, mallocOffset) {
|
|||
ASSERT_TRUE(_isheap(p + 100000));
|
||||
}
|
||||
|
||||
TEST(mmap, ziposMapFiles) {
|
||||
static const char *ziposLifePath = "/zip/life.elf";
|
||||
TEST(mmap, ziposCannotBeAnonymous) {
|
||||
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);
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_SYS(EINVAL, MAP_FAILED, (p = mmap(NULL, 0x00010000, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0)));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
TEST(mmap, ziposCannotBeShared) {
|
||||
int fd;
|
||||
void *p;
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_SYS(EACCES, MAP_FAILED, (p = mmap(NULL, 0x00010000, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// zipos NON-SHARED READ-ONLY FILE MEMORY
|
||||
|
||||
TEST(mmap, ziposCow) {
|
||||
int fd;
|
||||
void *p;
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_NE(MAP_FAILED, (p = mmap(NULL, 0x00010000, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
EXPECT_STREQN("ELF", ((const char *)p)+1, 3);
|
||||
EXPECT_NE(-1, munmap(p, 0x00010000));
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// zipos NON-SHARED READ-ONLY FILE MEMORY BETWEEN PROCESSES
|
||||
|
||||
TEST(mmap, ziposCowFileMapReadonlyFork) {
|
||||
int fd, ws;
|
||||
void *p;
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_NE(MAP_FAILED, (p = mmap(NULL, 4, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
EXPECT_STREQN("ELF", ((const char *)p)+1, 3);
|
||||
ASSERT_NE(-1, (ws = xspawn(0)));
|
||||
if (ws == -2) {
|
||||
ASSERT_STREQN("ELF", ((const char *)p)+1, 3);
|
||||
_exit(0);
|
||||
}
|
||||
EXPECT_EQ(0, ws);
|
||||
EXPECT_STREQN("ELF", ((const char *)p)+1, 3);
|
||||
EXPECT_NE(-1, munmap(p, 6));
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// zipos NON-SHARED READ/WRITE FILE MEMORY BETWEEN PROCESSES
|
||||
|
||||
TEST(mmap, ziposCowFileMapFork) {
|
||||
int fd, ws;
|
||||
void *p;
|
||||
char lol[4];
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_NE(MAP_FAILED, (p = mmap(NULL, 6, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)));
|
||||
memcpy(p, "parnt", 6);
|
||||
ASSERT_NE(-1, (ws = xspawn(0)));
|
||||
if (ws == -2) {
|
||||
ASSERT_STREQN("parnt", p, 5);
|
||||
strcpy(p, "child");
|
||||
ASSERT_STREQN("child", p, 5);
|
||||
_exit(0);
|
||||
}
|
||||
EXPECT_EQ(0, ws);
|
||||
EXPECT_STREQN("parnt", p, 5); // child changing memory did not change parent
|
||||
EXPECT_EQ(4, pread(fd, lol, 4, 0));
|
||||
EXPECT_STREQN("ELF", &lol[1], 3); // changing memory did not change file
|
||||
EXPECT_NE(-1, munmap(p, 6));
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NON-SHARED READ-ONLY FILE MEMORY
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue