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