Fix pthread stacks with larger guard size

This commit is contained in:
Justine Tunney 2022-09-09 06:19:05 -07:00
parent 1db76c288e
commit e97f1a99cf
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
10 changed files with 68 additions and 42 deletions

View file

@ -30,7 +30,6 @@ const char *(DescribeMapFlags)(char buf[64], int x) {
{MAP_SHARED, "SHARED"}, //
{MAP_FIXED, "FIXED"}, //
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
{MAP_GROWSDOWN, "GROWSDOWN"}, //
{MAP_CONCEAL, "CONCEAL"}, //
{MAP_HUGETLB, "HUGETLB"}, //
{MAP_LOCKED, "LOCKED"}, //

View file

@ -49,7 +49,6 @@ const char *(DescribeMapping)(char p[8], int prot, int flags) {
DescribeProt(p, prot);
p[3] = DescribeMapType(flags);
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
p[5] = (flags & MAP_GROWSDOWN) ? 'G' : '-';
p[6] = (flags & MAP_FIXED) ? 'F' : '-';
p[7] = 0;
return p;

View file

@ -85,7 +85,7 @@ typedef struct pthread_attr_s {
char detachstate;
size_t stacksize;
size_t guardsize;
void *stackaddr;
char *stackaddr;
int scope;
int schedpolicy;
int inheritsched;

View file

@ -30,8 +30,5 @@ int pthread_attr_init(pthread_attr_t *attr) {
.stacksize = GetStackSize(),
.guardsize = PAGESIZE,
};
if (attr->stacksize >= 1048576) {
attr->guardsize = FRAMESIZE;
}
return 0;
}

View file

@ -595,9 +595,7 @@ int clone(void *func, void *stk, size_t stksz, int flags, void *arg, int *ptid,
((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15)))) {
rc = einval();
} else if (IsAsan() &&
((stksz > PAGESIZE &&
!__asan_is_valid((char *)stk + PAGESIZE, stksz - PAGESIZE)) ||
((flags & CLONE_SETTLS) && !__asan_is_valid(tls, 64)) ||
(((flags & CLONE_SETTLS) && !__asan_is_valid(tls, 64)) ||
((flags & CLONE_SETTLS) && !__asan_is_valid(tls, sizeof(long))) ||
((flags & CLONE_PARENT_SETTID) &&
!__asan_is_valid(ptid, sizeof(*ptid))) ||

View file

@ -13,7 +13,6 @@ extern const int MAP_EXECUTABLE;
extern const int MAP_FILE;
extern const int MAP_FIXED;
extern const int MAP_FIXED_NOREPLACE;
extern const int MAP_GROWSDOWN;
extern const int MAP_HASSEMAPHORE;
extern const int MAP_HUGETLB;
extern const int MAP_HUGE_MASK;
@ -44,7 +43,6 @@ COSMOPOLITAN_C_END_
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
#define MAP_FIXED_NOREPLACE SYMBOLIC(MAP_FIXED_NOREPLACE)
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
#define MAP_HASSEMAPHORE SYMBOLIC(MAP_HASSEMAPHORE)
#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB)
#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK)

View file

@ -96,8 +96,8 @@ static int FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
n = ROUNDDOWN(n, PAGESIZE);
e = errno;
if (__sys_mmap((void *)y, n, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON_OPENBSD | MAP_STACK_OPENBSD, -1, 0,
0) != MAP_FAILED) {
MAP_PRIVATE | MAP_FIXED | MAP_ANON_OPENBSD | MAP_STACK_OPENBSD,
-1, 0, 0) == (void *)y) {
attr->stackaddr = (void *)y;
attr->stacksize = n;
return 0;
@ -215,8 +215,28 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
_pthread_free(pt);
return EINVAL;
}
pt->attr.stackaddr = mmap(0, pt->attr.stacksize, PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0);
if (pt->attr.guardsize == PAGESIZE) {
// user is wisely using smaller stacks with default guard size
pt->attr.stackaddr = mmap(0, pt->attr.stacksize, PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0);
} else {
// user is tuning things, performance may suffer
pt->attr.stackaddr = mmap(0, pt->attr.stacksize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (pt->attr.stackaddr != MAP_FAILED) {
if (IsOpenbsd() &&
__sys_mmap(
pt->attr.stackaddr, pt->attr.stacksize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED | MAP_ANON_OPENBSD | MAP_STACK_OPENBSD,
-1, 0, 0) != pt->attr.stackaddr) {
notpossible;
}
if (pt->attr.guardsize && !IsWindows() &&
mprotect(pt->attr.stackaddr, pt->attr.guardsize, PROT_NONE)) {
notpossible;
}
}
}
if (pt->attr.stackaddr == MAP_FAILED) {
rc = errno;
_pthread_free(pt);
@ -227,27 +247,8 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
return EAGAIN;
}
}
// mmap(MAP_STACK) creates a 4096 guard by default
if (pt->attr.guardsize != PAGESIZE) {
if (pt->attr.guardsize) {
// user requested special guard size
rc = mprotect(pt->attr.stackaddr, pt->attr.guardsize, PROT_NONE);
} else {
// user explicitly disabled guard page
rc = mprotect(pt->attr.stackaddr, PAGESIZE, PROT_READ | PROT_WRITE);
}
if (rc) {
notpossible;
}
}
if (IsAsan()) {
if (pt->attr.guardsize) {
__asan_poison(pt->attr.stackaddr, pt->attr.guardsize,
kAsanStackOverflow);
}
__asan_poison((char *)pt->attr.stackaddr + pt->attr.stacksize -
16 /* openbsd:stackbound */,
16, kAsanStackOverflow);
if (IsAsan() && pt->attr.guardsize) {
__asan_poison(pt->attr.stackaddr, pt->attr.guardsize, kAsanStackOverflow);
}
}
@ -267,7 +268,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// launch PosixThread(pt) in new thread
if (clone(PosixThread, pt->attr.stackaddr,
pt->attr.stacksize - 16 /* openbsd:stackbound */,
pt->attr.stacksize - (IsOpenbsd() ? 16 : 0),
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID |
CLONE_CHILD_CLEARTID,