Improve signals and memory protection

- Document sigaction()
- Simplify New Technology fork() code
- Testing and many bug fixes for mprotect()
- Distribute Intel Xed ILD in the amalgamation
- Turn Xed enums into defines to avoid DWARF bloat
- Improve polyfilling of SA_SIGINFO on BSDs and fix bugs
- setpgid(getpid(), getpid()) on Windows will ignore CTRL-C
- Work around issues relating to NT mappings being executable
- Permit automatic executable stack override via `ape_stack_pf`
This commit is contained in:
Justine Tunney 2022-04-12 22:11:00 -07:00
parent c95c9d9508
commit f684e348d4
76 changed files with 1844 additions and 1121 deletions

View file

@ -14,11 +14,10 @@ struct DirectMap {
};
struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int64_t, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t);
int sys_munmap_metal(void *, size_t);
uint32_t __prot2nt(int, int);
struct ProtectNt __nt2prot(int);
uint32_t __prot2nt(int, bool);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -106,7 +106,6 @@ textwindows void WinMainForked(void) {
struct DirectMap dm;
uint64_t size, upsize;
int64_t reader, writer;
uint32_t flags1, flags2;
struct MemoryInterval *maps;
char16_t fvar[21 + 1 + 21 + 1];
int64_t oncrash, savetsc, savebir;
@ -163,24 +162,21 @@ textwindows void WinMainForked(void) {
size = maps[i].size;
if (maps[i].flags & MAP_PRIVATE) {
upsize = ROUNDUP(size, FRAMESIZE);
if (maps[i].prot & PROT_EXEC) {
flags1 = kNtPageExecuteReadwrite;
flags2 = kNtFileMapWrite | kNtFileMapExecute;
} else {
flags1 = kNtPageReadwrite;
flags2 = kNtFileMapWrite;
}
// we don't need to close the map handle because sys_mmap_nt
// doesn't mark it inheritable across fork() for MAP_PRIVATE
if (!(maps[i].h =
CreateFileMapping(-1, 0, flags1, upsize >> 32, upsize, 0)) ||
!MapViewOfFileEx(maps[i].h, flags2, 0, 0, upsize, addr) ||
if (!(maps[i].h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite,
upsize >> 32, upsize, 0)) ||
!MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
upsize, addr) ||
!ReadAll(reader, addr, size)) {
ExitProcess(44);
}
} else {
// we can however safely inherit MAP_SHARED with zero copy
if (!MapViewOfFileEx(maps[i].h, __nt2prot(maps[i].prot).flags2,
if (!MapViewOfFileEx(maps[i].h,
maps[i].readonlyfile
? kNtFileMapRead | kNtFileMapExecute
: kNtFileMapWrite | kNtFileMapExecute,
maps[i].offset >> 32, maps[i].offset, size, addr)) {
ExitProcess(45);
}
@ -203,11 +199,8 @@ textwindows void WinMainForked(void) {
_mmi.p = maps;
_mmi.n = specialz / sizeof(_mmi.p[0]);
for (i = 0; i < mapcount; ++i) {
if ((maps[i].flags & MAP_PRIVATE) && (~maps[i].prot & PROT_WRITE)) {
VirtualProtect((void *)((uint64_t)maps[i].x << 16),
ROUNDUP(maps[i].size, FRAMESIZE),
__nt2prot(maps[i].prot).flags1, &oldprot);
}
VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot);
}
// we're all done reading!
@ -263,8 +256,7 @@ textwindows int sys_fork_nt(void) {
}
#endif
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar,
&kNtIsInheritable, NULL, true,
0 /* kNtCreateNewProcessGroup */, NULL, &startinfo,
&kNtIsInheritable, NULL, true, 0, NULL, &startinfo,
&procinfo) != -1) {
CloseHandle(reader);
CloseHandle(procinfo.hThread);

View file

@ -31,7 +31,7 @@ _jmpstack:
mov %rcx,%rsi
mov %r8,%rdx
mov %r9,%rcx
xor %rbp,%rbp
xor %ebp,%ebp
call *%rax
ud2
.unreachable
.endfn _jmpstack,globl,hidden

View file

@ -171,7 +171,8 @@ noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
}
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags, long offset, long size) {
int prot, int flags, bool readonlyfile,
bool iscow, long offset, long size) {
/* asan runtime depends on this function */
unsigned i;
assert(y >= x);
@ -197,6 +198,8 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
mm->p[i].flags = flags;
mm->p[i].offset = offset;
mm->p[i].size = size;
mm->p[i].iscow = iscow;
mm->p[i].readonlyfile = readonlyfile;
}
return 0;
}

