xref: /xnu-11215.41.3/EXTERNAL_HEADERS/ptrauth.h (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*===---- ptrauth.h - Pointer authentication -------------------------------===
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  *
21  *===-----------------------------------------------------------------------===
22  */
23 
24 #ifndef __PTRAUTH_H
25 #define __PTRAUTH_H
26 
27 #include <stdint.h>
28 
29 typedef enum {
30   ptrauth_key_asia = 0,
31   ptrauth_key_asib = 1,
32   ptrauth_key_asda = 2,
33   ptrauth_key_asdb = 3,
34 
35   /* A process-independent key which can be used to sign code pointers.
36      Signing and authenticating with this key is a no-op in processes
37      which disable ABI pointer authentication. */
38   ptrauth_key_process_independent_code = ptrauth_key_asia,
39 
40   /* A process-specific key which can be used to sign code pointers.
41      Signing and authenticating with this key is enforced even in processes
42      which disable ABI pointer authentication. */
43   ptrauth_key_process_dependent_code = ptrauth_key_asib,
44 
45   /* A process-independent key which can be used to sign data pointers.
46      Signing and authenticating with this key is a no-op in processes
47      which disable ABI pointer authentication. */
48   ptrauth_key_process_independent_data = ptrauth_key_asda,
49 
50   /* A process-specific key which can be used to sign data pointers.
51      Signing and authenticating with this key is a no-op in processes
52      which disable ABI pointer authentication. */
53   ptrauth_key_process_dependent_data = ptrauth_key_asdb,
54 
55   /* The key used to sign C function pointers.
56      The extra data is always 0. */
57   ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
58 
59   /* The key used to sign return addresses on the stack.
60      The extra data is based on the storage address of the return address.
61      On ARM64, that is always the storage address of the return address plus 8
62      (or, in other words, the value of the stack pointer on function entry) */
63   ptrauth_key_return_address = ptrauth_key_process_dependent_code,
64 
65   /* The key used to sign frame pointers on the stack.
66      The extra data is based on the storage address of the frame pointer.
67      On ARM64, that is always the storage address of the frame pointer plus 16
68      (or, in other words, the value of the stack pointer on function entry) */
69   ptrauth_key_frame_pointer = ptrauth_key_process_dependent_data,
70 
71   /* The key used to sign block function pointers, including:
72        invocation functions,
73        block object copy functions,
74        block object destroy functions,
75        __block variable copy functions, and
76        __block variable destroy functions.
77      The extra data is always the address at which the function pointer
78      is stored.
79 
80      Note that block object pointers themselves (i.e. the direct
81      representations of values of block-pointer type) are not signed. */
82   ptrauth_key_block_function = ptrauth_key_asia,
83 
84   /* The key used to sign C++ v-table pointers.
85      The extra data is always 0. */
86   ptrauth_key_cxx_vtable_pointer = ptrauth_key_asda,
87 
88   /* Other pointers signed under the ABI use private ABI rules. */
89 
90 } ptrauth_key;
91 
92 /* An integer type of the appropriate size for an extra-data argument. */
93 typedef uintptr_t ptrauth_extra_data_t;
94 
95 /* An integer type of the appropriate size for a generic signature. */
96 typedef uintptr_t ptrauth_generic_signature_t;
97 
98 /* A signed pointer value embeds the original pointer together with
99    a signature that attests to the validity of that pointer.  Because
100    this signature must use only "spare" bits of the pointer, a
101    signature's validity is probabilistic in practice: it is unlikely
102    but still plausible that an invalidly-derived signature will
103    somehow equal the correct signature and therefore successfully
104    authenticate.  Nonetheless, this scheme provides a strong degree
105    of protection against certain kinds of attacks. */
106 
107 /* Authenticating a pointer that was not signed with the given key
108    and extra-data value will (likely) fail.  However, an
109    authentication failure will not lead immediately to a trap.
110    Instead, it will yield a value which is guaranteed to trap
111    if actually dereferenced. */
112 
113 /* The null function pointer is always the all-zero bit pattern.
114    Signing an all-zero bit pattern will embed a (likely) non-zero
115    signature in the result, and so the result will not seem to be
116    a null function pointer.  Authenticating this value will yield
117    a null function pointer back.  However, authenticating an
118    all-zero bit pattern will probably fail, because the
119    authentication will expect a (likely) non-zero signature to
120    embedded in the value.
121 
122    Because of this, if a pointer may validly be null, you should
123    check for null before attempting to authenticate it. */
124 
125 #ifdef __PTRAUTH_INTRINSICS__
126 
127 /* Strip the signature from a value without authenticating it.
128 
129    If the value is a function pointer, the result will not be a
130    legal function pointer because of the missing signature, and
131    attempting to call it will result in an authentication failure.
132 
133    The value must be an expression of pointer type.
134    The key must be a constant expression of type ptrauth_key.
135    The result will have the same type as the original value. */
136 #define ptrauth_strip(__value, __key) \
137   __builtin_ptrauth_strip(__value, __key)
138 
139 /* Blend a pointer and a small integer to form a new extra-data
140    discriminator.  Not all bits of the inputs are guaranteed to
141    contribute to the result.
142 
143    On ARM64, only the low 16 bits of the integer will be considered.
144 
145    For the purposes of ptrauth_sign_constant, the result of calling
146    this function is considered a constant expression if the arguments
147    are constant.  Some restrictions may be imposed on the pointer.
148 
149    The first argument must be an expression of pointer type.
150    The second argument must be an expression of integer type.
151    The result will have type uintptr_t. */
152 #define ptrauth_blend_discriminator(__pointer, __integer) \
153   __builtin_ptrauth_blend_discriminator(__pointer, __integer)
154 
155 /* Compute the 16-bit integer discriminator of the given type.
156 
157    The argument must be a type.
158 */
159 #if __has_builtin(__builtin_ptrauth_type_discriminator)
160 #define ptrauth_type_discriminator(__type) \
161   __builtin_ptrauth_type_discriminator(__type)
162 #else
163 #define ptrauth_type_discriminator(__type) ((uintptr_t)0)
164 #endif
165 
166 /* Compute the constant discriminator used by Clang to sign pointers with the
167    given C function pointer type.
168 
169    A call to this function is an integer constant expression*/
170 #if __has_feature(ptrauth_function_pointer_type_discrimination)
171 #define ptrauth_function_pointer_type_discriminator(__type) \
172   __builtin_ptrauth_type_discriminator(__type)
173 #else
174 #define ptrauth_function_pointer_type_discriminator(__type) ((uintptr_t)0)
175 #endif
176 
177 /* Add a signature to the given pointer value using a specific key,
178    using the given extra data as a salt to the signing process.
179 
180    The value must be a constant expression of pointer type.
181    The key must be a constant expression of type ptrauth_key.
182    The extra data must be a constant expression of pointer or integer type;
183    if an integer, it will be coerced to ptrauth_extra_data_t.
184    The result will have the same type as the original value.
185 
186    This is a constant expression if the extra data is an integer or
187    null pointer constant. */
188 #define ptrauth_sign_constant(__value, __key, __data) \
189   __builtin_ptrauth_sign_constant(__value, __key, __data)
190 
191 /* Add a signature to the given pointer value using a specific key,
192    using the given extra data as a salt to the signing process.
193 
194    This operation does not authenticate the original value and is
195    therefore potentially insecure if an attacker could possibly
196    control that value.
197 
198    The value must be an expression of pointer type.
199    The key must be a constant expression of type ptrauth_key.
200    The extra data must be an expression of pointer or integer type;
201    if an integer, it will be coerced to ptrauth_extra_data_t.
202    The result will have the same type as the original value. */
203 #define ptrauth_sign_unauthenticated(__value, __key, __data) \
204   __builtin_ptrauth_sign_unauthenticated(__value, __key, __data)
205 
206 /* Authenticate a pointer using one scheme and resign it using another.
207 
208    If the result is subsequently authenticated using the new scheme, that
209    authentication is guaranteed to fail if and only if the initial
210    authentication failed.
211 
212    The value must be an expression of pointer type.
213    The key must be a constant expression of type ptrauth_key.
214    The extra data must be an expression of pointer or integer type;
215    if an integer, it will be coerced to ptrauth_extra_data_t.
216    The result will have the same type as the original value.
217 
218    This operation is guaranteed to not leave the intermediate value
219    available for attack before it is re-signed.
220 
221    Do not pass a null pointer to this function. A null pointer
222    will not successfully authenticate. */
223 #define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) \
224   __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data)
225 
226 /* Authenticate a pointer using one scheme and resign it as a C
227    function pointer.
228 
229    If the result is subsequently authenticated using the new scheme, that
230    authentication is guaranteed to fail if and only if the initial
231    authentication failed.
232 
233    The value must be an expression of function pointer type.
234    The key must be a constant expression of type ptrauth_key.
235    The extra data must be an expression of pointer or integer type;
236    if an integer, it will be coerced to ptrauth_extra_data_t.
237    The result will have the same type as the original value.
238 
239    This operation is guaranteed to not leave the intermediate value
240    available for attack before it is re-signed. Additionally, if this
241    expression is used syntactically as the function expression in a
242    call, only a single authentication will be performed. */
243 #define ptrauth_auth_function(__value, __old_key, __old_data) \
244   ptrauth_auth_and_resign(__value, __old_key, __old_data, ptrauth_key_function_pointer, 0)
245 
246 /* Cast a pointer to the given type without changing any signature.
247 
248    The type must have the same size as a pointer type.
249    The type of value must have the same size as a pointer type, and will be
250    converted to an rvalue prior to the cast.
251    The result has type given by the first argument.
252 
253    The result has an identical bit-pattern to the input pointer. */
254 #define ptrauth_nop_cast(__type, __value)        \
255   ({ union {                                     \
256       typeof(__value) __fptr;                    \
257       typeof(__type) __opaque;                   \
258   } __storage;                                   \
259   __storage.__fptr = (__value);                  \
260   __storage.__opaque; })
261 
262 /* Authenticate a data pointer.
263 
264    The value must be an expression of non-function pointer type.
265    The key must be a constant expression of type ptrauth_key.
266    The extra data must be an expression of pointer or integer type;
267    if an integer, it will be coerced to ptrauth_extra_data_t.
268    The result will have the same type as the original value.
269 
270    If the authentication fails, dereferencing the resulting pointer
271    will fail. */
272 #define ptrauth_auth_data(__value, __old_key, __old_data) \
273   __builtin_ptrauth_auth(__value, __old_key, __old_data)
274 
275 /* Return an extra-discriminator value which can validly be used
276    as the second argument to ptrauth_blend_discriminator or the
277    third argument to the __ptrauth qualifier.
278 
279    The argument must be a string literal.
280    A call to this function is an integer constant expression. */
281 #define ptrauth_string_discriminator(__string) \
282   __builtin_ptrauth_string_discriminator(__string)
283 
284 /* Compute a full pointer-width generic signature for the given
285    value, using the given data as a salt.
286 
287    This generic signature is process-independent, but may not be
288    consistent across reboots.
289 
290    This can be used to validate the integrity of arbitrary data
291    by storing a signature for that data together with it.  Because
292    the signature is pointer-sized, if the stored signature matches
293    the result of re-signing the current data, a match provides very
294    strong evidence that the data has not been corrupted.
295 
296    The value must be an expression of pointer or integer type; if
297    an integer, it will be coerced to uintptr_t.
298    The extra data must be an expression of pointer or integer type;
299    if an integer, it will be coerced to ptrauth_extra_data_t.
300    The result will have type ptrauth_generic_signature_t.
301 
302    This operation will compute a meaningful signature even in processes
303    which disable ABI pointer authentication. */
304 #define ptrauth_sign_generic_data(__value, __data) \
305   __builtin_ptrauth_sign_generic_data(__value, __data)
306 
307 
308 /* Define some standard __ptrauth qualifiers used in the ABI. */
309 #define __ptrauth_function_pointer            \
310   __ptrauth(ptrauth_key_function_pointer,0,0)
311 #define __ptrauth_return_address              \
312   __ptrauth(ptrauth_key_return_address,1,0)
313 #define __ptrauth_block_invocation_pointer    \
314   __ptrauth(ptrauth_key_function_pointer,1,0)
315 #define __ptrauth_block_copy_helper           \
316   __ptrauth(ptrauth_key_function_pointer,1,0)
317 #define __ptrauth_block_destroy_helper        \
318   __ptrauth(ptrauth_key_function_pointer,1,0)
319 #define __ptrauth_block_byref_copy_helper     \
320   __ptrauth(ptrauth_key_function_pointer,1,0)
321 #define __ptrauth_block_byref_destroy_helper  \
322   __ptrauth(ptrauth_key_function_pointer,1,0)
323 #define __ptrauth_objc_method_list_imp        \
324   __ptrauth(ptrauth_key_function_pointer,1,0)
325 #define __ptrauth_cxx_vtable_pointer          \
326   __ptrauth(ptrauth_key_cxx_vtable_pointer,0,0)
327 #define __ptrauth_cxx_vtt_vtable_pointer      \
328   __ptrauth(ptrauth_key_cxx_vtable_pointer,0,0)
329 #define __ptrauth_swift_heap_object_destructor \
330   __ptrauth(ptrauth_key_function_pointer,1,0xbbbf)
331 
332 /* Some situations in the C++ and Swift ABIs use declaration-specific
333    or type-specific extra discriminators. */
334 #define __ptrauth_cxx_virtual_function_pointer(__declkey) \
335   __ptrauth(ptrauth_key_function_pointer,1,__declkey)
336 #define __ptrauth_swift_function_pointer(__typekey) \
337   __ptrauth(ptrauth_key_function_pointer,0,__typekey)
338 #define __ptrauth_swift_class_method_pointer(__declkey) \
339   __ptrauth(ptrauth_key_function_pointer,1,__declkey)
340 #define __ptrauth_swift_protocol_witness_function_pointer(__declkey) \
341   __ptrauth(ptrauth_key_function_pointer,1,__declkey)
342 #define __ptrauth_swift_value_witness_function_pointer(__key) \
343   __ptrauth(ptrauth_key_function_pointer,1,__key)
344 
345 #else
346 
347 #define ptrauth_strip(__value, __key) ({ (void)__key; __value; })
348 #define ptrauth_blend_discriminator(__pointer, __integer) ({ (void)__pointer; (void)__integer; (uintptr_t)0; })
349 #define ptrauth_type_discriminator(__type) ((uintptr_t)0)
350 #define ptrauth_function_pointer_type_discriminator(__type) ((uintptr_t)0)
351 #define ptrauth_sign_constant(__value, __key, __data) ({ (void)__key; (void)__data; __value; })
352 #define ptrauth_sign_unauthenticated(__value, __key, __data) ({ (void)__key; (void)__data; __value; })
353 #define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) ({ \
354       (void)__old_key; \
355       (void)__old_data; \
356       (void)__new_key; \
357       (void)__new_data; \
358       __value; })
359 #define ptrauth_auth_function(__value, __old_key, __old_data) ({ (void)__old_key; (void)__old_data; __value; })
360 #define ptrauth_nop_cast(__type, __value) ((__type)__value)
361 #define ptrauth_auth_data(__value, __old_key, __old_data) ({ (void)__old_key; (void)__old_data; __value; })
362 #define ptrauth_string_discriminator(__string) ({ (void)__string; (int)0; })
363 #define ptrauth_sign_generic_data(__value, __data) ({ (void)__value; (void)__data; (ptrauth_generic_signature_t)0; })
364 
365 #define __ptrauth_function_pointer
366 #define __ptrauth_return_address
367 #define __ptrauth_block_invocation_pointer
368 #define __ptrauth_block_copy_helper
369 #define __ptrauth_block_destroy_helper
370 #define __ptrauth_block_byref_copy_helper
371 #define __ptrauth_block_byref_destroy_helper
372 #define __ptrauth_objc_method_list_imp
373 #define __ptrauth_cxx_vtable_pointer
374 #define __ptrauth_cxx_vtt_vtable_pointer
375 #define __ptrauth_swift_heap_object_destructor
376 #define __ptrauth_cxx_virtual_function_pointer(__declkey)
377 #define __ptrauth_swift_function_pointer(__typekey)
378 #define __ptrauth_swift_class_method_pointer(__declkey)
379 #define __ptrauth_swift_protocol_witness_function_pointer(__declkey)
380 #define __ptrauth_swift_value_witness_function_pointer(__key)
381 
382 #endif /* __PTRAUTH_INTRINSICS__ */
383 
384 #endif /* __PTRAUTH_H */
385