summaryrefslogtreecommitdiff
path: root/csu/libc-start.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-01-24 15:27:49 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-01-26 08:04:44 -0800
commitd139cd31adaf9f091a36027c8a452b016a05e95c (patch)
treee4cf3bbcdfaf1785476569d5deef9b05d18e993c /csu/libc-start.c
parent048fc0aaf81cd328631b3485e348e3e5723cb826 (diff)
downloadglibc-hjl/pr22743/master.tar.gz
nptl: Update struct pthread_unwind_buf [BZ #22743]hjl/pr22743/master
In glibc 2.28, the size of cancel_jmp_buf in struct pthread_unwind_buf has been increased to match the size of __jmp_buf_tag on Linux/x86 in order to save and restore shadow stack register. pthread_unwind_buf is used in <pthread.h>, whose address is passed from applications to libpthread. To access the private data in struct pthread_unwind_buf, which is placed after cancel_jmp_buf, in libpthread, we must know which struct pthread_unwind_buf, before glibc 28 and after glibc 2.28, is used in caller. If the size of caller's struct pthread_unwind_buf is smaller than what libpthread expects, libpthread will override caller's stack since struct pthread_unwind_buf is placed on caller's stack. We enable shadow stack at run-time only if program and all used shared objects, including dlopened ones, are shadow stack enabled, which means that they must be compiled with GCC 8 or above and glibc 2.28 or above. Since we need to save and restore shadow stack register only if shadow stack is enabled, we can safely assume that caller is compiled with smaller struct pthread_unwind_buf on stack if shadow stack isn't enabled at run-time. For callers with larger struct pthread_unwind_buf, but shadow stack isn't enabled, we just have some unused space on caller's stack. struct pthread_unwind_buf is changed to union of 1. struct cancel_jmp_buf[1], which contains the common fields of struct full and struct compat_pthread_unwind_buf. 2. struct full_pthread_unwind_buf, which is the full layout of the cleanup buffer. 3. struct compat_pthread_unwind_buf, which is the compatible layout of the cleanup buffer. A macro, UNWIND_BUF_PRIV, is added to get the pointer to the priv field. By default, it uses the priv field of struct compat_pthread_unwind_buf. If a target defines NEED_SAVED_MASK_IN_CANCEL_JMP_BUF, it must provide its own version of UNEIND_BUF_PRIV to get the pointer to the priv field. On Linux/x86, it uses the priv field of struct compat_pthread_unwind_buf if shadow stack is disabled and struct full_pthread_unwind_buf if shadow stack is enabled. Note: There is an unused pointer space in pthread_unwind_buf_data. But it isn't unsuitable for saving and restoring shadow stack register since x32 is a 64-bit process with 32-bit software pointer and kernel may place x32 shadow stack above 4GB. We need to save and restore 64-bit shadow stack register for x32. [BZ #22743] * csu/libc-start.c (LIBC_START_MAIN): Use the full version of the cleanup buffer. * nptl/cleanup.c (__pthread_register_cancel): Use UNWIND_BUF_PRIV to access the priv field in the cleanup buffer. (__pthread_unregister_cancel): Likewise. * nptl/cleanup_defer.c (__pthread_register_cancel_defer): Likewise. (__pthread_unregister_cancel_restore): Likewise. * nptl/unwind.c (unwind_stop): Likewise. (__pthread_unwind_next): Likewise. * nptl/descr.h (pthread_unwind_buf_data): New. (full_pthread_unwind_buf): Likewise. (compat_pthread_unwind_buf): Likewise. (pthread_unwind_buf): Updated to use full_pthread_unwind_buf and compat_pthread_unwind_buf. (UNWIND_BUF_PRIV): New. Macro to get pointer to the priv field in the cleanup buffer. * nptl/pthread_create.c (START_THREAD_DEFN): Use the full version of the cleanup buffer. (__pthread_create_2_1): Use THREAD_COPY_ADDITONAL_INFO to copy additonal info if defined. * sysdeps/unix/sysv/linux/x86/nptl/pthreadP.h: Use the full version of the cleanup buffer to check cancel_jmp_buf size. * sysdeps/unix/sysv/linux/x86/pthreaddef.h (THREAD_COPY_ADDITONAL_INFO): New. (UNWIND_BUF_PRIV): Likewise.
Diffstat (limited to 'csu/libc-start.c')
-rw-r--r--csu/libc-start.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 605222fa3f..c6bbc97ef0 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -298,8 +298,10 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
struct pthread *self = THREAD_SELF;
/* Store old info. */
- unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
- unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+ unwind_buf.full.priv.data.prev
+ = THREAD_GETMEM (self, cleanup_jmp_buf);
+ unwind_buf.full.priv.data.cleanup
+ = THREAD_GETMEM (self, cleanup);
/* Store the new cleanup handler info. */
THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);