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 a [set of intrinsics](#intrinsics)
14(to sign/authenticate pointers).
15
16The current implementation leverages the
17[Armv8.3-A PAuth/Pointer Authentication Code](#armv8-3-a-pauth-pointer-authentication-code)
18instructions in the [AArch64 backend](#aarch64-support).
19This support is used to implement the Darwin arm64e ABI, as well as the
20[PAuth ABI Extension to ELF](https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst).
21
22
23## LLVM IR Representation
24
25### Intrinsics
26
27These intrinsics are provided by LLVM to expose pointer authentication
28operations.
29
30
31#### '``llvm.ptrauth.sign``'
32
33##### Syntax:
34
35```llvm
36declare i64 @llvm.ptrauth.sign(i64 <value>, i32 <key>, i64 <discriminator>)
37```
38
39##### Overview:
40
41The '``llvm.ptrauth.sign``' intrinsic signs a raw pointer.
42
43
44##### Arguments:
45
46The ``value`` argument is the raw pointer value to be signed.
47The ``key`` argument is the identifier of the key to be used to generate the
48signed value.
49The ``discriminator`` argument is the additional diversity data to be used as a
50discriminator (an integer, an address, or a blend of the two).
51
52##### Semantics:
53
54The '``llvm.ptrauth.sign``' intrinsic implements the `sign`_ operation.
55It returns a signed value.
56
57If ``value`` is already a signed value, the behavior is undefined.
58
59If ``value`` is not a pointer value for which ``key`` is appropriate, the
60behavior is undefined.
61
62
63#### '``llvm.ptrauth.auth``'
64
65##### Syntax:
66
67```llvm
68declare i64 @llvm.ptrauth.auth(i64 <value>, i32 <key>, i64 <discriminator>)
69```
70
71##### Overview:
72
73The '``llvm.ptrauth.auth``' intrinsic authenticates a signed pointer.
74
75##### Arguments:
76
77The ``value`` argument is the signed pointer value to be authenticated.
78The ``key`` argument is the identifier of the key that was used to generate
79the signed value.
80The ``discriminator`` argument is the additional diversity data to be used as a
81discriminator.
82
83##### Semantics:
84
85The '``llvm.ptrauth.auth``' intrinsic implements the `auth`_ operation.
86It returns a raw pointer value.
87If ``value`` does not have a correct signature for ``key`` and ``discriminator``,
88the intrinsic traps in a target-specific way.
89
90
91#### '``llvm.ptrauth.strip``'
92
93##### Syntax:
94
95```llvm
96declare i64 @llvm.ptrauth.strip(i64 <value>, i32 <key>)
97```
98
99##### Overview:
100
101The '``llvm.ptrauth.strip``' intrinsic strips the embedded signature out of a
102possibly-signed pointer.
103
104
105##### Arguments:
106
107The ``value`` argument is the signed pointer value to be stripped.
108The ``key`` argument is the identifier of the key that was used to generate
109the signed value.
110
111##### Semantics:
112
113The '``llvm.ptrauth.strip``' intrinsic implements the `strip`_ operation.
114It returns a raw pointer value.  It does **not** check that the
115signature is valid.
116
117``key`` should identify a key that is appropriate for ``value``, as defined
118by the target-specific [keys](#key)).
119
120If ``value`` is a raw pointer value, it is returned as-is (provided the ``key``
121is appropriate for the pointer).
122
123If ``value`` is not a pointer value for which ``key`` is appropriate, the
124behavior is target-specific.
125
126If ``value`` is a signed pointer value, but ``key`` does not identify the
127same key that was used to generate ``value``, the behavior is
128target-specific.
129
130
131#### '``llvm.ptrauth.resign``'
132
133##### Syntax:
134
135```llvm
136declare i64 @llvm.ptrauth.resign(i64 <value>,
137                                 i32 <old key>, i64 <old discriminator>,
138                                 i32 <new key>, i64 <new discriminator>)
139```
140
141##### Overview:
142
143The '``llvm.ptrauth.resign``' intrinsic re-signs a signed pointer using
144a different key and diversity data.
145
146##### Arguments:
147
148The ``value`` argument is the signed pointer value to be authenticated.
149The ``old key`` argument is the identifier of the key that was used to generate
150the signed value.
151The ``old discriminator`` argument is the additional diversity data to be used
152as a discriminator in the auth operation.
153The ``new key`` argument is the identifier of the key to use to generate the
154resigned value.
155The ``new discriminator`` argument is the additional diversity data to be used
156as a discriminator in the sign operation.
157
158##### Semantics:
159
160The '``llvm.ptrauth.resign``' intrinsic performs a combined `auth`_ and `sign`_
161operation, without exposing the intermediate raw pointer.
162It returns a signed pointer value.
163If ``value`` does not have a correct signature for ``old key`` and
164``old discriminator``, the intrinsic traps in a target-specific way.
165
166#### '``llvm.ptrauth.sign_generic``'
167
168##### Syntax:
169
170```llvm
171declare i64 @llvm.ptrauth.sign_generic(i64 <value>, i64 <discriminator>)
172```
173
174##### Overview:
175
176The '``llvm.ptrauth.sign_generic``' intrinsic computes a generic signature of
177arbitrary data.
178
179##### Arguments:
180
181The ``value`` argument is the arbitrary data value to be signed.
182The ``discriminator`` argument is the additional diversity data to be used as a
183discriminator.
184
185##### Semantics:
186
187The '``llvm.ptrauth.sign_generic``' intrinsic computes the signature of a given
188combination of value and additional diversity data.
189
190It returns a full signature value (as opposed to a signed pointer value, with
191an embedded partial signature).
192
193As opposed to [``llvm.ptrauth.sign``](#llvm-ptrauth-sign), it does not interpret
194``value`` as a pointer value.  Instead, it is an arbitrary data value.
195
196
197#### '``llvm.ptrauth.blend``'
198
199##### Syntax:
200
201```llvm
202declare i64 @llvm.ptrauth.blend(i64 <address discriminator>, i64 <integer discriminator>)
203```
204
205##### Overview:
206
207The '``llvm.ptrauth.blend``' intrinsic blends a pointer address discriminator
208with a small integer discriminator to produce a new "blended" discriminator.
209
210##### Arguments:
211
212The ``address discriminator`` argument is a pointer value.
213The ``integer discriminator`` argument is a small integer, as specified by the
214target.
215
216##### Semantics:
217
218The '``llvm.ptrauth.blend``' intrinsic combines a small integer discriminator
219with a pointer address discriminator, in a way that is specified by the target
220implementation.
221
222
223## AArch64 Support
224
225AArch64 is currently the only architecture with full support of the pointer
226authentication primitives, based on Armv8.3-A instructions.
227
228### Armv8.3-A PAuth Pointer Authentication Code
229
230The Armv8.3-A architecture extension defines the PAuth feature, which provides
231support for instructions that manipulate Pointer Authentication Codes (PAC).
232
233#### Keys
234
2355 keys are supported by the PAuth feature.
236
237Of those, 4 keys are interchangeably usable to specify the key used in IR
238constructs:
239* ``ASIA``/``ASIB`` are instruction keys (encoded as respectively 0 and 1).
240* ``ASDA``/``ASDB`` are data keys (encoded as respectively 2 and 3).
241
242``ASGA`` is a special key that cannot be explicitly specified, and is only ever
243used implicitly, to implement the
244[``llvm.ptrauth.sign_generic``](#llvm-ptrauth-sign-generic) intrinsic.
245
246#### Instructions
247
248The IR [Intrinsics](#intrinsics) described above map onto these
249instructions as such:
250* [``llvm.ptrauth.sign``](#llvm-ptrauth-sign): ``PAC{I,D}{A,B}{Z,SP,}``
251* [``llvm.ptrauth.auth``](#llvm-ptrauth-auth): ``AUT{I,D}{A,B}{Z,SP,}``
252* [``llvm.ptrauth.strip``](#llvm-ptrauth-strip): ``XPAC{I,D}``
253* [``llvm.ptrauth.blend``](#llvm-ptrauth-blend): The semantics of the blend
254  operation are specified by the ABI.  In both the ELF PAuth ABI Extension and
255  arm64e, it's a ``MOVK`` into the high 16 bits.  Consequently, this limits
256  the width of the integer discriminator used in blends to 16 bits.
257* [``llvm.ptrauth.sign_generic``](#llvm-ptrauth-sign-generic): ``PACGA``
258* [``llvm.ptrauth.resign``](#llvm-ptrauth-resign): ``AUT*+PAC*``.  These are
259  represented as a single pseudo-instruction in the backend to guarantee that
260  the intermediate raw pointer value is not spilled and attackable.
261