mailing list of musl libc
 help / color / mirror / code / Atom feed
* [RFC PATCH v2 2/4] support SafeStack in init and threading
@ 2016-10-28 20:00 LeMay, Michael
  2016-11-01 23:52 ` Szabolcs Nagy
  0 siblings, 1 reply; 5+ messages in thread
From: LeMay, Michael @ 2016-10-28 20:00 UTC (permalink / raw)
  To: musl

This patch adds storage in the thread control block for the unsafe
stack pointer and safe stack metadata for that thread when SafeStack
is enabled.  It modifies the libc initialization routines and thread
creation routines to allocate and initialize both safe and unsafe
stacks.  Likewise, it modifies the thread destruction routine to unmap
the safe stack.

Signed-off-by: Michael LeMay <michael.lemay@intel.com>
---
 src/env/__libc_start_main.c |  16 +++++++
 src/internal/pthread_impl.h |  13 ++++++
 src/internal/safe_stack.c   | 109 ++++++++++++++++++++++++++++++++++++++++++++
 src/thread/pthread_create.c |  16 ++++++-
 4 files changed, 153 insertions(+), 1 deletion(-)
 create mode 100644 src/internal/safe_stack.c

diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c
index 5c79be2..b3c2b0d 100644
--- a/src/env/__libc_start_main.c
+++ b/src/env/__libc_start_main.c
@@ -19,6 +19,11 @@ weak_alias(dummy1, __init_ssp);
 
 #define AUX_CNT 38
 
+#if SAFE_STACK
+void __init_unsafe_stack(void);
+
+__attribute__((no_sanitize("safe-stack")))
+#endif
 void __init_libc(char **envp, char *pn)
 {
 	size_t i, *auxv, aux[AUX_CNT] = { 0 };
@@ -36,6 +41,9 @@ void __init_libc(char **envp, char *pn)
 	}
 
 	__init_tls(aux);
+#if SAFE_STACK
+	__init_unsafe_stack();
+#endif
 	__init_ssp((void *)aux[AT_RANDOM]);
 
 	if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID]
@@ -63,10 +71,18 @@ static void libc_start_init(void)
 
 weak_alias(libc_start_init, __libc_start_init);
 
+#if SAFE_STACK
+void __preinit_unsafe_stack(void);
+
+__attribute__((no_sanitize("safe-stack")))
+#endif
 int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv)
 {
 	char **envp = argv+argc+1;
 
+#if SAFE_STACK
+	__preinit_unsafe_stack();
+#endif
 	__init_libc(envp, argv[0]);
 	__libc_start_init();
 
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index 3890bb5..2b4fc30 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -18,6 +18,19 @@ struct pthread {
 	uintptr_t sysinfo;
 	uintptr_t canary, canary2;
 	pid_t tid, pid;
+#if SAFE_STACK
+	/* offset of unsafe_stack_ptr must be 0x24 for 32-bit targets
+	 * and 0x48 for 64-bit targets */
+#if __SIZEOF_POINTER__ == 8
+	void *safe_stack_base;
+	void *unsafe_stack_ptr;
+#else
+	void *unsafe_stack_ptr;
+	void *safe_stack_base;
+#endif
+	/* size of safe stack allocation, including the guard */
+	size_t safe_stack_size;
+#endif
 	int tsd_used, errno_val;
 	volatile int cancel, canceldisable, cancelasync;
 	int detached;
diff --git a/src/internal/safe_stack.c b/src/internal/safe_stack.c
new file mode 100644
index 0000000..7c873e3
--- /dev/null
+++ b/src/internal/safe_stack.c
@@ -0,0 +1,109 @@
+#if SAFE_STACK
+
+#define _GNU_SOURCE
+#include "pthread_impl.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+static bool unsafe_stack_ptr_inited = false;
+
+void *__mmap(void *, size_t, int, int, int, off_t);
+int __munmap(void *, size_t);
+int __mprotect(void *, size_t, int);
+
+/* There are no checks for overflows past the end of this stack buffer. It must
+ * be allocated with adequate space to meet the requirements of all of the code
+ * that runs prior to __init_unsafe_stack allocating a new unsafe stack.  This
+ * buffer is not used after that. */
+static uint8_t preinit_us[PAGE_SIZE];
+
+__attribute__((no_sanitize("safe-stack"), __visibility__("hidden")))
+void __init_unsafe_stack(void)
+{
+	void *stack_base;
+	size_t stack_size;
+	pthread_attr_t attr;
+	struct pthread *self;
+
+	if (unsafe_stack_ptr_inited)
+		return;
+
+	self = __pthread_self();
+
+	/* Set the unsafe stack pointer in the current TCB to the statically-allocated
+	 * unsafe stack, since some of the subroutines invoked below may use the
+	 * unsafe stack. */
+	self->unsafe_stack_ptr = preinit_us + sizeof(preinit_us);
+
+	if (pthread_getattr_np(self, &attr) != 0)
+		a_crash();
+
+	if (pthread_attr_getstack(&attr, &stack_base, &stack_size) != 0)
+		a_crash();
+
+	stack_size *= 2;
+
+	/* This mapping is not reclaimed until the process exits. */
+	uint8_t *unsafe_stack = __mmap(0, stack_size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
+	if (unsafe_stack == MAP_FAILED)
+		a_crash();
+
+	unsafe_stack += DEFAULT_GUARD_SIZE;
+	stack_size -= DEFAULT_GUARD_SIZE;
+
+	if (__mprotect(unsafe_stack, stack_size, PROT_READ|PROT_WRITE)
+	    && errno != ENOSYS)
+		a_crash();
+
+	self->unsafe_stack_ptr = unsafe_stack + stack_size;
+
+	unsafe_stack_ptr_inited = true;
+}
+
+static struct pthread preinit_tcb = {
+	.unsafe_stack_ptr =	preinit_us + sizeof(preinit_us)
+};
+
+/* Install a TCB with just the unsafe stack pointer initialized. */
+__attribute__((no_sanitize("safe-stack"), __visibility__("hidden")))
+void __preinit_unsafe_stack(void)
+{
+	if (unsafe_stack_ptr_inited)
+		return;
+
+	__set_thread_area(&preinit_tcb);
+}
+
+#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
+
+__attribute__((__visibility__("hidden")))
+int __safestack_init_thread(struct pthread *restrict new, const pthread_attr_t *restrict attr)
+{
+	size_t size, guard;
+	unsigned char *map = 0;
+
+	new->unsafe_stack_ptr = new->stack;
+
+	guard = ROUND(DEFAULT_GUARD_SIZE + attr->_a_guardsize);
+	size = ROUND(new->stack_size + guard);
+
+	map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
+	if (map == MAP_FAILED)
+		goto fail;
+	if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)
+	    && errno != ENOSYS) {
+		__munmap(map, size);
+		goto fail;
+	}
+
+	new->safe_stack_base = map;
+	new->safe_stack_size = size;
+	new->stack = map + size;
+
+	return 0;
+fail:
+	return EAGAIN;
+}
+
+#endif /*SAFE_STACK*/
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index 9f6b98e..1a8304b 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -19,7 +19,7 @@ weak_alias(dummy_0, __pthread_tsd_run_dtors);
 weak_alias(dummy_0, __do_orphaned_stdio_locks);
 weak_alias(dummy_0, __dl_thread_cleanup);
 
-_Noreturn void __pthread_exit(void *result)
+_Noreturn void __pthread_exit_generic(void *result)
 {
 	pthread_t self = __pthread_self();
 	sigset_t set;
@@ -116,6 +116,8 @@ _Noreturn void __pthread_exit(void *result)
 	for (;;) __syscall(SYS_exit, 0);
 }
 
+weak_alias(__pthread_exit_generic, __pthread_exit);
+
 void __do_cleanup_push(struct __ptcb *cb)
 {
 	struct pthread *self = __pthread_self();
@@ -176,6 +178,10 @@ static void init_file_lock(FILE *f)
 
 void *__copy_tls(unsigned char *);
 
+#if SAFE_STACK
+int __safestack_init_thread(struct pthread *restrict, const pthread_attr_t *restrict);
+#endif
+
 int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg)
 {
 	int ret, c11 = (attrp == __ATTRP_C11_THREAD);
@@ -269,6 +275,14 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
 	new->robust_list.head = &new->robust_list.head;
 	new->unblock_cancel = self->cancel;
 	new->CANARY = self->CANARY;
+#if SAFE_STACK
+	ret = __safestack_init_thread(new, &attr);
+	if (ret != 0) {
+		if (map) __munmap(map, size);
+		__release_ptc();
+		return ret;
+	}
+#endif
 
 	a_inc(&libc.threads_minus_1);
 	ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid);
-- 
2.7.4



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-11-02 21:50 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-28 20:00 [RFC PATCH v2 2/4] support SafeStack in init and threading LeMay, Michael
2016-11-01 23:52 ` Szabolcs Nagy
2016-11-02 16:56   ` LeMay, Michael
2016-11-02 17:40     ` Szabolcs Nagy
2016-11-02 21:50       ` LeMay, Michael

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).