Differences between revisions 2 and 3
Revision 2 as of 2013-10-16 13:37:05
Size: 3206
Editor: WillNewton
Comment:
Revision 3 as of 2013-10-16 13:45:43
Size: 3501
Editor: WillNewton
Comment: Added link to TLS benchmark code
Deletions are marked like this. Additions are marked like this.
Line 17: Line 17:
In general any port where the thread pointer is stored in a general purpose register will most likely find the per-thread scheme is the fastest method. Ports like ARM where access to the thread pointer can involve an instruction that can take many cycles or a call into the kernel may prefer to use global variables. In general any port where the thread pointer is stored in a general purpose register will most likely find the per-thread scheme is the fastest method. Ports like ARM where access to the thread pointer can involve an instruction that can take many cycles or a call into the kernel may prefer to use global variables. [[attachment:tls_benchmark.c|This]] benchmark code will give you an indication of which method is fastest. The thread pointer relative accesses will be slightly faster in practice than in the benchmark as the offset will be a compile time constant for the purposes of loading the pointer guard.

Pointer Encryption

Pointer encryption is a glibc security feature which aims to increase the difficulty to attackers of manipulating pointers - particularly function pointers - in glibc structures. This feature has also been referred to as "pointer mangling" or "pointer guard".

Implementation

A glibc port can support pointer encryption by implementing two macros:

   1 #define PTR_MANGLE(var)
   2 #define PTR_DEMANGLE(var)
   3 

These macros should XOR a known per-process value with the pointer var and return it. A corresponding pair of macros should also be implemented for use from assembly code so, for example, the pointers in jmp_buf can be encrypted, but these macros can be port-specific.

The startup code initializes a variable to a random value for use in these macros. There are two ways to access this variable which can be selected based on their relative performance on the target architecture. glibc only supports using one access method in any specific port however.

In general any port where the thread pointer is stored in a general purpose register will most likely find the per-thread scheme is the fastest method. Ports like ARM where access to the thread pointer can involve an instruction that can take many cycles or a call into the kernel may prefer to use global variables. This benchmark code will give you an indication of which method is fastest. The thread pointer relative accesses will be slightly faster in practice than in the benchmark as the offset will be a compile time constant for the purposes of loading the pointer guard.

Global variables

The pointer encryption guard value is initialized by the dynamic linker in the case of a dynamically linked executable and by the C library startup code in the case of a statically linked executable.

The dynamic linker exposes two variables, __pointer_chk_guard_local is hidden and can be used by dynamic linker code to access the guard value more efficiently, and __pointer_chk_guard is global and should be used by the dynamically linked C library.

   1 uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden __attribute__ ((nocommon));
   2 strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)

The static C library startup code only provides __pointer_chk_guard_local as global access to the variable is not required in a static link.

Per-thread variables

Many architectures can more efficiently access a variable at a constant offset from the thread pointer than a global variable. On these architectures it is better to store the pointer encryption guard value in the TCB.

An example tcbhead_t layout:

   1 typedef struct
   2 {
   3   dtv_t *dtv;
   4   uintptr_t pointer_guard;
   5 } tcbhead_t;

It is required to implement two macros for generic code:

   1 #define THREAD_SET_POINTER_GUARD(value)
   2 #define THREAD_COPY_POINTER_GUARD(descr)
   3 

THREAD_SET_POINTER_GUARD sets the pointer encryption guard for the current thread to value. THREAD_COPY_POINTER_GUARD copies the pointer encryption guard for the current thread and initializes the TCB referenced by descr with that value.

The port should also provide a stackguard-macros.h file and make sure that it defines the POINTER_CHK_GUARD macro to enable the pointer encryption tests to pass.

References

None: PointerEncryption (last edited 2013-10-16 13:45:43 by WillNewton)