View file

@ -38,6 +38,8 @@ struct MemoryInterval {
int flags;
long offset;
long size;
bool iscow;
bool readonlyfile;
};
struct MemoryIntervals {
@ -50,12 +52,11 @@ extern hidden struct MemoryIntervals _mmi;
const char *DescribeFrame(int);
void PrintSystemMappings(int) hidden;
char *DescribeProt(int, char[hasatleast 4]);
char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int,
long, long) hidden;
bool, bool, long, long) hidden;
int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
void (*)(struct MemoryIntervals *, int, int)) hidden;
void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;

View file

@ -25,16 +25,19 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/rand/rand.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
@ -45,9 +48,14 @@
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
forceinline wontreturn void Die(void) {
if (weaken(__die)) weaken(__die)();
abort();
static wontreturn void OnUnrecoverableMmapError(const char *s) {
if (IsTiny()) {
unreachable;
} else {
STRACE("%s %m", s);
__restorewintty();
_Exit(199);
}
}
noasan static bool IsMapped(char *p, size_t n) {
@ -93,12 +101,9 @@ noasan static bool Automap(int n, int *res) {
if (*res + n <= FRAME(kAutomapStart + (kAutomapStart - 1))) {
return true;
} else {
STRACE("mmap(%.12p, %p) ENOMEM (automap interval exhausted)", ADDR(*res),
ADDR(n + 1));
return false;
}
} else {
STRACE("mmap(%.12p, %p) ENOMEM (automap failed)", ADDR(*res), ADDR(n + 1));
return false;
}
}
@ -109,31 +114,23 @@ static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
dm = sys_mmap(addr, size, prot, f, fd, off);
if (UNLIKELY(dm.addr == MAP_FAILED)) {
if (IsWindows() && (flags & MAP_FIXED)) {
STRACE("mmap(%.12p, %'ld) → %m (%s)", addr, size,
"can't recover from MAP_FIXED errors on Windows");
assert(!"MapMemory() failed");
Die();
OnUnrecoverableMmapError(
"can't recover from MAP_FIXED errors on Windows");
}
return MAP_FAILED;
}
if (UNLIKELY(dm.addr != addr)) {
STRACE("KERNEL DIDN'T RESPECT MAP_FIXED");
assert(!"MapMemory() failed");
Die();
OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
}
if (!IsWindows() && (flags & MAP_FIXED)) {
if (UntrackMemoryIntervals(addr, size)) {
STRACE("FIXED UNTRACK FAILED %m");
assert(!"MapMemory() failed");
Die();
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
}
}
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags, off,
size)) {
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags,
false, false, off, size)) {
if (sys_munmap(addr, n) == -1) {
STRACE("TRACK MUNMAP FAILED %m");
assert(!"MapMemory() failed");
Die();
OnUnrecoverableMmapError("TRACK MUNMAP FAILED");
}
return MAP_FAILED;
}
@ -155,21 +152,19 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
int f, int x, size_t n) {
int64_t oi, sz;
struct DirectMap dm;
bool iscow, readonlyfile;
size_t i, m = (n - 1) * FRAMESIZE;
assert(m < size && m + FRAMESIZE >= size);
oi = fd == -1 ? 0 : off + m;
sz = size - m;
dm = sys_mmap(addr + m, sz, prot, f, fd, oi);
if (dm.addr == MAP_FAILED) {
STRACE("MapMemories(%.12p+%lx/%lx) %m", addr, m, size);
return MAP_FAILED;
}
if (dm.addr == MAP_FAILED) return MAP_FAILED;
iscow = (flags & MAP_PRIVATE) && fd != -1;
readonlyfile = (flags & MAP_SHARED) && fd != -1 &&
(g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY;
if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot,
flags, oi, sz) == -1) {
STRACE("MapMemories(%.12p+%lx/%lx) unrecoverable failure #1 %m", addr, m,
size);
assert(!"MapMemories() failed");
Die();
flags, readonlyfile, iscow, oi, sz) == -1) {
OnUnrecoverableMmapError("MapMemories unrecoverable #1");
}
for (i = 0; i < m; i += FRAMESIZE) {
oi = fd == -1 ? 0 : off + i;
@ -177,11 +172,9 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
dm = sys_mmap(addr + i, sz, prot, f, fd, oi);
if (dm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE,
dm.maphandle, prot, flags, oi, sz) == -1) {
STRACE("MapMemories(%p+%x/%x) unrecoverable failure #2 %m", addr, i,
size);
assert(!"MapMemories() failed");
Die();
dm.maphandle, prot, flags, readonlyfile, iscow, oi,
sz) == -1) {
OnUnrecoverableMmapError("MapMemories unrecoverable #2");
}
}
if (weaken(__asan_map_shadow) && !OverlapsShadowSpace(addr, size)) {
@ -221,94 +214,87 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
*/
noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) {
void *res;
char *p = addr;
struct DirectMap dm;
int a, b, i, f, m, n, x;
char mode[8], *p = addr;
if (UNLIKELY(!size)) {
STRACE("mmap(%.12p, %'zu) EINVAL (size=0)", p, size);
return VIP(einval());
}
if (UNLIKELY(!IsLegalSize(size))) {
STRACE("mmap(%.12p, %'zu) EINVAL (size isn't 48-bit)", p, size);
return VIP(einval());
}
if (UNLIKELY(!IsLegalPointer(p))) {
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, size);
return VIP(einval());
}
if (UNLIKELY(!ALIGNED(p))) {
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, size);
return VIP(einval());
}
if (UNLIKELY(fd < -1)) {
if (!IsTiny() && UNLIKELY(!size)) {
STRACE("size=0");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(!IsLegalSize(size))) {
STRACE("size isn't 48-bit");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(!IsLegalPointer(p))) {
STRACE("p isn't 48-bit");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(!ALIGNED(p))) {
STRACE("p isn't 64kb aligned");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(fd < -1)) {
STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd);
return VIP(ebadf());
}
if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
STRACE("mmap(%.12p, %'zu, %s, %d, %'ld) EINVAL (fd anonymous mismatch)", p,
size, DescribeMapping(prot, flags, mode), fd, off);
return VIP(einval());
}
if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
STRACE("mmap(%.12p, %'zu) EINVAL (MAP_SHARED ^ MAP_PRIVATE)", p, size);
return VIP(einval());
}
if (UNLIKELY(off < 0)) {
STRACE("mmap(%.12p, %'zu, off=%'ld) EINVAL (neg off)", p, size, off);
return VIP(einval());
}
if (UNLIKELY(INT64_MAX - size < off)) {
STRACE("mmap(%.12p, %'zu, off=%'ld) EINVAL (too large)", p, size, off);
return VIP(einval());
}
if (UNLIKELY(!ALIGNED(off))) {
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, size);
return VIP(einval());
}
if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
res = VIP(ebadf());
} else if (!IsTiny() && UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
STRACE("fd anonymous mismatch");
res = VIP(einval());
} else if (!IsTiny() &&
UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
STRACE("MAP_SHARED ^ MAP_PRIVATE");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(off < 0)) {
STRACE("neg off");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(INT64_MAX - size < off)) {
STRACE("too large");
res = VIP(einval());
} else if (!IsTiny() && UNLIKELY(!ALIGNED(off))) {
STRACE("p isn't 64kb aligned");
res = VIP(einval());
} else if (!IsTiny() && (flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
#ifdef SYSDEBUG
if (OverlapsImageSpace(p, size)) {
STRACE("mmap(%.12p, %'zu) EFAULT (overlaps image)", p, size);
STRACE("overlaps image");
} else {
STRACE("mmap(%.12p, %'zu) EFAULT (overlaps existing)", p, size);
STRACE("overlaps existing");
}
return VIP(efault());
}
if (__isfdkind(fd, kFdZip)) {
STRACE("mmap(%.12p, %'zu) EINVAL (fd is zipos handle)", p, size);
return VIP(einval());
}
STRACE("mmap(%.12p, %'zu, %s, %d, %'ld)% m", p, size,
DescribeMapping(prot, flags, mode), fd, off);
if (fd == -1) {
size = ROUNDUP(size, FRAMESIZE);
if (IsWindows()) {
prot |= PROT_WRITE; /* kludge */
}
}
n = FRAME(size) + !!(size & (FRAMESIZE - 1));
f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
if (flags & MAP_FIXED) {
x = FRAME(p);
if (IsWindows()) {
if (UntrackMemoryIntervals(p, size)) {
STRACE("FIXED UNTRACK FAILED %m");
assert(!"mmap() failed");
Die();
#endif
res = VIP(efault());
} else if (!IsTiny() && __isfdkind(fd, kFdZip)) {
STRACE("fd is zipos handle");
res = VIP(einval());
} else {
if (fd == -1) {
size = ROUNDUP(size, FRAMESIZE);
if (IsWindows()) {
prot |= PROT_WRITE; /* kludge */
}
}
} else if (!NeedAutomap(p, size)) {
x = FRAME(p);
} else if (!Automap(n, &x)) {
return VIP(enomem());
}
p = (char *)ADDR(x);
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
}
if (!IsWindows()) {
return MapMemory(p, size, prot, flags, fd, off, f, x, n);
} else {
return MapMemories(p, size, prot, flags, fd, off, f, x, n);
n = FRAME(size) + !!(size & (FRAMESIZE - 1));
f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
if (flags & MAP_FIXED) {
x = FRAME(p);
if (IsWindows()) {
if (UntrackMemoryIntervals(p, size)) {
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
}
}
} else if (!NeedAutomap(p, size)) {
x = FRAME(p);
} else if (!Automap(n, &x)) {
STRACE("AUTOMAP OUT OF MEMORY D:");
return VIP(enomem());
}
p = (char *)ADDR(x);
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) res = MAP_FAILED;
}
if (!IsWindows()) {
res = MapMemory(p, size, prot, flags, fd, off, f, x, n);
} else {
res = MapMemories(p, size, prot, flags, fd, off, f, x, n);
}
}
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size,
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res);
return res;
}

