Author: kib
Date: Sun Jan  9 12:38:40 2011
New Revision: 217191
URL: http://svn.freebsd.org/changeset/base/217191

Log:
  Implement the __pthread_map_stacks_exec() for libthr.
  
  Stack creation code is changed to call _rtld_get_stack_prot() to get
  the stack protection right. There is a race where thread is created
  during dlopen() of dso that requires executable stacks. Then,
  _rtld_get_stack_prot() may return PROT_READ | PROT_WRITE, but thread
  is still not linked into the thread list. In this case, the callback
  misses the thread stack, and rechecks the required protection
  afterward.
  
  Reviewed by:  davidxu

Modified:
  head/lib/libthr/pthread.map
  head/lib/libthr/thread/thr_create.c
  head/lib/libthr/thread/thr_private.h
  head/lib/libthr/thread/thr_rtld.c
  head/lib/libthr/thread/thr_stack.c

Modified: head/lib/libthr/pthread.map
==============================================================================
--- head/lib/libthr/pthread.map Sun Jan  9 11:52:23 2011        (r217190)
+++ head/lib/libthr/pthread.map Sun Jan  9 12:38:40 2011        (r217191)
@@ -382,6 +382,8 @@ FBSDprivate_1.0 {
        _thread_size_key;
        _thread_state_running;
        _thread_state_zoombie;
+
+       __pthread_map_stacks_exec;
 };
 
 FBSD_1.1 {

Modified: head/lib/libthr/thread/thr_create.c
==============================================================================
--- head/lib/libthr/thread/thr_create.c Sun Jan  9 11:52:23 2011        
(r217190)
+++ head/lib/libthr/thread/thr_create.c Sun Jan  9 12:38:40 2011        
(r217191)
@@ -32,6 +32,7 @@
 #include <sys/rtprio.h>
 #include <sys/signalvar.h>
 #include <errno.h>
+#include <link.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stddef.h>
@@ -58,6 +59,7 @@ _pthread_create(pthread_t * thread, cons
        sigset_t set, oset;
        cpuset_t *cpusetp = NULL;
        int cpusetsize = 0;
+       int old_stack_prot;
 
        _thr_check_init();
 
@@ -96,6 +98,7 @@ _pthread_create(pthread_t * thread, cons
 
        new_thread->tid = TID_TERMINATED;
 
+       old_stack_prot = _rtld_get_stack_prot();
        if (create_stack(&new_thread->attr) != 0) {
                /* Insufficient memory to create a stack: */
                _thr_free(curthread, new_thread);
@@ -130,6 +133,14 @@ _pthread_create(pthread_t * thread, cons
        /* Add the new thread. */
        new_thread->refcount = 1;
        _thr_link(curthread, new_thread);
+
+       /*
+        * Handle the race between __pthread_map_stacks_exec and
+        * thread linkage.
+        */
+       if (old_stack_prot != _rtld_get_stack_prot())
+               _thr_stack_fix_protection(new_thread);
+
        /* Return thread pointer eariler so that new thread can use it. */
        (*thread) = new_thread;
        if (SHOULD_REPORT_EVENT(curthread, TD_CREATE) || cpusetp != NULL) {

Modified: head/lib/libthr/thread/thr_private.h
==============================================================================
--- head/lib/libthr/thread/thr_private.h        Sun Jan  9 11:52:23 2011        
(r217190)
+++ head/lib/libthr/thread/thr_private.h        Sun Jan  9 12:38:40 2011        
(r217191)
@@ -898,6 +898,7 @@ struct dl_phdr_info;
 void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
 void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden;
 void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden;
+void _thr_stack_fix_protection(struct pthread *thrd);
 
 __END_DECLS
 

Modified: head/lib/libthr/thread/thr_rtld.c
==============================================================================
--- head/lib/libthr/thread/thr_rtld.c   Sun Jan  9 11:52:23 2011        
(r217190)
+++ head/lib/libthr/thread/thr_rtld.c   Sun Jan  9 12:38:40 2011        
(r217191)
@@ -31,6 +31,8 @@
   * A lockless rwlock for rtld.
   */
 #include <sys/cdefs.h>
+#include <sys/mman.h>
+#include <link.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -194,6 +196,9 @@ _thr_rtld_init(void)
        /* force to resolve memcpy PLT */
        memcpy(&dummy, &dummy, sizeof(dummy));
 
+       mprotect(NULL, 0, 0);
+       _rtld_get_stack_prot();
+
        li.lock_create  = _thr_rtld_lock_create;
        li.lock_destroy = _thr_rtld_lock_destroy;
        li.rlock_acquire = _thr_rtld_rlock_acquire;

Modified: head/lib/libthr/thread/thr_stack.c
==============================================================================
--- head/lib/libthr/thread/thr_stack.c  Sun Jan  9 11:52:23 2011        
(r217190)
+++ head/lib/libthr/thread/thr_stack.c  Sun Jan  9 12:38:40 2011        
(r217191)
@@ -32,6 +32,7 @@
 #include <sys/queue.h>
 #include <stdlib.h>
 #include <pthread.h>
+#include <link.h>
 
 #include "thr_private.h"
 
@@ -128,6 +129,38 @@ round_up(size_t size)
        return size;
 }
 
+void
+_thr_stack_fix_protection(struct pthread *thrd)
+{
+
+       mprotect((char *)thrd->attr.stackaddr_attr +
+           round_up(thrd->attr.guardsize_attr),
+           round_up(thrd->attr.stacksize_attr),
+           _rtld_get_stack_prot());
+}
+
+void __pthread_map_stacks_exec(void);
+void
+__pthread_map_stacks_exec(void)
+{
+       struct pthread *curthread, *thrd;
+       struct stack *st;
+
+       curthread = _get_curthread();
+       THREAD_LIST_RDLOCK(curthread);
+       LIST_FOREACH(st, &mstackq, qe)
+               mprotect((char *)st->stackaddr + st->guardsize, st->stacksize,
+                   _rtld_get_stack_prot());
+       LIST_FOREACH(st, &dstackq, qe)
+               mprotect((char *)st->stackaddr + st->guardsize, st->stacksize,
+                   _rtld_get_stack_prot());
+       TAILQ_FOREACH(thrd, &_thread_gc_list, gcle)
+               _thr_stack_fix_protection(thrd);
+       TAILQ_FOREACH(thrd, &_thread_list, tle)
+               _thr_stack_fix_protection(thrd);
+       THREAD_LIST_UNLOCK(curthread);
+}
+
 int
 _thr_stack_alloc(struct pthread_attr *attr)
 {
@@ -210,7 +243,7 @@ _thr_stack_alloc(struct pthread_attr *at
                /* 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,
+                    _rtld_get_stack_prot(), MAP_STACK,
                     -1, 0)) != MAP_FAILED &&
                    (guardsize == 0 ||
                     mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to