Module Name:    src
Committed By:   christos
Date:           Sat Dec 18 15:54:27 UTC 2010

Modified Files:
        src/lib/libpthread: pthread.c pthread_int.h

Log Message:
I've had this patch in my tree for a while and since it only improves
the situation, I decided to commit it. There is an inherent problem
with ASLR and the way the pthread library is using the thread stack.

Our pthread library chooses that stack for each thread strategically
so that it can locate the location of the pthread struct for each
thread by masking the stack pointer and looking just below the red
zone it creates. Unfortunately with ASLR you get many random values
for the initial stack, and there are situations where the masked
stack base ends up below the base of the stack. (this happens on
x86 when the stack base happens to be 0x???02000 for example and
your mask is stackmask is 0xffe00000). To fix this, we detect the
pathological cases (this happens only in the main thread), allocate
more stack, and mprotect it appropriately. Then we stash the main
base and the main struct, so that when we look for the pthread
struct in pthread__id, we can special case the main thread.

Another way to work around the problem is unlimiting stacksize,
but the proper way is to use TLS to find the thread structure and
not to play games with the thread stacks.


To generate a diff of this commit:
cvs rdiff -u -r1.117 -r1.118 src/lib/libpthread/pthread.c
cvs rdiff -u -r1.72 -r1.73 src/lib/libpthread/pthread_int.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libpthread/pthread.c
diff -u src/lib/libpthread/pthread.c:1.117 src/lib/libpthread/pthread.c:1.118
--- src/lib/libpthread/pthread.c:1.117	Sun Nov 14 17:25:23 2010
+++ src/lib/libpthread/pthread.c	Sat Dec 18 10:54:27 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pthread.c,v 1.117 2010/11/14 22:25:23 tron Exp $	*/
+/*	$NetBSD: pthread.c,v 1.118 2010/12/18 15:54:27 christos Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread.c,v 1.117 2010/11/14 22:25:23 tron Exp $");
+__RCSID("$NetBSD: pthread.c,v 1.118 2010/12/18 15:54:27 christos Exp $");
 
 #define	__EXPOSE_STACK	1
 
@@ -108,6 +108,8 @@
 size_t	pthread__stacksize = 1 << _STACKSIZE_LG;
 vaddr_t	pthread__stackmask = (1 << _STACKSIZE_LG) - 1;
 vaddr_t pthread__threadmask = (vaddr_t)~((1 << _STACKSIZE_LG) - 1);
+vaddr_t	pthread__mainbase = 0;
+vaddr_t	pthread__mainstruct = 0;
 #undef	_STACKSIZE_LG
 
 int _sys___sigprocmask14(int, const sigset_t *, sigset_t *);
@@ -1221,7 +1223,14 @@
 	pthread__threadmask = ~pthread__stackmask;
 
 	base = (void *)(pthread__sp() & pthread__threadmask);
+	if ((pthread__sp() - (uintptr_t)base) < 4 * pagesize) {
+		pthread__mainbase = (vaddr_t)base;
+		base = STACK_GROW(base, pthread__stacksize);
+		pthread__mainstruct = (vaddr_t)base;
+	}
 	size = pthread__stacksize;
+	if (mprotect(base, size, PROT_READ|PROT_WRITE) == -1)
+		err(1, "mprotect stack");
 
 	error = pthread__stackid_setup(base, size, &t);
 	if (error) {
@@ -1258,7 +1267,6 @@
 #else
 	t->pt_stack.ss_sp = (char *)(void *)base + 2 * pagesize;
 #endif
-
 	/* Protect the next-to-bottom stack page as a red zone. */
 	ret = mprotect(redaddr, pagesize, PROT_NONE);
 	if (ret == -1) {

Index: src/lib/libpthread/pthread_int.h
diff -u src/lib/libpthread/pthread_int.h:1.72 src/lib/libpthread/pthread_int.h:1.73
--- src/lib/libpthread/pthread_int.h:1.72	Sun May 17 10:49:00 2009
+++ src/lib/libpthread/pthread_int.h	Sat Dec 18 10:54:27 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pthread_int.h,v 1.72 2009/05/17 14:49:00 ad Exp $	*/
+/*	$NetBSD: pthread_int.h,v 1.73 2010/12/18 15:54:27 christos Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -249,13 +249,18 @@
 	_INITCONTEXT_U_MD(ucp)						\
 	} while (/*CONSTCOND*/0)
 
-/* Stack location of pointer to a particular thread */
-#define pthread__id(sp) \
-	((pthread_t) (((vaddr_t)(sp)) & pthread__threadmask))
 
 #ifdef PTHREAD__HAVE_THREADREG
 #define	pthread__self()		pthread__threadreg_get()
 #else
+/* Stack location of pointer to a particular thread */
+extern vaddr_t	pthread__mainbase;
+extern vaddr_t	pthread__mainstruct;
+static inline pthread_t
+pthread__id(vaddr_t sp) {
+	vaddr_t va = sp & pthread__threadmask;
+	return (pthread_t)(va == pthread__mainbase ? pthread__mainstruct : va);
+}
 #define pthread__self() 	(pthread__id(pthread__sp()))
 #endif
 

Reply via email to