View file

@ -0,0 +1,107 @@
/*-*- 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 2020 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/bits/asmflag.h"
#include "libc/bits/likely.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
/**
* Modifies restrictions on virtual memory address range.
*
* @param addr needs to be 4kb aligned
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN,GROWSUP}
* @return 0 on success, or -1 w/ errno
* @see mmap()
*/
noasan noubsan privileged int mprotect(void *addr, size_t size, int prot) {
bool cf;
int64_t rc;
unsigned i;
uint32_t op;
char *a, *b, *x, *y, *p;
if (SupportsWindows() && (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC |
PROT_GROWSDOWN | PROT_GROWSUP))) {
rc = einval(); // unix checks prot before checking size
} else if (!size) {
return 0; // make new technology consistent with unix
} else if (UNLIKELY((intptr_t)addr & 4095)) {
rc = einval();
} else if (!IsWindows()) {
asm volatile(CFLAG_ASM("clc\n\tsyscall")
: CFLAG_CONSTRAINT(cf), "=a"(rc)
: "1"(__NR_mprotect), "D"(addr), "S"(size), "d"(prot)
: "rcx", "r11", "memory", "cc");
if (cf) {
errno = rc;
rc = -1;
} else if (rc > -4096ul) {
errno = -rc;
rc = -1;
}
} else {
rc = 0;
p = addr;
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) {
// memory isn't in memtrack
// let's just trust the user then
// it's probably part of the executable
if (!VirtualProtect(addr, size, __prot2nt(prot, false), &op)) {
rc = -1;
}
} else {
// memory is in memtrack, so use memtrack, to do dimensioning
// we unfortunately must do something similar to this for cow
for (; i < _mmi.i; ++i) {
x = ADDR(_mmi.p[i].x);
y = x + _mmi.p[i].size;
if ((x <= p && p < y) || (x < p + size && p + size <= y) ||
(p < x && y < p + size)) {
a = MIN(MAX(p, x), y);
b = MAX(MIN(p + size, y), x);
if (!VirtualProtect(a, b - a, __prot2nt(prot, _mmi.p[i].iscow),
&op)) {
rc = -1;
break;
}
} else {
break;
}
}
}
}
STRACE("mprotect(%p, %'zu, %s) → %d% m", addr, size, DescribeProtFlags(prot),
rc);
return rc;
}

