svn commit: r217191 - in head/lib/libthr: . thread

Konstantin Belousov kib at FreeBSD.org
Sun Jan 9 12:38:41 UTC 2011


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)) {


More information about the svn-src-all mailing list