]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
ARM: Add pointer encryption support.
authorWill Newton <will.newton@linaro.org>
Wed, 7 Aug 2013 12:55:30 +0000 (13:55 +0100)
committerWill Newton <will.newton@linaro.org>
Thu, 3 Oct 2013 10:35:50 +0000 (11:35 +0100)
Add support for pointer encryption in glibc internal structures in C
and assembler code. Pointer encryption is a glibc security feature
described here:

https://sourceware.org/glibc/wiki/PointerEncryption

The ARM implementation uses global variables instead of thread pointer
relative accesses to get the value of the pointer encryption guard
because accessing the thread pointer can be very expensive on older
ARM cores.

ports/ChangeLog.arm:

2013-10-03  Will Newton  <will.newton@linaro.org>

* sysdeps/arm/__longjmp.S (__longjmp): Demangle fp, sp
and lr when restoring register values.
* sysdeps/arm/include/bits/setjmp.h (JMP_BUF_REGLIST): Remove
sp and lr from list and replace fp with a4.
* sysdeps/arm/jmpbuf-unwind.h (_jmpbuf_sp): New function.
(_JMPBUF_UNWINDS_ADJ): Call _jmpbuf_sp.
* sysdeps/arm/setjmp.S (__sigsetjmp): Mangle fp, sp and lr
before storing register values.
* sysdeps/arm/sysdep.h (LDST_GLOBAL): New macro.
* sysdeps/unix/sysv/linux/arm/sysdep.h (PTR_MANGLE): New macro.
(PTR_DEMANGLE): Likewise. (PTR_MANGLE2): Likewise.
(PTR_DEMANGLE2): Likewise.

ports/ChangeLog.arm
ports/sysdeps/arm/__longjmp.S
ports/sysdeps/arm/include/bits/setjmp.h
ports/sysdeps/arm/jmpbuf-unwind.h
ports/sysdeps/arm/setjmp.S
ports/sysdeps/arm/sysdep.h
ports/sysdeps/unix/sysv/linux/arm/sysdep.h

index a84c7d211cea1c8a4d921b89591c15de187c62f9..0724dbd9a008f2b923b93c6c123348b50edce6e6 100644 (file)
@@ -1,3 +1,18 @@
+2013-10-03  Will Newton  <will.newton@linaro.org>
+
+       * sysdeps/arm/__longjmp.S (__longjmp): Demangle fp, sp
+       and lr when restoring register values.
+       * sysdeps/arm/include/bits/setjmp.h (JMP_BUF_REGLIST): Remove
+       sp and lr from list and replace fp with a4.
+       * sysdeps/arm/jmpbuf-unwind.h (_jmpbuf_sp): New function.
+       (_JMPBUF_UNWINDS_ADJ): Call _jmpbuf_sp.
+       * sysdeps/arm/setjmp.S (__sigsetjmp): Mangle fp, sp and lr
+       before storing register values.
+       * sysdeps/arm/sysdep.h (LDST_GLOBAL): New macro.
+       * sysdeps/unix/sysv/linux/arm/sysdep.h (PTR_MANGLE): New macro.
+       (PTR_DEMANGLE): Likewise. (PTR_MANGLE2): Likewise.
+       (PTR_DEMANGLE2): Likewise.
+
 2013-09-24  Will Newton  <will.newton@linaro.org>
 
        * ports/sysdeps/arm/nptl/tls.h (TLS_INIT_TP_EXPENSIVE): Remove
index a5edede16d70361c8e1f866b139c9b200a012e0a..2b1f7f41c19ee7ed46f1107a5238c18f14d25b15 100644 (file)
@@ -34,10 +34,24 @@ ENTRY (__longjmp)
        sfi_breg ip, \
        ldr     r4, [\B, #32]   /* jmpbuf's sp */
        cfi_undefined (r4)
+#ifdef PTR_DEMANGLE
+       PTR_DEMANGLE (r4, r4, a3, a4)
+#endif
        CHECK_SP (r4)
 #endif
        sfi_sp sfi_breg ip, \
        ldmia   \B!, JMP_BUF_REGLIST
+#ifdef PTR_DEMANGLE
+       PTR_DEMANGLE (fp, a4, a3, a2)
+       ldr     a4, [ip], #4
+       PTR_DEMANGLE2 (sp, a4, a3)
+       ldr     a4, [ip], #4
+       PTR_DEMANGLE2 (lr, a4, a3)
+#else
+       mov     fp, a4
+       ldr     sp, [ip], #4
+       ldr     lr, [ip], #4
+#endif
        cfi_restore (v1)
        cfi_restore (v2)
        cfi_restore (v3)
index 1559d7b8e634b3370bc1d5deb8cf65fc96eb048b..64505dcb945b84d55c5da3fbdfbb31f2a7371b88 100644 (file)
@@ -26,8 +26,9 @@
 
 #ifndef _ISOMAC
 /* Register list for a ldm/stm instruction to load/store
-   the general registers from a __jmp_buf.  */
-# define JMP_BUF_REGLIST       {v1-v6, sl, fp, sp, lr}
+   the general registers from a __jmp_buf. The a4 register
+   contains fp at this point.  */
+# define JMP_BUF_REGLIST       {a4, v1-v6, sl}
 
 /* Index of __jmp_buf where the sp register resides.  */
 # define __JMP_BUF_SP          8
index 0863540ce067fcc12977ab8360f541b3d87c585c..1b0d0202e39fc3c5112a114c64545b5129ade9c2 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <setjmp.h>
 #include <stdint.h>
+#include <sysdep.h>
 #include <unwind.h>
 
 /* Test if longjmp to JMPBUF would unwind the frame
 #define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
   _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
 
+static inline uintptr_t __attribute__ ((unused))
+_jmpbuf_sp (__jmp_buf regs)
+{
+  uintptr_t sp = regs[__JMP_BUF_SP];
+#ifdef PTR_DEMANGLE
+  PTR_DEMANGLE (sp);
+#endif
+  return sp;
+}
+
 #define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
-  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj))
+  ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
 
 /* We use the normal longjmp for unwinding.  */
 #define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
index a6c161db54144ed018051e2a8bfe002960708274..b38b919af065cbae2d176de9100439d0373bacf0 100644 (file)
 #include <arm-features.h>
 
 ENTRY (__sigsetjmp)
+#ifdef PTR_MANGLE
+       PTR_MANGLE (a4, fp, a3, ip)
+#else
+       mov     a4, fp
+#endif
        mov     ip, r0
 
        /* Save registers */
        sfi_breg ip, \
        stmia   \B!, JMP_BUF_REGLIST
+#ifdef PTR_MANGLE
+       PTR_MANGLE2 (a4, sp, a3)
+       str     a4, [ip], #4
+       PTR_MANGLE2 (a4, lr, a3)
+       str     a4, [ip], #4
+#else
+       str     sp, [ip], #4
+       str     lr, [ip], #4
+#endif
 
 #if !defined ARM_ASSUME_NO_IWMMXT || defined __SOFTFP__
 # define NEED_HWCAP 1
index 550159740bc5572bc576d3e6d85d1c03a9049368..3823617f13d9f3b0615618e987be72d409999542 100644 (file)
 99:    OP      R, [pc, T]
 # endif
 
+/* Load or store to/from a global EXPR into/from R, using T.  */
+# define LDST_GLOBAL(OP, R, T, EXPR)                   \
+       ldr     T, 99f;                                 \
+       ldr     R, 100f;                                \
+98:    add     T, T, pc;                               \
+       ldr     T, [T, R];                              \
+       .subsection 2;                                  \
+99:    .word   _GLOBAL_OFFSET_TABLE_ - 98b - PC_OFS;   \
+100:   .word   EXPR##(GOT);                            \
+       .previous;                                      \
+       OP      R, [T]
+
 /* Cope with negative memory offsets, which thumb can't encode.
    Use NEGOFF_ADJ_BASE to (conditionally) alter the base register,
    and then NEGOFF_OFF1 to use 0 for thumb and the offset for arm,
index b195d8ea1d4149be38bbeaa10ae964cb8d0145e9..6cfe4e08a713d7bf50af3adf708307385ad0a17a 100644 (file)
@@ -435,8 +435,44 @@ __local_syscall_error:                                             \
 
 #endif /* __ASSEMBLER__ */
 
-/* Pointer mangling is not yet supported for ARM.  */
-#define PTR_MANGLE(var) (void) (var)
-#define PTR_DEMANGLE(var) (void) (var)
+/* Pointer mangling support.  */
+#if (defined NOT_IN_libc && defined IS_IN_rtld) || \
+  (!defined SHARED && (!defined NOT_IN_libc || defined IS_IN_libpthread))
+# ifdef __ASSEMBLER__
+#  define PTR_MANGLE(dst, src, guard, tmp)                             \
+  LDST_PCREL(ldr, guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard_local)); \
+  PTR_MANGLE2(dst, src, guard)
+/* Use PTR_MANGLE2 for efficiency if guard is already loaded.  */
+#  define PTR_MANGLE2(dst, src, guard)         \
+  eor dst, src, guard
+#  define PTR_DEMANGLE(dst, src, guard, tmp)   \
+  PTR_MANGLE (dst, src, guard, tmp)
+#  define PTR_DEMANGLE2(dst, src, guard)       \
+  PTR_MANGLE2 (dst, src, guard)
+# else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#  define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
+#  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
+# endif
+#else
+# ifdef __ASSEMBLER__
+#  define PTR_MANGLE(dst, src, guard, tmp)                             \
+  LDST_GLOBAL(ldr, guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard));    \
+  PTR_MANGLE2(dst, src, guard)
+/* Use PTR_MANGLE2 for efficiency if guard is already loaded.  */
+#  define PTR_MANGLE2(dst, src, guard)         \
+  eor dst, src, guard
+#  define PTR_DEMANGLE(dst, src, guard, tmp)   \
+  PTR_MANGLE (dst, src, guard, tmp)
+#  define PTR_DEMANGLE2(dst, src, guard)       \
+  PTR_MANGLE2 (dst, src, guard)
+# else
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#  define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard)
+#  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
+# endif
+#endif
 
 #endif /* linux/arm/sysdep.h */