View file

@ -24,6 +24,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h"
@ -67,48 +68,54 @@ static bool MustMoveMap(intptr_t y, size_t j) {
* @param q is new address
*/
void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
enosys();
return MAP_FAILED;
void *q;
va_list va;
void *res, *q;
if (f & MREMAP_FIXED) {
va_start(va, f);
q = va_arg(va, void *);
va_end(va);
} else {
q = 0;
}
enosys();
res = MAP_FAILED;
STRACE("mremap(%p, %'zu, %'zu, %s, %p) → %p% m", p, n, m,
DescribeRemapFlags(f), q, res);
return res;
#if 0
// TODO(jart): perhaps some day?
// probably not a big perf gain at this point :|
size_t i, j, k;
struct DirectMap dm;
int a, b, prot, flags;
assert(!__vforked);
if (UNLIKELY(!m)) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (m=0)", p, n, m, f);
STRACE("m=0");
return VIP(einval());
}
if (UNLIKELY(!n)) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n=0)", p, n, m, f);
} else if (UNLIKELY(!n)) {
STRACE("n=0");
return VIP(eopnotsupp());
}
if (UNLIKELY(!ALIGNED(n))) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n align)", p, n, m, f);
} else if (UNLIKELY(!ALIGNED(n))) {
STRACE("n align");
return VIP(eopnotsupp());
}
if (UNLIKELY(!ALIGNED(m))) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n align)", p, n, m, f);
} else if (UNLIKELY(!ALIGNED(m))) {
STRACE("n align");
return VIP(eopnotsupp());
}
if (UNLIKELY(!ALIGNED(p))) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (64kb align)", p, n, m, f);
} else if (UNLIKELY(!ALIGNED(p))) {
STRACE("64kb align");
return VIP(einval());
}
if (UNLIKELY(!IsLegalSize(n))) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (n too big)", p, n, m, f);
} else if (UNLIKELY(!IsLegalSize(n))) {
STRACE("n too big");
return VIP(enomem());
}
if (UNLIKELY(!IsLegalSize(m))) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (m too big)", p, n, m, f);
} else if (UNLIKELY(!IsLegalSize(m))) {
STRACE("m too big");
return VIP(enomem());
}
if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (bad flag)", p, n, m, f);
} else if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) {
STRACE("bad flag");
return VIP(einval());
}
if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) {
STRACE("munmap(%p, %'zu) EFAULT (interval not tracked)", p, n);
} else if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) {
STRACE("interval not tracked");
return VIP(efault());
}
STRACE("mremap(%p, %'zu, %'zu, %#b)", p, n, m, f);
@ -119,9 +126,6 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
return VIP(eopnotsupp()); /* TODO */
}
if (f & MREMAP_FIXED) {
va_start(va, f);
q = va_arg(va, void *);
va_end(va);
if (!ALIGNED(q)) return VIP(einval());
return VIP(eopnotsupp()); /* TODO */
}
@ -145,7 +149,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
if (dm.addr == MAP_FAILED) return 0;
if (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16,
((uintptr_t)p + m - FRAMESIZE) >> 16, dm.maphandle,
prot, flags, 0, m - n) != -1) {
prot, flags, false, false, 0, m - n) != -1) {
if (weaken(__asan_map_shadow)) {
weaken(__asan_map_shadow)((uintptr_t)dm.addr, m - n);
}
@ -178,7 +182,8 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
if (q == MAP_FAILED) return 0;
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 &&
TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, 0, m) != -1) {
TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, false, false, 0, m) !=
-1) {
if (weaken(__asan_poison)) {
if (!OverlapsShadowSpace(p, n)) {
weaken(__asan_poison)((intptr_t)p, n, kAsanUnmapped);
@ -198,4 +203,5 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
} else {
return q;
}
#endif
}

View file

@ -29,6 +29,29 @@
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int i, rc = 0;
char *a, *b, *x, *y;
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
x = ADDR(_mmi.p[i].x);
y = x + _mmi.p[i].size;
if ((x <= addr && addr < y) || (x < addr + size && addr + size <= y) ||
(addr < x && y < addr + size)) {
a = MIN(MAX(addr, x), y);
b = MAX(MIN(addr + size, y), x);
if (!FlushViewOfFile(a, b - a)) {
rc = -1;
break;
}
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
} else {
break;
}
}
return rc;
}
#if 0
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
char *a, *b;
int rc, x, y, l, r, i;
@ -51,3 +74,4 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
}
return rc;
}
#endif

