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