From: Matthew Dillon Date: Thu, 23 Apr 2009 20:05:24 +0000 (-0700) Subject: Fix libthread_xu's use of MAP_STACK. Guards were not being setup properly. X-Git-Tag: v2.3.1~69 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/2035b67992ac162a5968a22584ef29d2f53f93e2 Fix libthread_xu's use of MAP_STACK. Guards were not being setup properly. MAP_STACK mappings do not immediately extend down to their base, so calling mprotect() on the base is basically a NOP. Instead of calling mprotect() we call mmap() with MAP_FIXED to force the guard. Properly use MAP_FIXED when setting up the primary guard on the original user stack. The address specified in the mmap() is only a hint when MAP_FIXED is not used, and will not properly map the anonymous area. Also, new kernels do not allow non-MAP_STACK mappings to override MAP_STACK mappings and the user stack area is a MAP_STACK mapping, so use of MAP_FIXED is mandatory here. --- diff --git a/lib/libthread_xu/thread/thr_init.c b/lib/libthread_xu/thread/thr_init.c index 902ea0cf86..8911e59177 100644 --- a/lib/libthread_xu/thread/thr_init.c +++ b/lib/libthread_xu/thread/thr_init.c @@ -258,9 +258,10 @@ init_main_thread(struct pthread *thread) * red zone to protect the thread stack that is just beyond. */ if (mmap(_usrstack - _thr_stack_initial - - _thr_guard_default, _thr_guard_default, 0, MAP_ANON, - -1, 0) == MAP_FAILED) + _thr_guard_default, _thr_guard_default, + 0, MAP_ANON | MAP_FIXED, -1, 0) == MAP_FAILED) { PANIC("Cannot allocate red zone for initial thread"); + } /* * Mark the stack as an application supplied stack so that it diff --git a/lib/libthread_xu/thread/thr_stack.c b/lib/libthread_xu/thread/thr_stack.c index 68af995347..cae1267aa4 100644 --- a/lib/libthread_xu/thread/thr_stack.c +++ b/lib/libthread_xu/thread/thr_stack.c @@ -190,9 +190,10 @@ _thr_stack_alloc(struct pthread_attr *attr) } else { /* Allocate a stack from usrstack. */ - if (last_stack == NULL) + if (last_stack == NULL) { last_stack = _usrstack - _thr_stack_initial - - _thr_guard_default; + _thr_guard_default; + } /* Allocate a new stack. */ stackaddr = last_stack - stacksize - guardsize; @@ -209,19 +210,28 @@ _thr_stack_alloc(struct pthread_attr *attr) /* Release the lock before mmap'ing it. */ THREAD_LIST_UNLOCK(curthread); - /* Map the stack and guard page together, and split guard - page from allocated space: */ - if ((stackaddr = mmap(stackaddr, stacksize+guardsize, - PROT_READ | PROT_WRITE, MAP_STACK, - -1, 0)) != MAP_FAILED && - (guardsize == 0 || - mprotect(stackaddr, guardsize, PROT_NONE) == 0)) { - stackaddr += guardsize; - } else { - if (stackaddr != MAP_FAILED) + /* + * Map the stack and guard page together then split the + * guard page from allocated space. + * + * NOTE: MAP_STACK mappings are grow-down and the + * initial mapping does not actually extend to the guard + * area, so creating the guard requires doing a fixed + * anonymous mmap of the guard area. + */ + stackaddr = mmap(stackaddr, stacksize + guardsize, + PROT_READ | PROT_WRITE, MAP_STACK, -1, 0); + if (stackaddr != MAP_FAILED && guardsize) { + if (mmap(stackaddr, guardsize, 0, + MAP_ANON | MAP_FIXED, -1, 0) == MAP_FAILED) { munmap(stackaddr, stacksize + guardsize); - stackaddr = NULL; + stackaddr = MAP_FAILED; + } else { + stackaddr += guardsize; + } } + if (stackaddr == MAP_FAILED) + stackaddr = NULL; attr->stackaddr_attr = stackaddr; } if (attr->stackaddr_attr != NULL)