View file

@ -52,7 +52,9 @@
#if defined(__GNUC__) && defined(__ELF__) && !defined(__STRICT_ANSI__)
COSMOPOLITAN_C_START_
extern char ape_stack_prot[] __attribute__((__weak__));
extern char ape_stack_memsz[] __attribute__((__weak__));
extern char ape_stack_align[] __attribute__((__weak__));
#define GetStackSize() ((uintptr_t)ape_stack_memsz)

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/elf/pf2prot.internal.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
@ -42,6 +43,7 @@
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/teb.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
@ -53,8 +55,10 @@
#if IsTiny()
extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW __msabi;
extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx __msabi;
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
#define CreateFileMapping __imp_CreateFileMappingW
#define MapViewOfFileEx __imp_MapViewOfFileEx
#define VirtualProtect __imp_VirtualProtect
#endif
#define AT_EXECFN 31L
@ -114,12 +118,11 @@ forceinline void MakeLongDoubleLongAgain(void) {
static noasan textwindows wontreturn noinstrument void WinMainNew(
const char16_t *cmdline) {
bool32 rc;
int64_t h;
int version;
int i, count;
int64_t hand;
int64_t h, hand;
uint32_t oldprot;
struct WinArgs *wa;
const char16_t *env16;
int i, prot, count, version;
intptr_t stackaddr, allocaddr;
size_t allocsize, argsize, stacksize;
version = NtGetPeb()->OSMajorVersion;
@ -152,9 +155,13 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
allocsize >> 32, allocsize, NULL)),
kNtFileMapWrite | kNtFileMapExecute, 0, 0, allocsize, (void *)allocaddr);
prot = (intptr_t)ape_stack_prot;
if (~prot & PROT_EXEC) {
VirtualProtect((void *)allocaddr, allocsize, kNtPageReadwrite, &oldprot);
}
_mmi.p[0].x = allocaddr >> 16;
_mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1);
_mmi.p[0].prot = PROT_READ | PROT_WRITE | PROT_EXEC;
_mmi.p[0].prot = prot;
_mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS;
_mmi.p[0].size = allocsize;
_mmi.i = 1;
@ -175,8 +182,8 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
wa->auxv[0][0] = pushpop(AT_EXECFN);
wa->auxv[0][1] = (intptr_t)wa->argv[0];
STRACE("WinMainNew() switching stacks");
_jmpstack((char *)stackaddr + stacksize, cosmo, count, wa->argv, wa->envp,
wa->auxv);
_jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo,
count, wa->argv, wa->envp, wa->auxv);
}
/**