10fca6ea1SDimitry Andric /*===---- ptrauth.h - Pointer authentication -------------------------------=== 20fca6ea1SDimitry Andric * 30fca6ea1SDimitry Andric * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40fca6ea1SDimitry Andric * See https://llvm.org/LICENSE.txt for license information. 50fca6ea1SDimitry Andric * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60fca6ea1SDimitry Andric * 70fca6ea1SDimitry Andric *===-----------------------------------------------------------------------=== 80fca6ea1SDimitry Andric */ 90fca6ea1SDimitry Andric 100fca6ea1SDimitry Andric #ifndef __PTRAUTH_H 110fca6ea1SDimitry Andric #define __PTRAUTH_H 120fca6ea1SDimitry Andric 130fca6ea1SDimitry Andric typedef enum { 140fca6ea1SDimitry Andric ptrauth_key_asia = 0, 150fca6ea1SDimitry Andric ptrauth_key_asib = 1, 160fca6ea1SDimitry Andric ptrauth_key_asda = 2, 170fca6ea1SDimitry Andric ptrauth_key_asdb = 3, 180fca6ea1SDimitry Andric 190fca6ea1SDimitry Andric /* A process-independent key which can be used to sign code pointers. */ 200fca6ea1SDimitry Andric ptrauth_key_process_independent_code = ptrauth_key_asia, 210fca6ea1SDimitry Andric 220fca6ea1SDimitry Andric /* A process-specific key which can be used to sign code pointers. */ 230fca6ea1SDimitry Andric ptrauth_key_process_dependent_code = ptrauth_key_asib, 240fca6ea1SDimitry Andric 250fca6ea1SDimitry Andric /* A process-independent key which can be used to sign data pointers. */ 260fca6ea1SDimitry Andric ptrauth_key_process_independent_data = ptrauth_key_asda, 270fca6ea1SDimitry Andric 280fca6ea1SDimitry Andric /* A process-specific key which can be used to sign data pointers. */ 290fca6ea1SDimitry Andric ptrauth_key_process_dependent_data = ptrauth_key_asdb, 300fca6ea1SDimitry Andric 31*62987288SDimitry Andric /* The key used to sign return addresses on the stack. 32*62987288SDimitry Andric The extra data is based on the storage address of the return address. 33*62987288SDimitry Andric On AArch64, that is always the storage address of the return address + 8 34*62987288SDimitry Andric (or, in other words, the value of the stack pointer on function entry) */ 35*62987288SDimitry Andric ptrauth_key_return_address = ptrauth_key_process_dependent_code, 36*62987288SDimitry Andric 370fca6ea1SDimitry Andric /* The key used to sign C function pointers. 380fca6ea1SDimitry Andric The extra data is always 0. */ 390fca6ea1SDimitry Andric ptrauth_key_function_pointer = ptrauth_key_process_independent_code, 400fca6ea1SDimitry Andric 410fca6ea1SDimitry Andric /* The key used to sign C++ v-table pointers. 420fca6ea1SDimitry Andric The extra data is always 0. */ 430fca6ea1SDimitry Andric ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data, 440fca6ea1SDimitry Andric 450fca6ea1SDimitry Andric /* Other pointers signed under the ABI use private ABI rules. */ 460fca6ea1SDimitry Andric 470fca6ea1SDimitry Andric } ptrauth_key; 480fca6ea1SDimitry Andric 490fca6ea1SDimitry Andric /* An integer type of the appropriate size for a discriminator argument. */ 500fca6ea1SDimitry Andric typedef __UINTPTR_TYPE__ ptrauth_extra_data_t; 510fca6ea1SDimitry Andric 520fca6ea1SDimitry Andric /* An integer type of the appropriate size for a generic signature. */ 530fca6ea1SDimitry Andric typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; 540fca6ea1SDimitry Andric 550fca6ea1SDimitry Andric /* A signed pointer value embeds the original pointer together with 560fca6ea1SDimitry Andric a signature that attests to the validity of that pointer. Because 570fca6ea1SDimitry Andric this signature must use only "spare" bits of the pointer, a 580fca6ea1SDimitry Andric signature's validity is probabilistic in practice: it is unlikely 590fca6ea1SDimitry Andric but still plausible that an invalidly-derived signature will 600fca6ea1SDimitry Andric somehow equal the correct signature and therefore successfully 610fca6ea1SDimitry Andric authenticate. Nonetheless, this scheme provides a strong degree 620fca6ea1SDimitry Andric of protection against certain kinds of attacks. */ 630fca6ea1SDimitry Andric 640fca6ea1SDimitry Andric /* Authenticating a pointer that was not signed with the given key 650fca6ea1SDimitry Andric and extra-data value will (likely) fail by trapping. */ 660fca6ea1SDimitry Andric 670fca6ea1SDimitry Andric /* The null function pointer is always the all-zero bit pattern. 680fca6ea1SDimitry Andric Signing an all-zero bit pattern will embed a (likely) non-zero 690fca6ea1SDimitry Andric signature in the result, and so the result will not seem to be 700fca6ea1SDimitry Andric a null function pointer. Authenticating this value will yield 710fca6ea1SDimitry Andric a null function pointer back. However, authenticating an 720fca6ea1SDimitry Andric all-zero bit pattern will probably fail, because the 730fca6ea1SDimitry Andric authentication will expect a (likely) non-zero signature to 740fca6ea1SDimitry Andric embedded in the value. 750fca6ea1SDimitry Andric 760fca6ea1SDimitry Andric Because of this, if a pointer may validly be null, you should 770fca6ea1SDimitry Andric check for null before attempting to authenticate it with one 780fca6ea1SDimitry Andric of these intrinsics. This is not necessary when using the 790fca6ea1SDimitry Andric __ptrauth qualifier; the compiler will perform this check 800fca6ea1SDimitry Andric automatically. */ 810fca6ea1SDimitry Andric 820fca6ea1SDimitry Andric #if __has_feature(ptrauth_intrinsics) 830fca6ea1SDimitry Andric 840fca6ea1SDimitry Andric /* Strip the signature from a value without authenticating it. 850fca6ea1SDimitry Andric 860fca6ea1SDimitry Andric If the value is a function pointer, the result will not be a 870fca6ea1SDimitry Andric legal function pointer because of the missing signature, and 880fca6ea1SDimitry Andric attempting to call it will result in an authentication failure. 890fca6ea1SDimitry Andric 900fca6ea1SDimitry Andric The value must be an expression of pointer type. 910fca6ea1SDimitry Andric The key must be a constant expression of type ptrauth_key. 920fca6ea1SDimitry Andric The result will have the same type as the original value. */ 930fca6ea1SDimitry Andric #define ptrauth_strip(__value, __key) __builtin_ptrauth_strip(__value, __key) 940fca6ea1SDimitry Andric 950fca6ea1SDimitry Andric /* Blend a constant discriminator into the given pointer-like value 960fca6ea1SDimitry Andric to form a new discriminator. Not all bits of the inputs are 970fca6ea1SDimitry Andric guaranteed to contribute to the result. 980fca6ea1SDimitry Andric 990fca6ea1SDimitry Andric On arm64e, the integer must fall within the range of a uint16_t; 1000fca6ea1SDimitry Andric other bits may be ignored. 1010fca6ea1SDimitry Andric 1020fca6ea1SDimitry Andric For the purposes of ptrauth_sign_constant, the result of calling 1030fca6ea1SDimitry Andric this function is considered a constant expression if the arguments 1040fca6ea1SDimitry Andric are constant. Some restrictions may be imposed on the pointer. 1050fca6ea1SDimitry Andric 1060fca6ea1SDimitry Andric The first argument must be an expression of pointer type. 1070fca6ea1SDimitry Andric The second argument must be an expression of integer type. 1080fca6ea1SDimitry Andric The result will have type uintptr_t. */ 1090fca6ea1SDimitry Andric #define ptrauth_blend_discriminator(__pointer, __integer) \ 1100fca6ea1SDimitry Andric __builtin_ptrauth_blend_discriminator(__pointer, __integer) 1110fca6ea1SDimitry Andric 1120fca6ea1SDimitry Andric /* Return a signed pointer for a constant address in a manner which guarantees 1130fca6ea1SDimitry Andric a non-attackable sequence. 1140fca6ea1SDimitry Andric 1150fca6ea1SDimitry Andric The value must be a constant expression of pointer type which evaluates to 1160fca6ea1SDimitry Andric a non-null pointer. 1170fca6ea1SDimitry Andric The key must be a constant expression of type ptrauth_key. 1180fca6ea1SDimitry Andric The extra data must be a constant expression of pointer or integer type; 1190fca6ea1SDimitry Andric if an integer, it will be coerced to ptrauth_extra_data_t. 1200fca6ea1SDimitry Andric The result will have the same type as the original value. 1210fca6ea1SDimitry Andric 1220fca6ea1SDimitry Andric This can be used in constant expressions. */ 1230fca6ea1SDimitry Andric #define ptrauth_sign_constant(__value, __key, __data) \ 1240fca6ea1SDimitry Andric __builtin_ptrauth_sign_constant(__value, __key, __data) 1250fca6ea1SDimitry Andric 1260fca6ea1SDimitry Andric /* Add a signature to the given pointer value using a specific key, 1270fca6ea1SDimitry Andric using the given extra data as a salt to the signing process. 1280fca6ea1SDimitry Andric 1290fca6ea1SDimitry Andric This operation does not authenticate the original value and is 1300fca6ea1SDimitry Andric therefore potentially insecure if an attacker could possibly 1310fca6ea1SDimitry Andric control that value. 1320fca6ea1SDimitry Andric 1330fca6ea1SDimitry Andric The value must be an expression of pointer type. 1340fca6ea1SDimitry Andric The key must be a constant expression of type ptrauth_key. 1350fca6ea1SDimitry Andric The extra data must be an expression of pointer or integer type; 1360fca6ea1SDimitry Andric if an integer, it will be coerced to ptrauth_extra_data_t. 1370fca6ea1SDimitry Andric The result will have the same type as the original value. */ 1380fca6ea1SDimitry Andric #define ptrauth_sign_unauthenticated(__value, __key, __data) \ 1390fca6ea1SDimitry Andric __builtin_ptrauth_sign_unauthenticated(__value, __key, __data) 1400fca6ea1SDimitry Andric 1410fca6ea1SDimitry Andric /* Authenticate a pointer using one scheme and resign it using another. 1420fca6ea1SDimitry Andric 1430fca6ea1SDimitry Andric If the result is subsequently authenticated using the new scheme, that 1440fca6ea1SDimitry Andric authentication is guaranteed to fail if and only if the initial 1450fca6ea1SDimitry Andric authentication failed. 1460fca6ea1SDimitry Andric 1470fca6ea1SDimitry Andric The value must be an expression of pointer type. 1480fca6ea1SDimitry Andric The key must be a constant expression of type ptrauth_key. 1490fca6ea1SDimitry Andric The extra data must be an expression of pointer or integer type; 1500fca6ea1SDimitry Andric if an integer, it will be coerced to ptrauth_extra_data_t. 1510fca6ea1SDimitry Andric The result will have the same type as the original value. 1520fca6ea1SDimitry Andric 1530fca6ea1SDimitry Andric This operation is guaranteed to not leave the intermediate value 1540fca6ea1SDimitry Andric available for attack before it is re-signed. 1550fca6ea1SDimitry Andric 1560fca6ea1SDimitry Andric Do not pass a null pointer to this function. A null pointer 1570fca6ea1SDimitry Andric will not successfully authenticate. 1580fca6ea1SDimitry Andric 1590fca6ea1SDimitry Andric This operation traps if the authentication fails. */ 1600fca6ea1SDimitry Andric #define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \ 1610fca6ea1SDimitry Andric __new_data) \ 1620fca6ea1SDimitry Andric __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \ 1630fca6ea1SDimitry Andric __new_data) 1640fca6ea1SDimitry Andric 1650fca6ea1SDimitry Andric /* Authenticate a pointer using one scheme and resign it as a C 1660fca6ea1SDimitry Andric function pointer. 1670fca6ea1SDimitry Andric 1680fca6ea1SDimitry Andric If the result is subsequently authenticated using the new scheme, that 1690fca6ea1SDimitry Andric authentication is guaranteed to fail if and only if the initial 1700fca6ea1SDimitry Andric authentication failed. 1710fca6ea1SDimitry Andric 1720fca6ea1SDimitry Andric The value must be an expression of function pointer type. 1730fca6ea1SDimitry Andric The key must be a constant expression of type ptrauth_key. 1740fca6ea1SDimitry Andric The extra data must be an expression of pointer or integer type; 1750fca6ea1SDimitry Andric if an integer, it will be coerced to ptrauth_extra_data_t. 1760fca6ea1SDimitry Andric The result will have the same type as the original value. 1770fca6ea1SDimitry Andric 1780fca6ea1SDimitry Andric This operation is guaranteed to not leave the intermediate value 1790fca6ea1SDimitry Andric available for attack before it is re-signed. Additionally, if this 1800fca6ea1SDimitry Andric expression is used syntactically as the function expression in a 1810fca6ea1SDimitry Andric call, only a single authentication will be performed. */ 1820fca6ea1SDimitry Andric #define ptrauth_auth_function(__value, __old_key, __old_data) \ 1830fca6ea1SDimitry Andric ptrauth_auth_and_resign(__value, __old_key, __old_data, \ 1840fca6ea1SDimitry Andric ptrauth_key_function_pointer, 0) 1850fca6ea1SDimitry Andric 1860fca6ea1SDimitry Andric /* Authenticate a data pointer. 1870fca6ea1SDimitry Andric 1880fca6ea1SDimitry Andric The value must be an expression of non-function pointer type. 1890fca6ea1SDimitry Andric The key must be a constant expression of type ptrauth_key. 1900fca6ea1SDimitry Andric The extra data must be an expression of pointer or integer type; 1910fca6ea1SDimitry Andric if an integer, it will be coerced to ptrauth_extra_data_t. 1920fca6ea1SDimitry Andric The result will have the same type as the original value. 1930fca6ea1SDimitry Andric 1940fca6ea1SDimitry Andric This operation traps if the authentication fails. */ 1950fca6ea1SDimitry Andric #define ptrauth_auth_data(__value, __old_key, __old_data) \ 1960fca6ea1SDimitry Andric __builtin_ptrauth_auth(__value, __old_key, __old_data) 1970fca6ea1SDimitry Andric 1980fca6ea1SDimitry Andric /* Compute a constant discriminator from the given string. 1990fca6ea1SDimitry Andric 2000fca6ea1SDimitry Andric The argument must be a string literal of char character type. The result 2010fca6ea1SDimitry Andric has type ptrauth_extra_data_t. 2020fca6ea1SDimitry Andric 2030fca6ea1SDimitry Andric The result value is never zero and always within range for both the 2040fca6ea1SDimitry Andric __ptrauth qualifier and ptrauth_blend_discriminator. 2050fca6ea1SDimitry Andric 2060fca6ea1SDimitry Andric This can be used in constant expressions. 2070fca6ea1SDimitry Andric */ 2080fca6ea1SDimitry Andric #define ptrauth_string_discriminator(__string) \ 2090fca6ea1SDimitry Andric __builtin_ptrauth_string_discriminator(__string) 2100fca6ea1SDimitry Andric 21136b606aeSDimitry Andric /* Compute a constant discriminator from the given type. 21236b606aeSDimitry Andric 21336b606aeSDimitry Andric The result can be used as the second argument to 21436b606aeSDimitry Andric ptrauth_blend_discriminator or the third argument to the 21536b606aeSDimitry Andric __ptrauth qualifier. It has type size_t. 21636b606aeSDimitry Andric 21736b606aeSDimitry Andric If the type is a C++ member function pointer type, the result is 21836b606aeSDimitry Andric the discriminator used to signed member function pointers of that 21936b606aeSDimitry Andric type. If the type is a function, function pointer, or function 22036b606aeSDimitry Andric reference type, the result is the discriminator used to sign 22136b606aeSDimitry Andric functions of that type. It is ill-formed to use this macro with any 22236b606aeSDimitry Andric other type. 22336b606aeSDimitry Andric 22436b606aeSDimitry Andric A call to this function is an integer constant expression. */ 22536b606aeSDimitry Andric #define ptrauth_type_discriminator(__type) \ 22636b606aeSDimitry Andric __builtin_ptrauth_type_discriminator(__type) 22736b606aeSDimitry Andric 2280fca6ea1SDimitry Andric /* Compute a signature for the given pair of pointer-sized values. 2290fca6ea1SDimitry Andric The order of the arguments is significant. 2300fca6ea1SDimitry Andric 2310fca6ea1SDimitry Andric Like a pointer signature, the resulting signature depends on 2320fca6ea1SDimitry Andric private key data and therefore should not be reliably reproducible 2330fca6ea1SDimitry Andric by attackers. That means that this can be used to validate the 2340fca6ea1SDimitry Andric integrity of arbitrary data by storing a signature for that data 2350fca6ea1SDimitry Andric alongside it, then checking that the signature is still valid later. 2360fca6ea1SDimitry Andric Data which exceeds two pointers in size can be signed by either 2370fca6ea1SDimitry Andric computing a tree of generic signatures or just signing an ordinary 2380fca6ea1SDimitry Andric cryptographic hash of the data. 2390fca6ea1SDimitry Andric 2400fca6ea1SDimitry Andric The result has type ptrauth_generic_signature_t. However, it may 2410fca6ea1SDimitry Andric not have as many bits of entropy as that type's width would suggest; 2420fca6ea1SDimitry Andric some implementations are known to compute a compressed signature as 2430fca6ea1SDimitry Andric if the arguments were a pointer and a discriminator. 2440fca6ea1SDimitry Andric 2450fca6ea1SDimitry Andric The arguments must be either pointers or integers; if integers, they 2460fca6ea1SDimitry Andric will be coerce to uintptr_t. */ 2470fca6ea1SDimitry Andric #define ptrauth_sign_generic_data(__value, __data) \ 2480fca6ea1SDimitry Andric __builtin_ptrauth_sign_generic_data(__value, __data) 2490fca6ea1SDimitry Andric 2500fca6ea1SDimitry Andric /* C++ vtable pointer signing class attribute */ 2510fca6ea1SDimitry Andric #define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ 2520fca6ea1SDimitry Andric extra_discrimination...) \ 2530fca6ea1SDimitry Andric [[clang::ptrauth_vtable_pointer(key, address_discrimination, \ 2540fca6ea1SDimitry Andric extra_discrimination)]] 2550fca6ea1SDimitry Andric 2560fca6ea1SDimitry Andric #else 2570fca6ea1SDimitry Andric 2580fca6ea1SDimitry Andric #define ptrauth_strip(__value, __key) \ 2590fca6ea1SDimitry Andric ({ \ 2600fca6ea1SDimitry Andric (void)__key; \ 2610fca6ea1SDimitry Andric __value; \ 2620fca6ea1SDimitry Andric }) 2630fca6ea1SDimitry Andric 2640fca6ea1SDimitry Andric #define ptrauth_blend_discriminator(__pointer, __integer) \ 2650fca6ea1SDimitry Andric ({ \ 2660fca6ea1SDimitry Andric (void)__pointer; \ 2670fca6ea1SDimitry Andric (void)__integer; \ 2680fca6ea1SDimitry Andric ((ptrauth_extra_data_t)0); \ 2690fca6ea1SDimitry Andric }) 2700fca6ea1SDimitry Andric 2710fca6ea1SDimitry Andric #define ptrauth_sign_constant(__value, __key, __data) \ 2720fca6ea1SDimitry Andric ({ \ 2730fca6ea1SDimitry Andric (void)__key; \ 2740fca6ea1SDimitry Andric (void)__data; \ 2750fca6ea1SDimitry Andric __value; \ 2760fca6ea1SDimitry Andric }) 2770fca6ea1SDimitry Andric 2780fca6ea1SDimitry Andric #define ptrauth_sign_unauthenticated(__value, __key, __data) \ 2790fca6ea1SDimitry Andric ({ \ 2800fca6ea1SDimitry Andric (void)__key; \ 2810fca6ea1SDimitry Andric (void)__data; \ 2820fca6ea1SDimitry Andric __value; \ 2830fca6ea1SDimitry Andric }) 2840fca6ea1SDimitry Andric 2850fca6ea1SDimitry Andric #define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \ 2860fca6ea1SDimitry Andric __new_data) \ 2870fca6ea1SDimitry Andric ({ \ 2880fca6ea1SDimitry Andric (void)__old_key; \ 2890fca6ea1SDimitry Andric (void)__old_data; \ 2900fca6ea1SDimitry Andric (void)__new_key; \ 2910fca6ea1SDimitry Andric (void)__new_data; \ 2920fca6ea1SDimitry Andric __value; \ 2930fca6ea1SDimitry Andric }) 2940fca6ea1SDimitry Andric 2950fca6ea1SDimitry Andric #define ptrauth_auth_function(__value, __old_key, __old_data) \ 2960fca6ea1SDimitry Andric ({ \ 2970fca6ea1SDimitry Andric (void)__old_key; \ 2980fca6ea1SDimitry Andric (void)__old_data; \ 2990fca6ea1SDimitry Andric __value; \ 3000fca6ea1SDimitry Andric }) 3010fca6ea1SDimitry Andric 3020fca6ea1SDimitry Andric #define ptrauth_auth_data(__value, __old_key, __old_data) \ 3030fca6ea1SDimitry Andric ({ \ 3040fca6ea1SDimitry Andric (void)__old_key; \ 3050fca6ea1SDimitry Andric (void)__old_data; \ 3060fca6ea1SDimitry Andric __value; \ 3070fca6ea1SDimitry Andric }) 3080fca6ea1SDimitry Andric 3090fca6ea1SDimitry Andric #define ptrauth_string_discriminator(__string) \ 3100fca6ea1SDimitry Andric ({ \ 3110fca6ea1SDimitry Andric (void)__string; \ 3120fca6ea1SDimitry Andric ((ptrauth_extra_data_t)0); \ 3130fca6ea1SDimitry Andric }) 3140fca6ea1SDimitry Andric 31536b606aeSDimitry Andric #define ptrauth_type_discriminator(__type) ((ptrauth_extra_data_t)0) 31636b606aeSDimitry Andric 3170fca6ea1SDimitry Andric #define ptrauth_sign_generic_data(__value, __data) \ 3180fca6ea1SDimitry Andric ({ \ 3190fca6ea1SDimitry Andric (void)__value; \ 3200fca6ea1SDimitry Andric (void)__data; \ 3210fca6ea1SDimitry Andric ((ptrauth_generic_signature_t)0); \ 3220fca6ea1SDimitry Andric }) 3230fca6ea1SDimitry Andric 3240fca6ea1SDimitry Andric 3250fca6ea1SDimitry Andric #define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ 3260fca6ea1SDimitry Andric extra_discrimination...) 3270fca6ea1SDimitry Andric 3280fca6ea1SDimitry Andric #endif /* __has_feature(ptrauth_intrinsics) */ 3290fca6ea1SDimitry Andric 3300fca6ea1SDimitry Andric #endif /* __PTRAUTH_H */ 331