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