1# Pointer Authentication
2
3## Introduction
4
5Pointer Authentication is a mechanism by which certain pointers are signed.
6When a pointer gets signed, a cryptographic hash of its value and other values
7(pepper and salt) is stored in unused bits of that pointer.
8
9Before the pointer is used, it needs to be authenticated, i.e., have its
10signature checked.  This prevents pointer values of unknown origin from being
11used to replace the signed pointer value.
12
13At the IR level, it is represented using:
14
15* a [set of intrinsics](#intrinsics) (to sign/authenticate pointers)
16* a [call operand bundle](#operand-bundle) (to authenticate called pointers)
17
18The current implementation leverages the
19[Armv8.3-A PAuth/Pointer Authentication Code](#armv8-3-a-pauth-pointer-authentication-code)
20instructions in the [AArch64 backend](#aarch64-support).
21This support is used to implement the Darwin arm64e ABI, as well as the
22[PAuth ABI Extension to ELF](https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst).
23
24
25## LLVM IR Representation
26
27### Intrinsics
28
29These intrinsics are provided by LLVM to expose pointer authentication
30operations.
31
32
33#### '``llvm.ptrauth.sign``'
34
35##### Syntax:
36
37```llvm
38declare i64 @llvm.ptrauth.sign(i64 <value>, i32 <key>, i64 <discriminator>)
39```
40
41##### Overview:
42
43The '``llvm.ptrauth.sign``' intrinsic signs a raw pointer.
44
45
46##### Arguments:
47
48The ``value`` argument is the raw pointer value to be signed.
49The ``key`` argument is the identifier of the key to be used to generate the
50signed value.
51The ``discriminator`` argument is the additional diversity data to be used as a
52discriminator (an integer, an address, or a blend of the two).
53
54##### Semantics:
55
56The '``llvm.ptrauth.sign``' intrinsic implements the `sign`_ operation.
57It returns a signed value.
58
59If ``value`` is already a signed value, the behavior is undefined.
60
61If ``value`` is not a pointer value for which ``key`` is appropriate, the
62behavior is undefined.
63
64
65#### '``llvm.ptrauth.auth``'
66
67##### Syntax:
68
69```llvm
70declare i64 @llvm.ptrauth.auth(i64 <value>, i32 <key>, i64 <discriminator>)
71```
72
73##### Overview:
74
75The '``llvm.ptrauth.auth``' intrinsic authenticates a signed pointer.
76
77##### Arguments:
78
79The ``value`` argument is the signed pointer value to be authenticated.
80The ``key`` argument is the identifier of the key that was used to generate
81the signed value.
82The ``discriminator`` argument is the additional diversity data to be used as a
83discriminator.
84
85##### Semantics:
86
87The '``llvm.ptrauth.auth``' intrinsic implements the `auth`_ operation.
88It returns a raw pointer value.
89If ``value`` does not have a correct signature for ``key`` and ``discriminator``,
90the intrinsic traps in a target-specific way.
91
92
93#### '``llvm.ptrauth.strip``'
94
95##### Syntax:
96
97```llvm
98declare i64 @llvm.ptrauth.strip(i64 <value>, i32 <key>)
99```
100
101##### Overview:
102
103The '``llvm.ptrauth.strip``' intrinsic strips the embedded signature out of a
104possibly-signed pointer.
105
106
107##### Arguments:
108
109The ``value`` argument is the signed pointer value to be stripped.
110The ``key`` argument is the identifier of the key that was used to generate
111the signed value.
112
113##### Semantics:
114
115The '``llvm.ptrauth.strip``' intrinsic implements the `strip`_ operation.
116It returns a raw pointer value.  It does **not** check that the
117signature is valid.
118
119``key`` should identify a key that is appropriate for ``value``, as defined
120by the target-specific [keys](#key)).
121
122If ``value`` is a raw pointer value, it is returned as-is (provided the ``key``
123is appropriate for the pointer).
124
125If ``value`` is not a pointer value for which ``key`` is appropriate, the
126behavior is target-specific.
127
128If ``value`` is a signed pointer value, but ``key`` does not identify the
129same key that was used to generate ``value``, the behavior is
130target-specific.
131
132
133#### '``llvm.ptrauth.resign``'
134
135##### Syntax:
136
137```llvm
138declare i64 @llvm.ptrauth.resign(i64 <value>,
139                                 i32 <old key>, i64 <old discriminator>,
140                                 i32 <new key>, i64 <new discriminator>)
141```
142
143##### Overview:
144
145The '``llvm.ptrauth.resign``' intrinsic re-signs a signed pointer using
146a different key and diversity data.
147
148##### Arguments:
149
150The ``value`` argument is the signed pointer value to be authenticated.
151The ``old key`` argument is the identifier of the key that was used to generate
152the signed value.
153The ``old discriminator`` argument is the additional diversity data to be used
154as a discriminator in the auth operation.
155The ``new key`` argument is the identifier of the key to use to generate the
156resigned value.
157The ``new discriminator`` argument is the additional diversity data to be used
158as a discriminator in the sign operation.
159
160##### Semantics:
161
162The '``llvm.ptrauth.resign``' intrinsic performs a combined `auth`_ and `sign`_
163operation, without exposing the intermediate raw pointer.
164It returns a signed pointer value.
165If ``value`` does not have a correct signature for ``old key`` and
166``old discriminator``, the intrinsic traps in a target-specific way.
167
168#### '``llvm.ptrauth.sign_generic``'
169
170##### Syntax:
171
172```llvm
173declare i64 @llvm.ptrauth.sign_generic(i64 <value>, i64 <discriminator>)
174```
175
176##### Overview:
177
178The '``llvm.ptrauth.sign_generic``' intrinsic computes a generic signature of
179arbitrary data.
180
181##### Arguments:
182
183The ``value`` argument is the arbitrary data value to be signed.
184The ``discriminator`` argument is the additional diversity data to be used as a
185discriminator.
186
187##### Semantics:
188
189The '``llvm.ptrauth.sign_generic``' intrinsic computes the signature of a given
190combination of value and additional diversity data.
191
192It returns a full signature value (as opposed to a signed pointer value, with
193an embedded partial signature).
194
195As opposed to [``llvm.ptrauth.sign``](#llvm-ptrauth-sign), it does not interpret
196``value`` as a pointer value.  Instead, it is an arbitrary data value.
197
198
199#### '``llvm.ptrauth.blend``'
200
201##### Syntax:
202
203```llvm
204declare i64 @llvm.ptrauth.blend(i64 <address discriminator>, i64 <integer discriminator>)
205```
206
207##### Overview:
208
209The '``llvm.ptrauth.blend``' intrinsic blends a pointer address discriminator
210with a small integer discriminator to produce a new "blended" discriminator.
211
212##### Arguments:
213
214The ``address discriminator`` argument is a pointer value.
215The ``integer discriminator`` argument is a small integer, as specified by the
216target.
217
218##### Semantics:
219
220The '``llvm.ptrauth.blend``' intrinsic combines a small integer discriminator
221with a pointer address discriminator, in a way that is specified by the target
222implementation.
223
224
225### Operand Bundle
226
227Function pointers used as indirect call targets can be signed when materialized,
228and authenticated before calls.  This can be accomplished with the
229[``llvm.ptrauth.auth``](#llvm-ptrauth-auth) intrinsic, feeding its result to
230an indirect call.
231
232However, that exposes the intermediate, unauthenticated pointer, e.g., if it
233gets spilled to the stack.  An attacker can then overwrite the pointer in
234memory, negating the security benefit provided by pointer authentication.
235To prevent that, the ``ptrauth`` operand bundle may be used: it guarantees that
236the intermediate call target is kept in a register and never stored to memory.
237This hardening benefit is similar to that provided by
238[``llvm.ptrauth.resign``](#llvm-ptrauth-resign)).
239
240Concretely:
241
242```llvm
243define void @f(void ()* %fp) {
244  call void %fp() [ "ptrauth"(i32 <key>, i64 <data>) ]
245  ret void
246}
247```
248
249is functionally equivalent to:
250
251```llvm
252define void @f(void ()* %fp) {
253  %fp_i = ptrtoint void ()* %fp to i64
254  %fp_auth = call i64 @llvm.ptrauth.auth(i64 %fp_i, i32 <key>, i64 <data>)
255  %fp_auth_p = inttoptr i64 %fp_auth to void ()*
256  call void %fp_auth_p()
257  ret void
258}
259```
260
261but with the added guarantee that ``%fp_i``, ``%fp_auth``, and ``%fp_auth_p``
262are not stored to (and reloaded from) memory.
263
264
265## AArch64 Support
266
267AArch64 is currently the only architecture with full support of the pointer
268authentication primitives, based on Armv8.3-A instructions.
269
270### Armv8.3-A PAuth Pointer Authentication Code
271
272The Armv8.3-A architecture extension defines the PAuth feature, which provides
273support for instructions that manipulate Pointer Authentication Codes (PAC).
274
275#### Keys
276
2775 keys are supported by the PAuth feature.
278
279Of those, 4 keys are interchangeably usable to specify the key used in IR
280constructs:
281* ``ASIA``/``ASIB`` are instruction keys (encoded as respectively 0 and 1).
282* ``ASDA``/``ASDB`` are data keys (encoded as respectively 2 and 3).
283
284``ASGA`` is a special key that cannot be explicitly specified, and is only ever
285used implicitly, to implement the
286[``llvm.ptrauth.sign_generic``](#llvm-ptrauth-sign-generic) intrinsic.
287
288#### Instructions
289
290The IR [Intrinsics](#intrinsics) described above map onto these
291instructions as such:
292* [``llvm.ptrauth.sign``](#llvm-ptrauth-sign): ``PAC{I,D}{A,B}{Z,SP,}``
293* [``llvm.ptrauth.auth``](#llvm-ptrauth-auth): ``AUT{I,D}{A,B}{Z,SP,}``
294* [``llvm.ptrauth.strip``](#llvm-ptrauth-strip): ``XPAC{I,D}``
295* [``llvm.ptrauth.blend``](#llvm-ptrauth-blend): The semantics of the blend
296  operation are specified by the ABI.  In both the ELF PAuth ABI Extension and
297  arm64e, it's a ``MOVK`` into the high 16 bits.  Consequently, this limits
298  the width of the integer discriminator used in blends to 16 bits.
299* [``llvm.ptrauth.sign_generic``](#llvm-ptrauth-sign-generic): ``PACGA``
300* [``llvm.ptrauth.resign``](#llvm-ptrauth-resign): ``AUT*+PAC*``.  These are
301  represented as a single pseudo-instruction in the backend to guarantee that
302  the intermediate raw pointer value is not spilled and attackable.
303