zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

ptrauth.h (15989B) - Raw


      1 /*===---- ptrauth.h - Pointer authentication -------------------------------===
      2  *
      3  * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  * See https://llvm.org/LICENSE.txt for license information.
      5  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  *
      7  *===-----------------------------------------------------------------------===
      8  */
      9 
     10 #ifndef __PTRAUTH_H
     11 #define __PTRAUTH_H
     12 
     13 typedef enum {
     14   ptrauth_key_asia = 0,
     15   ptrauth_key_asib = 1,
     16   ptrauth_key_asda = 2,
     17   ptrauth_key_asdb = 3,
     18 
     19   /* A process-independent key which can be used to sign code pointers. */
     20   ptrauth_key_process_independent_code = ptrauth_key_asia,
     21 
     22   /* A process-specific key which can be used to sign code pointers. */
     23   ptrauth_key_process_dependent_code = ptrauth_key_asib,
     24 
     25   /* A process-independent key which can be used to sign data pointers. */
     26   ptrauth_key_process_independent_data = ptrauth_key_asda,
     27 
     28   /* A process-specific key which can be used to sign data pointers. */
     29   ptrauth_key_process_dependent_data = ptrauth_key_asdb,
     30 
     31   /* The key used to sign return addresses on the stack.
     32      The extra data is based on the storage address of the return address.
     33      On AArch64, that is always the storage address of the return address + 8
     34      (or, in other words, the value of the stack pointer on function entry) */
     35   ptrauth_key_return_address = ptrauth_key_process_dependent_code,
     36 
     37   /* The key used to sign C function pointers.
     38      The extra data is always 0. */
     39   ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
     40 
     41   /* The key used to sign C++ v-table pointers.
     42      The extra data is always 0. */
     43   ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data,
     44 
     45   /* The key used to sign pointers in ELF .init_array/.fini_array. */
     46   ptrauth_key_init_fini_pointer = ptrauth_key_process_independent_code,
     47 
     48   /* Other pointers signed under the ABI use private ABI rules. */
     49 
     50 } ptrauth_key;
     51 
     52 /* An integer type of the appropriate size for a discriminator argument. */
     53 typedef __UINTPTR_TYPE__ ptrauth_extra_data_t;
     54 
     55 /* An integer type of the appropriate size for a generic signature. */
     56 typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
     57 
     58 /* A signed pointer value embeds the original pointer together with
     59    a signature that attests to the validity of that pointer.  Because
     60    this signature must use only "spare" bits of the pointer, a
     61    signature's validity is probabilistic in practice: it is unlikely
     62    but still plausible that an invalidly-derived signature will
     63    somehow equal the correct signature and therefore successfully
     64    authenticate.  Nonetheless, this scheme provides a strong degree
     65    of protection against certain kinds of attacks. */
     66 
     67 /* Authenticating a pointer that was not signed with the given key
     68    and extra-data value will (likely) fail by trapping. */
     69 
     70 /* The null function pointer is always the all-zero bit pattern.
     71    Signing an all-zero bit pattern will embed a (likely) non-zero
     72    signature in the result, and so the result will not seem to be
     73    a null function pointer.  Authenticating this value will yield
     74    a null function pointer back.  However, authenticating an
     75    all-zero bit pattern will probably fail, because the
     76    authentication will expect a (likely) non-zero signature to
     77    embedded in the value.
     78 
     79    Because of this, if a pointer may validly be null, you should
     80    check for null before attempting to authenticate it with one
     81    of these intrinsics.  This is not necessary when using the
     82    __ptrauth qualifier; the compiler will perform this check
     83    automatically. */
     84 
     85 #if __has_feature(ptrauth_intrinsics)
     86 
     87 /* Strip the signature from a value without authenticating it.
     88 
     89    If the value is a function pointer, the result will not be a
     90    legal function pointer because of the missing signature, and
     91    attempting to call it will result in an authentication failure.
     92 
     93    The value must be an expression of pointer type.
     94    The key must be a constant expression of type ptrauth_key.
     95    The result will have the same type as the original value. */
     96 #define ptrauth_strip(__value, __key) __builtin_ptrauth_strip(__value, __key)
     97 
     98 /* Blend a constant discriminator into the given pointer-like value
     99    to form a new discriminator.  Not all bits of the inputs are
    100    guaranteed to contribute to the result.
    101 
    102    On arm64e, the integer must fall within the range of a uint16_t;
    103    other bits may be ignored.
    104 
    105    For the purposes of ptrauth_sign_constant, the result of calling
    106    this function is considered a constant expression if the arguments
    107    are constant.  Some restrictions may be imposed on the pointer.
    108 
    109    The first argument must be an expression of pointer type.
    110    The second argument must be an expression of integer type.
    111    The result will have type uintptr_t. */
    112 #define ptrauth_blend_discriminator(__pointer, __integer)                      \
    113   __builtin_ptrauth_blend_discriminator(__pointer, __integer)
    114 
    115 /* Return a signed pointer for a constant address in a manner which guarantees
    116    a non-attackable sequence.
    117 
    118    The value must be a constant expression of pointer type which evaluates to
    119    a non-null pointer.
    120    The key must be a constant expression of type ptrauth_key.
    121    The extra data must be a constant expression of pointer or integer type;
    122    if an integer, it will be coerced to ptrauth_extra_data_t.
    123    The result will have the same type as the original value.
    124 
    125    This can be used in constant expressions.  */
    126 #define ptrauth_sign_constant(__value, __key, __data)                          \
    127   __builtin_ptrauth_sign_constant(__value, __key, __data)
    128 
    129 /* Add a signature to the given pointer value using a specific key,
    130    using the given extra data as a salt to the signing process.
    131 
    132    This operation does not authenticate the original value and is
    133    therefore potentially insecure if an attacker could possibly
    134    control that value.
    135 
    136    The value must be an expression of pointer type.
    137    The key must be a constant expression of type ptrauth_key.
    138    The extra data must be an expression of pointer or integer type;
    139    if an integer, it will be coerced to ptrauth_extra_data_t.
    140    The result will have the same type as the original value. */
    141 #define ptrauth_sign_unauthenticated(__value, __key, __data)                   \
    142   __builtin_ptrauth_sign_unauthenticated(__value, __key, __data)
    143 
    144 /* Authenticate a pointer using one scheme and resign it using another.
    145 
    146    If the result is subsequently authenticated using the new scheme, that
    147    authentication is guaranteed to fail if and only if the initial
    148    authentication failed.
    149 
    150    The value must be an expression of pointer type.
    151    The key must be a constant expression of type ptrauth_key.
    152    The extra data must be an expression of pointer or integer type;
    153    if an integer, it will be coerced to ptrauth_extra_data_t.
    154    The result will have the same type as the original value.
    155 
    156    This operation is guaranteed to not leave the intermediate value
    157    available for attack before it is re-signed.
    158 
    159    Do not pass a null pointer to this function. A null pointer
    160    will not successfully authenticate.
    161 
    162    This operation traps if the authentication fails. */
    163 #define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key,     \
    164                                 __new_data)                                    \
    165   __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
    166                                     __new_data)
    167 
    168 /* Authenticate a pointer using one scheme and resign it as a C
    169    function pointer.
    170 
    171    If the result is subsequently authenticated using the new scheme, that
    172    authentication is guaranteed to fail if and only if the initial
    173    authentication failed.
    174 
    175    The value must be an expression of function pointer type.
    176    The key must be a constant expression of type ptrauth_key.
    177    The extra data must be an expression of pointer or integer type;
    178    if an integer, it will be coerced to ptrauth_extra_data_t.
    179    The result will have the same type as the original value.
    180 
    181    This operation is guaranteed to not leave the intermediate value
    182    available for attack before it is re-signed. Additionally, if this
    183    expression is used syntactically as the function expression in a
    184    call, only a single authentication will be performed. */
    185 #define ptrauth_auth_function(__value, __old_key, __old_data)                  \
    186   ptrauth_auth_and_resign(__value, __old_key, __old_data,                      \
    187                           ptrauth_key_function_pointer, 0)
    188 
    189 /* Authenticate a data pointer.
    190 
    191    The value must be an expression of non-function pointer type.
    192    The key must be a constant expression of type ptrauth_key.
    193    The extra data must be an expression of pointer or integer type;
    194    if an integer, it will be coerced to ptrauth_extra_data_t.
    195    The result will have the same type as the original value.
    196 
    197    This operation traps if the authentication fails. */
    198 #define ptrauth_auth_data(__value, __old_key, __old_data)                      \
    199   __builtin_ptrauth_auth(__value, __old_key, __old_data)
    200 
    201 /* Compute a constant discriminator from the given string.
    202 
    203    The argument must be a string literal of char character type.  The result
    204    has type ptrauth_extra_data_t.
    205 
    206    The result value is never zero and always within range for both the
    207    __ptrauth qualifier and ptrauth_blend_discriminator.
    208 
    209    This can be used in constant expressions.
    210 */
    211 #define ptrauth_string_discriminator(__string)                                 \
    212   __builtin_ptrauth_string_discriminator(__string)
    213 
    214 /* Compute a constant discriminator from the given type.
    215 
    216    The result can be used as the second argument to
    217    ptrauth_blend_discriminator or the third argument to the
    218    __ptrauth qualifier.  It has type size_t.
    219 
    220    If the type is a C++ member function pointer type, the result is
    221    the discriminator used to signed member function pointers of that
    222    type.  If the type is a function, function pointer, or function
    223    reference type, the result is the discriminator used to sign
    224    functions of that type.  It is ill-formed to use this macro with any
    225    other type.
    226 
    227    A call to this function is an integer constant expression. */
    228 #define ptrauth_type_discriminator(__type)                                     \
    229   __builtin_ptrauth_type_discriminator(__type)
    230 
    231 /* Compute a signature for the given pair of pointer-sized values.
    232    The order of the arguments is significant.
    233 
    234    Like a pointer signature, the resulting signature depends on
    235    private key data and therefore should not be reliably reproducible
    236    by attackers.  That means that this can be used to validate the
    237    integrity of arbitrary data by storing a signature for that data
    238    alongside it, then checking that the signature is still valid later.
    239    Data which exceeds two pointers in size can be signed by either
    240    computing a tree of generic signatures or just signing an ordinary
    241    cryptographic hash of the data.
    242 
    243    The result has type ptrauth_generic_signature_t.  However, it may
    244    not have as many bits of entropy as that type's width would suggest;
    245    some implementations are known to compute a compressed signature as
    246    if the arguments were a pointer and a discriminator.
    247 
    248    The arguments must be either pointers or integers; if integers, they
    249    will be coerce to uintptr_t. */
    250 #define ptrauth_sign_generic_data(__value, __data)                             \
    251   __builtin_ptrauth_sign_generic_data(__value, __data)
    252 
    253 /* C++ vtable pointer signing class attribute */
    254 #define ptrauth_cxx_vtable_pointer(key, address_discrimination,                \
    255                                    extra_discrimination...)                    \
    256   [[clang::ptrauth_vtable_pointer(key, address_discrimination,                 \
    257                                   extra_discrimination)]]
    258 
    259 /* The value is ptrauth_string_discriminator("init_fini") */
    260 #define __ptrauth_init_fini_discriminator 0xd9d4
    261 
    262 #else
    263 
    264 #define ptrauth_strip(__value, __key)                                          \
    265   ({                                                                           \
    266     (void)__key;                                                               \
    267     __value;                                                                   \
    268   })
    269 
    270 #define ptrauth_blend_discriminator(__pointer, __integer)                      \
    271   ({                                                                           \
    272     (void)__pointer;                                                           \
    273     (void)__integer;                                                           \
    274     ((ptrauth_extra_data_t)0);                                                 \
    275   })
    276 
    277 #define ptrauth_sign_constant(__value, __key, __data)                          \
    278   ({                                                                           \
    279     (void)__key;                                                               \
    280     (void)__data;                                                              \
    281     __value;                                                                   \
    282   })
    283 
    284 #define ptrauth_sign_unauthenticated(__value, __key, __data)                   \
    285   ({                                                                           \
    286     (void)__key;                                                               \
    287     (void)__data;                                                              \
    288     __value;                                                                   \
    289   })
    290 
    291 #define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key,     \
    292                                 __new_data)                                    \
    293   ({                                                                           \
    294     (void)__old_key;                                                           \
    295     (void)__old_data;                                                          \
    296     (void)__new_key;                                                           \
    297     (void)__new_data;                                                          \
    298     __value;                                                                   \
    299   })
    300 
    301 #define ptrauth_auth_function(__value, __old_key, __old_data)                  \
    302   ({                                                                           \
    303     (void)__old_key;                                                           \
    304     (void)__old_data;                                                          \
    305     __value;                                                                   \
    306   })
    307 
    308 #define ptrauth_auth_data(__value, __old_key, __old_data)                      \
    309   ({                                                                           \
    310     (void)__old_key;                                                           \
    311     (void)__old_data;                                                          \
    312     __value;                                                                   \
    313   })
    314 
    315 #define ptrauth_string_discriminator(__string)                                 \
    316   ({                                                                           \
    317     (void)__string;                                                            \
    318     ((ptrauth_extra_data_t)0);                                                 \
    319   })
    320 
    321 #define ptrauth_type_discriminator(__type) ((ptrauth_extra_data_t)0)
    322 
    323 #define ptrauth_sign_generic_data(__value, __data)                             \
    324   ({                                                                           \
    325     (void)__value;                                                             \
    326     (void)__data;                                                              \
    327     ((ptrauth_generic_signature_t)0);                                          \
    328   })
    329 
    330 
    331 #define ptrauth_cxx_vtable_pointer(key, address_discrimination,                \
    332                                    extra_discrimination...)
    333 
    334 #endif /* __has_feature(ptrauth_intrinsics) */
    335 
    336 #endif /* __PTRAUTH_H */