]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-ptrauth.h
objc4-818.2.tar.gz
[apple/objc4.git] / runtime / objc-ptrauth.h
CommitLineData
66799735
A
1/*
2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#ifndef _OBJC_PTRAUTH_H_
25#define _OBJC_PTRAUTH_H_
26
27#include <objc/objc.h>
28
29// On some architectures, method lists and method caches store signed IMPs.
30
66799735
A
31// fixme simply include ptrauth.h once all build trains have it
32#if __has_include (<ptrauth.h>)
33#include <ptrauth.h>
34#else
35#define ptrauth_strip(__value, __key) __value
36#define ptrauth_blend_discriminator(__pointer, __integer) ((uintptr_t)0)
37#define ptrauth_sign_constant(__value, __key, __data) __value
38#define ptrauth_sign_unauthenticated(__value, __key, __data) __value
39#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) __value
40#define ptrauth_auth_function(__value, __old_key, __old_data) __value
41#define ptrauth_auth_data(__value, __old_key, __old_data) __value
42#define ptrauth_string_discriminator(__string) ((int)0)
43#define ptrauth_sign_generic_data(__value, __data) ((ptrauth_generic_signature_t)0)
44
45#define __ptrauth_function_pointer
46#define __ptrauth_return_address
47#define __ptrauth_block_invocation_pointer
48#define __ptrauth_block_copy_helper
49#define __ptrauth_block_destroy_helper
50#define __ptrauth_block_byref_copy_helper
51#define __ptrauth_block_byref_destroy_helper
52#define __ptrauth_objc_method_list_imp
53#define __ptrauth_cxx_vtable_pointer
54#define __ptrauth_cxx_vtt_vtable_pointer
55#define __ptrauth_swift_heap_object_destructor
56#define __ptrauth_cxx_virtual_function_pointer(__declkey)
57#define __ptrauth_swift_function_pointer(__typekey)
58#define __ptrauth_swift_class_method_pointer(__declkey)
59#define __ptrauth_swift_protocol_witness_function_pointer(__declkey)
60#define __ptrauth_swift_value_witness_function_pointer(__key)
61#endif
62
34d5b5e8
A
63// Workaround <rdar://problem/64531063> Definitions of ptrauth_sign_unauthenticated and friends generate unused variables warnings
64#if __has_feature(ptrauth_calls)
65#define UNUSED_WITHOUT_PTRAUTH
66#else
67#define UNUSED_WITHOUT_PTRAUTH __unused
68#endif
66799735
A
69
70#if __has_feature(ptrauth_calls)
71
13ba007e
A
72#if !__arm64__
73#error ptrauth other than arm64e is unimplemented
74#endif
75
66799735 76// Method lists use process-independent signature for compatibility.
66799735 77using MethodListIMP = IMP __ptrauth_objc_method_list_imp;
66799735
A
78
79#else
80
81using MethodListIMP = IMP;
66799735
A
82
83#endif
84
bc4fafce
A
85// A struct that wraps a pointer using the provided template.
86// The provided Auth parameter is used to sign and authenticate
87// the pointer as it is read and written.
88template<typename T, typename Auth>
89struct WrappedPtr {
90private:
91 T *ptr;
92
93public:
94 WrappedPtr(T *p) {
95 *this = p;
96 }
97
98 WrappedPtr(const WrappedPtr<T, Auth> &p) {
99 *this = p;
100 }
101
102 WrappedPtr<T, Auth> &operator =(T *p) {
103 ptr = Auth::sign(p, &ptr);
104 return *this;
105 }
106
107 WrappedPtr<T, Auth> &operator =(const WrappedPtr<T, Auth> &p) {
108 *this = (T *)p;
109 return *this;
110 }
111
112 operator T*() const { return get(); }
113 T *operator->() const { return get(); }
114
115 T *get() const { return Auth::auth(ptr, &ptr); }
116
117 // When asserts are enabled, ensure that we can read a byte from
118 // the underlying pointer. This can be used to catch ptrauth
119 // errors early for easier debugging.
120 void validate() const {
121#if !NDEBUG
122 char *p = (char *)get();
123 char dummy;
124 memset_s(&dummy, 1, *p, 1);
125 ASSERT(dummy == *p);
126#endif
127 }
128};
129
130// A "ptrauth" struct that just passes pointers through unchanged.
131struct PtrauthRaw {
132 template <typename T>
34d5b5e8 133 static T *sign(T *ptr, __unused const void *address) {
bc4fafce
A
134 return ptr;
135 }
136
137 template <typename T>
34d5b5e8 138 static T *auth(T *ptr, __unused const void *address) {
bc4fafce
A
139 return ptr;
140 }
141};
142
143// A ptrauth struct that stores pointers raw, and strips ptrauth
144// when reading.
145struct PtrauthStrip {
146 template <typename T>
34d5b5e8 147 static T *sign(T *ptr, __unused const void *address) {
bc4fafce
A
148 return ptr;
149 }
150
151 template <typename T>
34d5b5e8 152 static T *auth(T *ptr, __unused const void *address) {
bc4fafce
A
153 return ptrauth_strip(ptr, ptrauth_key_process_dependent_data);
154 }
155};
156
157// A ptrauth struct that signs and authenticates pointers using the
158// DB key with the given discriminator and address diversification.
159template <unsigned discriminator>
160struct Ptrauth {
161 template <typename T>
34d5b5e8 162 static T *sign(T *ptr, UNUSED_WITHOUT_PTRAUTH const void *address) {
bc4fafce
A
163 if (!ptr)
164 return nullptr;
165 return ptrauth_sign_unauthenticated(ptr, ptrauth_key_process_dependent_data, ptrauth_blend_discriminator(address, discriminator));
166 }
167
168 template <typename T>
34d5b5e8 169 static T *auth(T *ptr, UNUSED_WITHOUT_PTRAUTH const void *address) {
bc4fafce
A
170 if (!ptr)
171 return nullptr;
172 return ptrauth_auth_data(ptr, ptrauth_key_process_dependent_data, ptrauth_blend_discriminator(address, discriminator));
173 }
174};
175
176// A template that produces a WrappedPtr to the given type using a
177// plain unauthenticated pointer.
178template <typename T> using RawPtr = WrappedPtr<T, PtrauthRaw>;
179
180#if __has_feature(ptrauth_calls)
181// Get a ptrauth type that uses a string discriminator.
34d5b5e8
A
182#if __BUILDING_OBJCDT__
183#define PTRAUTH_STR(name) PtrauthStrip
184#else
bc4fafce 185#define PTRAUTH_STR(name) Ptrauth<ptrauth_string_discriminator(#name)>
34d5b5e8 186#endif
bc4fafce
A
187
188// When ptrauth is available, declare a template that wraps a type
189// in a WrappedPtr that uses an authenticated pointer using the
190// process-dependent data key, address diversification, and a
191// discriminator based on the name passed in.
192//
193// When ptrauth is not available, equivalent to RawPtr.
194#define DECLARE_AUTHED_PTR_TEMPLATE(name) \
195 template <typename T> using name ## _authed_ptr \
196 = WrappedPtr<T, PTRAUTH_STR(name)>;
197#else
198#define PTRAUTH_STR(name) PtrauthRaw
199#define DECLARE_AUTHED_PTR_TEMPLATE(name) \
200 template <typename T> using name ## _authed_ptr = RawPtr<T>;
201#endif
202
66799735
A
203// _OBJC_PTRAUTH_H_
204#endif