From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/10675 Path: news.gmane.org!.POSTED!not-for-mail From: "LeMay, Michael" Newsgroups: gmane.linux.lib.musl.general Subject: [RFC PATCH v2 2/4] support SafeStack in init and threading Date: Fri, 28 Oct 2016 20:00:24 +0000 Message-ID: <390CE752059EB848A71F4F676EBAB76D3AC2636A@ORSMSX114.amr.corp.intel.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1477684849 27075 195.159.176.226 (28 Oct 2016 20:00:49 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 28 Oct 2016 20:00:49 +0000 (UTC) To: "musl@lists.openwall.com" Original-X-From: musl-return-10688-gllmg-musl=m.gmane.org@lists.openwall.com Fri Oct 28 22:00:45 2016 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by blaine.gmane.org with smtp (Exim 4.84_2) (envelope-from ) id 1c0DKR-0005qu-FD for gllmg-musl@m.gmane.org; Fri, 28 Oct 2016 22:00:39 +0200 Original-Received: (qmail 14097 invoked by uid 550); 28 Oct 2016 20:00:40 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Original-Received: (qmail 14056 invoked from network); 28 Oct 2016 20:00:38 -0000 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,411,1473145200"; d="scan'208";a="24969736" Thread-Topic: [RFC PATCH v2 2/4] support SafeStack in init and threading Thread-Index: AdIxVX3PY+g+0aRRTN2OiDoYxHEwoA== Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.22.254.140] Xref: news.gmane.org gmane.linux.lib.musl.general:10675 Archived-At: 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 --- 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); =20 #define AUX_CNT 38 =20 +#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] =3D { 0 }; @@ -36,6 +41,9 @@ void __init_libc(char **envp, char *pn) } =20 __init_tls(aux); +#if SAFE_STACK + __init_unsafe_stack(); +#endif __init_ssp((void *)aux[AT_RANDOM]); =20 if (aux[AT_UID]=3D=3Daux[AT_EUID] && aux[AT_GID]=3D=3Daux[AT_EGID] @@ -63,10 +71,18 @@ static void libc_start_init(void) =20 weak_alias(libc_start_init, __libc_start_init); =20 +#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 **a= rgv) { char **envp =3D argv+argc+1; =20 +#if SAFE_STACK + __preinit_unsafe_stack(); +#endif __init_libc(envp, argv[0]); __libc_start_init(); =20 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__ =3D=3D 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 +#include +#include + +static bool unsafe_stack_ptr_inited =3D 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 =3D __pthread_self(); + + /* Set the unsafe stack pointer in the current TCB to the statically-allo= cated + * unsafe stack, since some of the subroutines invoked below may use the + * unsafe stack. */ + self->unsafe_stack_ptr =3D preinit_us + sizeof(preinit_us); + + if (pthread_getattr_np(self, &attr) !=3D 0) + a_crash(); + + if (pthread_attr_getstack(&attr, &stack_base, &stack_size) !=3D 0) + a_crash(); + + stack_size *=3D 2; + + /* This mapping is not reclaimed until the process exits. */ + uint8_t *unsafe_stack =3D __mmap(0, stack_size, PROT_NONE, MAP_PRIVATE|MA= P_ANON, -1, 0); + if (unsafe_stack =3D=3D MAP_FAILED) + a_crash(); + + unsafe_stack +=3D DEFAULT_GUARD_SIZE; + stack_size -=3D DEFAULT_GUARD_SIZE; + + if (__mprotect(unsafe_stack, stack_size, PROT_READ|PROT_WRITE) + && errno !=3D ENOSYS) + a_crash(); + + self->unsafe_stack_ptr =3D unsafe_stack + stack_size; + + unsafe_stack_ptr_inited =3D true; +} + +static struct pthread preinit_tcb =3D { + .unsafe_stack_ptr =3D 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_at= tr_t *restrict attr) +{ + size_t size, guard; + unsigned char *map =3D 0; + + new->unsafe_stack_ptr =3D new->stack; + + guard =3D ROUND(DEFAULT_GUARD_SIZE + attr->_a_guardsize); + size =3D ROUND(new->stack_size + guard); + + map =3D __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); + if (map =3D=3D MAP_FAILED) + goto fail; + if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE) + && errno !=3D ENOSYS) { + __munmap(map, size); + goto fail; + } + + new->safe_stack_base =3D map; + new->safe_stack_size =3D size; + new->stack =3D 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); =20 -_Noreturn void __pthread_exit(void *result) +_Noreturn void __pthread_exit_generic(void *result) { pthread_t self =3D __pthread_self(); sigset_t set; @@ -116,6 +116,8 @@ _Noreturn void __pthread_exit(void *result) for (;;) __syscall(SYS_exit, 0); } =20 +weak_alias(__pthread_exit_generic, __pthread_exit); + void __do_cleanup_push(struct __ptcb *cb) { struct pthread *self =3D __pthread_self(); @@ -176,6 +178,10 @@ static void init_file_lock(FILE *f) =20 void *__copy_tls(unsigned char *); =20 +#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 *restri= ct attrp, void *(*entry)(void *), void *restrict arg) { int ret, c11 =3D (attrp =3D=3D __ATTRP_C11_THREAD); @@ -269,6 +275,14 @@ int __pthread_create(pthread_t *restrict res, const pt= hread_attr_t *restrict att new->robust_list.head =3D &new->robust_list.head; new->unblock_cancel =3D self->cancel; new->CANARY =3D self->CANARY; +#if SAFE_STACK + ret =3D __safestack_init_thread(new, &attr); + if (ret !=3D 0) { + if (map) __munmap(map, size); + __release_ptc(); + return ret; + } +#endif =20 a_inc(&libc.threads_minus_1); ret =3D __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, = TP_ADJ(new), &new->tid); --=20 2.7.4