mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-26 04:20:30 +00:00
Add torture test for zipos file descriptors
This change hardens the code for opening /zip/ files using the system call interface. Thread safety and signal safety has been improved for file descriptors in general. We now document fixed addresses that are needed for low level allocations.
This commit is contained in:
parent
579080cd4c
commit
e466dd0553
44 changed files with 2981 additions and 307 deletions
|
@ -22,51 +22,65 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/directmap.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/prot.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
// XXX: until we can add read locks to all the code that uses g_fds.p
|
||||
// (right now we only have write locks) we need to keep old copies
|
||||
// of g_fds.p around after it's been extended, so that threads
|
||||
// which are using an fd they de facto own can continue reading
|
||||
static void FreeOldFdsArray(void *p) {
|
||||
weaken(free)(p);
|
||||
}
|
||||
static volatile size_t mapsize;
|
||||
|
||||
/**
|
||||
* Grows file descriptor array memory if needed.
|
||||
*
|
||||
* @see libc/runtime/memtrack64.txt
|
||||
* @see libc/runtime/memtrack32.txt
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __ensurefds_unlocked(int fd) {
|
||||
size_t n1, n2;
|
||||
struct Fd *p1, *p2;
|
||||
uint64_t addr;
|
||||
int prot, flags;
|
||||
size_t size, chunk;
|
||||
struct DirectMap dm;
|
||||
if (fd < g_fds.n) return fd;
|
||||
STRACE("__ensurefds(%d) extending", fd);
|
||||
if (!weaken(malloc)) return emfile();
|
||||
p1 = g_fds.p;
|
||||
n1 = g_fds.n;
|
||||
if (p1 == g_fds.__init_p) {
|
||||
if (!(p2 = weaken(malloc)(sizeof(g_fds.__init_p)))) return -1;
|
||||
memcpy(p2, p1, sizeof(g_fds.__init_p));
|
||||
g_fds.p = p1 = p2;
|
||||
size = mapsize;
|
||||
chunk = FRAMESIZE;
|
||||
if (IsAsan()) chunk *= 8;
|
||||
addr = kMemtrackFdsStart + size;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||
dm = sys_mmap((char *)addr, chunk, prot, flags, -1, 0);
|
||||
TrackMemoryInterval(&_mmi, addr >> 16, (addr + chunk - 1) >> 16, dm.maphandle,
|
||||
prot, flags, false, false, 0, chunk);
|
||||
if (IsAsan()) {
|
||||
addr = (addr >> 3) + 0x7fff8000;
|
||||
dm = sys_mmap((char *)addr, FRAMESIZE, prot, flags, -1, 0);
|
||||
TrackMemoryInterval(&_mmi, addr >> 16, addr >> 16, dm.maphandle, prot,
|
||||
flags, false, false, 0, FRAMESIZE);
|
||||
}
|
||||
n2 = n1;
|
||||
while (n2 <= fd) n2 *= 2;
|
||||
if (!(p2 = weaken(malloc)(n2 * sizeof(*p1)))) return -1;
|
||||
__cxa_atexit(FreeOldFdsArray, p1, 0);
|
||||
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
||||
g_fds.p = p2;
|
||||
g_fds.n = n2;
|
||||
if (!size) {
|
||||
g_fds.p = memcpy((char *)kMemtrackFdsStart, g_fds.__init_p,
|
||||
sizeof(g_fds.__init_p));
|
||||
}
|
||||
g_fds.n = (size + chunk) / sizeof(*g_fds.p);
|
||||
mapsize = size + chunk;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows file descriptor array memory if needed.
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __ensurefds(int fd) {
|
||||
__fds_lock();
|
||||
|
@ -77,22 +91,29 @@ int __ensurefds(int fd) {
|
|||
|
||||
/**
|
||||
* Finds open file descriptor slot.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __reservefd_unlocked(int start) {
|
||||
int fd;
|
||||
for (fd = MAX(start, g_fds.f); fd < g_fds.n; ++fd) {
|
||||
if (!g_fds.p[fd].kind) {
|
||||
break;
|
||||
for (;;) {
|
||||
for (fd = MAX(start, g_fds.f); fd < g_fds.n; ++fd) {
|
||||
if (!g_fds.p[fd].kind) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fd = __ensurefds_unlocked(fd);
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||
_cmpxchg(&g_fds.f, fd, fd + 1);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
fd = __ensurefds_unlocked(fd);
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
g_fds.p[fd].kind = kFdReserved;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds open file descriptor slot.
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __reservefd(int start) {
|
||||
int fd;
|
||||
|
@ -101,37 +122,3 @@ int __reservefd(int start) {
|
|||
__fds_unlock();
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes non-stdio file descriptors to free dynamic memory.
|
||||
*/
|
||||
static void FreeFds(void) {
|
||||
int i, keep = 3;
|
||||
STRACE("FreeFds()");
|
||||
__fds_lock();
|
||||
for (i = keep; i < g_fds.n; ++i) {
|
||||
if (g_fds.p[i].kind) {
|
||||
__fds_unlock();
|
||||
close(i);
|
||||
__fds_lock();
|
||||
}
|
||||
}
|
||||
if (g_fds.p != g_fds.__init_p) {
|
||||
bzero(g_fds.__init_p, sizeof(g_fds.__init_p));
|
||||
memcpy(g_fds.__init_p, g_fds.p, sizeof(*g_fds.p) * keep);
|
||||
if (weaken(free)) {
|
||||
weaken(free)(g_fds.p);
|
||||
}
|
||||
g_fds.p = g_fds.__init_p;
|
||||
g_fds.n = ARRAYLEN(g_fds.__init_p);
|
||||
}
|
||||
__fds_unlock();
|
||||
}
|
||||
|
||||
static textstartup void FreeFdsInit(void) {
|
||||
atexit(FreeFds);
|
||||
}
|
||||
|
||||
const void *const FreeFdsCtor[] initarray = {
|
||||
FreeFdsInit,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue