ARM: Add pointer encryption support.

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.
This commit is contained in:
Will Newton 2013-08-07 13:55:30 +01:00
parent 29c793b3c2
commit b7f2d27dbd
7 changed files with 109 additions and 6 deletions

View 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

View 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)

View 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

View 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
@ -27,8 +28,18 @@
#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)

View File

@ -24,11 +24,25 @@
#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

View File

@ -171,6 +171,18 @@
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,

View 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 */