brintos

brintos / llvm-project-archived public Read only

0
0
Text · 78.1 KiB · bf2520b Raw
1730 lines · plain
1Pointer Authentication2======================3 4.. contents::5   :local:6 7Introduction8------------9 10Pointer authentication is a technology which offers strong probabilistic11protection against exploiting a broad class of memory bugs to take control of12program execution.  When adopted consistently in a language ABI, it provides13a form of relatively fine-grained control flow integrity (CFI) check that14resists both return-oriented programming (ROP) and jump-oriented programming15(JOP) attacks.16 17While pointer authentication can be implemented purely in software, direct18hardware support (e.g. as provided by Armv8.3 PAuth) can dramatically improve19performance and code size.  Similarly, while pointer authentication20can be implemented on any architecture, taking advantage of the (typically)21excess addressing range of a target with 64-bit pointers minimizes the impact22on memory performance and can allow interoperation with existing code (by23disabling pointer authentication dynamically).  This document will generally24attempt to present the pointer authentication feature independent of any25hardware implementation or ABI.  Considerations that are26implementation-specific are clearly identified throughout.27 28Note that there are several different terms in use:29 30- **Pointer authentication** is a target-independent language technology.31 32- **PAuth** (sometimes referred to as **PAC**, for Pointer Authentication33  Codes) is an AArch64 architecture extension that provides hardware support34  for pointer authentication.  Additional extensions either modify some of the35  PAuth instruction behavior (notably FPAC), or provide new instruction36  variants (PAuth_LR).37 38- **Armv8.3** is an AArch64 architecture revision that makes PAuth mandatory.39 40- **arm64e** is a specific ABI (not yet fully stable) for implementing pointer41  authentication using PAuth on certain Apple operating systems.42 43This document serves four purposes:44 45- It describes the basic ideas of pointer authentication.46 47- It documents several language extensions that are useful on targets using48  pointer authentication.49 50- It presents a theory of operation for the security mitigation, describing the51  basic requirements for correctness, various weaknesses in the mechanism, and52  ways in which programmers can strengthen its protections (including53  recommendations for language implementors).54 55- It documents the stable ABI of the C, C++, and Objective-C languages on arm64e56  platforms.57 58 59Basic concepts60--------------61 62The simple address of an object or function is a **raw pointer**.  A raw63pointer can be **signed** to produce a **signed pointer**.  A signed pointer64can be then **authenticated** in order to verify that it was **validly signed**65and extract the original raw pointer.  These terms reflect the most likely66implementation technique: computing and storing a cryptographic signature along67with the pointer.68 69An **abstract signing key** is a name which refers to a secret key which is70used to sign and authenticate pointers.  The concrete key value for a71particular name is consistent throughout a process.72 73A **discriminator** is an arbitrary value used to **diversify** signed pointers74so that one validly-signed pointer cannot simply be copied over another.75A discriminator is simply opaque data of some implementation-defined size that76is included in the signature as a salt (see `Discriminators`_ for details.)77 78Nearly all aspects of pointer authentication use just these two primary79operations:80 81- ``sign(raw_pointer, key, discriminator)`` produces a signed pointer given82  a raw pointer, an abstract signing key, and a discriminator.83 84- ``auth(signed_pointer, key, discriminator)`` produces a raw pointer given85  a signed pointer, an abstract signing key, and a discriminator.86 87``auth(sign(raw_pointer, key, discriminator), key, discriminator)`` must88succeed and produce ``raw_pointer``.  ``auth`` applied to a value that was89ultimately produced in any other way is expected to fail, which halts the90program either:91 92- immediately, on implementations that enforce ``auth`` success (e.g., when93  using compiler-generated ``auth`` failure checks, or Armv8.3 with the FPAC94  extension), or95 96- when the resulting pointer value is used, on implementations that don't.97 98However, regardless of the implementation's handling of ``auth`` failures, it99is permitted for ``auth`` to fail to detect that a signed pointer was not100produced in this way, in which case it may return anything; this is what makes101pointer authentication a probabilistic mitigation rather than a perfect one.102 103There are two secondary operations which are required only to implement certain104intrinsics in ``<ptrauth.h>``:105 106- ``strip(signed_pointer, key)`` produces a raw pointer given a signed pointer107  and a key without verifying its validity, unlike ``auth``.  This is useful108  for certain kinds of tooling, such as crash backtraces; it should generally109  not be used in the basic language ABI except in very careful ways.110 111- ``sign_generic(value)`` produces a cryptographic signature for arbitrary112  data, not necessarily a pointer.  This is useful for efficiently verifying113  that non-pointer data has not been tampered with.114 115Whenever any of these operations is called for, the key value must be known116statically.  This is because the layout of a signed pointer may vary according117to the signing key.  (For example, in Armv8.3, the layout of a signed pointer118depends on whether Top Byte Ignore (TBI) is enabled, which can be set119independently for I and D keys.)120 121.. admonition:: Note for API designers and language implementors122 123  These are the *primitive* operations of pointer authentication, provided for124  clarity of description.  They are not suitable either as high-level125  interfaces or as primitives in a compiler IR because they expose raw126  pointers.  Raw pointers require special attention in the language127  implementation to avoid the accidental creation of exploitable code128  sequences; see the section on `Attackable code sequences`_.129 130The following details are all implementation-defined:131 132- the nature of a signed pointer133- the size of a discriminator134- the number and nature of the signing keys135- the implementation of the ``sign``, ``auth``, ``strip``, and ``sign_generic``136  operations137 138While the use of the terms "sign" and "signed pointer" suggest the use of139a cryptographic signature, other implementations may be possible.  See140`Alternative implementations`_ for an exploration of implementation options.141 142.. admonition:: Implementation example: Armv8.3143 144  Readers may find it helpful to know how these terms map to Armv8.3 PAuth:145 146  - A signed pointer is a pointer with a signature stored in the147    otherwise-unused high bits.  The kernel configures the address width based148    on the system's addressing needs, and enables TBI for I or D keys as149    needed.  The bits above the address bits and below the TBI bits (if150    enabled) are unused.  The signature width then depends on this addressing151    configuration.152 153  - A discriminator is a 64-bit integer.  Constant discriminators are 16-bit154    integers.  Blending a constant discriminator into an address consists of155    replacing the top 16 bits of the pointer containing the address with the156    constant.  Pointers used for blending purposes should only have address157    bits, since higher bits will be at least partially overwritten with the158    constant discriminator.159 160  - There are five 128-bit signing-key registers, each of which can only be161    directly read or set by privileged code.  Of these, four are used for162    signing pointers, and the fifth is used only for ``sign_generic``.  The key163    data is simply a pepper added to the hash, not an encryption key, and so164    can be initialized using random data.165 166  - ``sign`` computes a cryptographic hash of the pointer, discriminator, and167    signing key, and stores it in the high bits as the signature. ``auth``168    removes the signature, computes the same hash, and compares the result with169    the stored signature.  ``strip`` removes the signature without170    authenticating it.  The ``aut`` instructions in the baseline Armv8.3 PAuth171    feature do not guarantee to trap on authentication failure; instead, they172    simply corrupt the pointer so that later uses will likely trap. Unless the173    "later use" follows immediately and cannot be recovered from (e.g. with a174    signal handler), this does not provide adequate protection against175    `authentication oracles`_, so implementations must emit additional176    instructions to force an immediate trap. This is unnecessary if the177    processor provides the optional ``FPAC`` extension, which guarantees an178    immediate trap.179 180  - ``sign_generic`` corresponds to the ``pacga`` instruction, which takes two181    64-bit values and produces a 64-bit cryptographic hash. Implementations of182    this instruction are not required to produce meaningful data in all bits of183    the result.184 185Discriminators186~~~~~~~~~~~~~~187 188A discriminator is arbitrary extra data which alters the signature calculated189for a pointer.  When two pointers are signed differently --- either with190different keys or with different discriminators --- an attacker cannot simply191replace one pointer with the other.192 193To use standard cryptographic terminology, a discriminator acts as a194`salt <https://en.wikipedia.org/wiki/Salt_(cryptography)>`_ in the signing of a195pointer, and the key data acts as a196`pepper <https://en.wikipedia.org/wiki/Pepper_(cryptography)>`_.  That is,197both the discriminator and key data are ultimately just added as inputs to the198signing algorithm along with the pointer, but they serve significantly199different roles.  The key data is a common secret added to every signature,200whereas the discriminator is a value that can be derived from201the context in which a specific pointer is signed.  However, unlike a password202salt, it's important that discriminators be *independently* derived from the203circumstances of the signing; they should never simply be stored alongside204a pointer.  Discriminators are then re-derived in authentication operations.205 206The intrinsic interface in ``<ptrauth.h>`` allows an arbitrary discriminator207value to be provided, but can only be used when running normal code.  The208discriminators used by language ABIs must be restricted to make it feasible for209the loader to sign pointers stored in global memory without needing excessive210amounts of metadata.  Under these restrictions, a discriminator may consist of211either or both of the following:212 213- The address at which the pointer is stored in memory.  A pointer signed with214  a discriminator which incorporates its storage address is said to have215  **address diversity**.  In general, using address diversity means that216  a pointer cannot be reliably copied by an attacker to or from a different217  memory location.  However, an attacker may still be able to attack a larger218  call sequence if they can alter the address through which the pointer is219  accessed.  Furthermore, some situations cannot use address diversity because220  of language or other restrictions.221 222- A constant integer, called a **constant discriminator**. A pointer signed223  with a non-zero constant discriminator is said to have **constant224  diversity**.  If the discriminator is specific to a single declaration, it is225  said to have **declaration diversity**; if the discriminator is specific to226  a type of value, it is said to have **type diversity**.  For example, C++227  v-tables on arm64e sign their component functions using a hash of their228  method names and signatures, which provides declaration diversity; similarly,229  C++ member function pointers sign their invocation functions using a hash of230  the member pointer type, which provides type diversity.231 232The implementation may need to restrict constant discriminators to be233significantly smaller than the full size of a discriminator.  For example, on234arm64e, constant discriminators are only 16-bit values.  This is believed to235not significantly weaken the mitigation, since collisions remain uncommon.236 237The algorithm for blending a constant discriminator with a storage address is238implementation-defined.239 240.. _Signing schemas:241 242Signing schemas243~~~~~~~~~~~~~~~244 245Correct use of pointer authentication requires the signing code and the246authenticating code to agree about the **signing schema** for the pointer:247 248- the abstract signing key with which the pointer should be signed and249- an algorithm for computing the discriminator.250 251As described in the section above on `Discriminators`_, in most situations, the252discriminator is produced by taking a constant discriminator and optionally253blending it with the storage address of the pointer.  In these situations, the254signing schema breaks down even more simply:255 256- the abstract signing key,257- a constant discriminator, and258- whether to use address diversity.259 260It is important that the signing schema be independently derived at all signing261and authentication sites.  Preferably, the schema should be hard-coded262everywhere it is needed, but at the very least, it must not be derived by263inspecting information stored along with the pointer.  See the section on264`Attacks on pointer authentication`_ for more information.265 266 267Language features268-----------------269 270There are three levels of the pointer authentication language feature:271 272- The language implementation automatically signs and authenticates function273  pointers (and certain data pointers) across a variety of standard situations,274  including return addresses, function pointers, and C++ virtual functions. The275  intent is for all pointers to code in program memory to be signed in some way276  and for all branches to code in program text to authenticate those277  signatures. In addition to the code pointers themselves, we also use pointer278  authentication to protect data values that directly or indirectly influence279  control flow or program integrity, or can provide attackers with some other280  powerful program compromise.281 282- The language also provides extensions to override the default rules used by283  the language implementation.  For example, the ``__ptrauth`` type qualifier284  can be used to change how pointers or pointer sized integers are signed when285  they are stored in a particular variable or field; this provides much stronger286  protection than is guaranteed by the default rules for C function and data287  pointers.288 289- Finally, the language provides the ``<ptrauth.h>`` intrinsic interface for290  manually signing and authenticating pointers in code.  These can be used in291  circumstances where very specific behavior is required.292 293Language implementation294~~~~~~~~~~~~~~~~~~~~~~~295 296For the most part, pointer authentication is an unobserved detail of the297implementation of the programming language.  Any element of the language298implementation that would perform an indirect branch to a pointer is implicitly299altered so that the pointer is signed when first constructed and authenticated300when the branch is performed.  This includes:301 302- indirect-call features in the programming language, such as C function303  pointers, C++ virtual functions, C++ member function pointers, the "blocks"304  C extension, and so on;305 306- returning from a function, no matter how it is called; and307 308- indirect calls introduced by the implementation, such as branches through the309  global offset table (GOT) used to implement direct calls to functions defined310  outside of the current shared object.311 312For more information about this, see the `Language ABI`_ section.313 314However, some aspects of the implementation are observable by the programmer or315otherwise require special notice.316 317C data pointers318^^^^^^^^^^^^^^^319 320The current implementation in Clang does not sign pointers to ordinary data by321default. For a partial explanation of the reasoning behind this, see the322`Theory of Operation`_ section.323 324A specific data pointer which is more security-sensitive than most can be325signed using the `__ptrauth qualifier`_ or using the ``<ptrauth.h>``326intrinsics.327 328C function pointers329^^^^^^^^^^^^^^^^^^^330 331The C standard imposes restrictions on the representation and semantics of332function pointer types which make it difficult to achieve satisfactory333signature diversity in the default language rules.  See `Attacks on pointer334authentication`_ for more information about signature diversity.  Programmers335should strongly consider using the ``__ptrauth`` qualifier to improve the336protections for important function pointers, such as the components of of337a hand-rolled "v-table"; see the section on the `__ptrauth qualifier`_ for338details.339 340The value of a pointer to a C function includes a signature, even when the341value is cast to a non-function-pointer type like ``void*`` or ``intptr_t``. On342implementations that use high bits to store the signature, this means that343relational comparisons and hashes will vary according to the exact signature344value, which is likely to change between executions of a program.  In some345implementations, it may also vary based on the exact function pointer type.346 347Null pointers348^^^^^^^^^^^^^349 350In principle, an implementation could derive the signed null pointer value351simply by applying the standard signing algorithm to the raw null pointer352value. However, for likely signing algorithms, this would mean that the signed353null pointer value would no longer be statically known, which would have many354negative consequences.  For one, it would become substantially more expensive355to emit null pointer values or to perform null-pointer checks.  For another,356the pervasive (even if technically unportable) assumption that null pointers357are bitwise zero would be invalidated, making it substantially more difficult358to adopt pointer authentication, as well as weakening common optimizations for359zero-initialized memory such as the use of ``.bzz`` sections.  Therefore it is360beneficial to treat null pointers specially by giving them their usual361representation.  On AArch64, this requires additional code when working with362possibly-null pointers, such as when copying a pointer field that has been363signed with address diversity.364 365While this representation of nulls is the safest option for the general case,366there are some situations in which a null pointer may have important semantic367or security impact. For that purpose Clang has the concept of a pointer368authentication schema that signs and authenticates null values.369 370Return addresses371^^^^^^^^^^^^^^^^372 373The current implementation in Clang implicitly signs the return addresses in374function calls.  While the value of the return address is technically an375implementation detail of a function, there are some important libraries and376development tools which rely on manually walking the chain of stack frames.377These tools must be updated to correctly account for pointer authentication,378either by stripping signatures (if security is not important for the tool, e.g.379if it is capturing a stack trace during a crash) or properly authenticating380them.  More information about how these values are signed is available in the381`Language ABI`_ section.382 383C++ virtual functions384^^^^^^^^^^^^^^^^^^^^^385 386The current implementation in Clang signs virtual function pointers with387a discriminator derived from the full signature of the overridden method,388including the method name and parameter types.  It is possible to write C++389code that relies on v-table layout remaining constant despite changes to390a method signature; for example, a parameter might be a ``typedef`` that391resolves to a different type based on a build setting.  Such code violates392C++'s One Definition Rule (ODR), but that violation is not normally detected;393however, pointer authentication will detect it.394 395Language extensions396~~~~~~~~~~~~~~~~~~~397 398Feature testing399^^^^^^^^^^^^^^^400 401Whether the current target uses pointer authentication can be tested for with402a number of different tests.403 404- ``__PTRAUTH__`` macro is defined if ``<ptrauth.h>`` provides its normal405  interface. This implies support for the pointer authentication intrinsics406  and the ``__ptrauth`` qualifier.407 408- ``__has_feature(ptrauth_returns)`` is true if the target uses pointer409  authentication to protect return addresses.410 411- ``__has_feature(ptrauth_calls)`` is true if the target uses pointer412  authentication to protect indirect branches.  On arm64e this implies413  ``__has_feature(ptrauth_returns)``, ``__has_feature(ptrauth_intrinsics)``,414  and the ``__PTRAUTH__`` macro.415 416- For backwards compatibility purposes ``__has_feature(ptrauth_intrinsics)``417  and ``__has_feature(ptrauth_qualifier)`` are available on arm64e targets.418  These features are synonymous with each other, and are equivalent to testing419  for the ``__PTRAUTH__`` macro definition. Use of these features should be420  restricted to cases where backwards compatibility is required, and should be421  paired with ``defined(__PTRAUTH__)``.422 423 424Clang provides several other tests only for historical purposes; for current425purposes they are all equivalent to ``ptrauth_calls``.426 427``__ptrauth`` qualifier428^^^^^^^^^^^^^^^^^^^^^^^429 430``__ptrauth(key, address, discriminator)`` is an extended type431qualifier which causes so-qualified objects to hold pointers or pointer sized432integers signed using the specified schema rather than the default schema for433such types.434 435In the current implementation in Clang, the qualified type must be a C pointer436type, either to a function or to an object, or a pointer sized integer.  It437currently cannot be an Objective-C pointer type, a C++ reference type, or a438block pointer type; these restrictions may be lifted in the future.439 440The current implementation in Clang is known to not provide adequate safety441guarantees against the creation of `signing oracles`_ when assigning data442pointers to ``__ptrauth``-qualified gl-values.  See the section on `safe443derivation`_ for more information.444 445The qualifier's operands are as follows:446 447- ``key`` - an expression evaluating to a key value from ``<ptrauth.h>``; must448  be a constant expression449 450- ``address`` - whether to use address diversity (1) or not (0); must be451  a constant expression with one of these two values452 453- ``discriminator`` - a constant discriminator; must be a constant expression454 455See `Discriminators`_ for more information about discriminators.456 457Currently the operands must be constant-evaluable even within templates. In the458future this restriction may be lifted to allow value-dependent expressions as459long as they instantiate to a constant expression.460 461Consistent with the ordinary C/C++ rule for parameters, top-level ``__ptrauth``462qualifiers on a parameter (after parameter type adjustment) are ignored when463deriving the type of the function.  The parameter will be passed using the464default ABI for the unqualified pointer type.465 466If ``x`` is an object of type ``__ptrauth(key, address, discriminator) T``,467then the signing schema of the value stored in ``x`` is a key of ``key`` and468a discriminator determined as follows:469 470- if ``address`` is 0, then the discriminator is ``discriminator``;471 472- if ``address`` is 1 and ``discriminator`` is 0, then the discriminator is473  ``&x``; otherwise474 475- if ``address`` is 1 and ``discriminator`` is non-zero, then the discriminator476  is ``ptrauth_blend_discriminator(&x, discriminator)``; see477  `ptrauth_blend_discriminator`_.478 479Non-triviality from address diversity480+++++++++++++++++++++++++++++++++++++481 482Address diversity must impose additional restrictions in order to allow the483implementation to correctly copy values.  In C++, a type qualified with address484diversity is treated like a class type with non-trivial copy/move constructors485and assignment operators, with the usual effect on containing classes and486unions.  C does not have a standard concept of non-triviality, and so we must487describe the basic rules here, with the intention of imitating the emergent488rules of C++:489 490- A type may be **non-trivial to copy**.491 492- A type may also be **illegal to copy**. Types that are illegal to copy are493  always non-trivial to copy.494 495- A type may also be **address-sensitive**. This includes types that use self496  referencing pointers, data protected by address diversified pointer497  authentication, or other similar concepts.498 499- A type qualified with a ``ptrauth`` qualifier or implicit authentication500  schema that requires address diversity is non-trivial to copy and501  address-sensitive.502 503- An array type is illegal to copy, non-trivial to copy, or address-sensitive504  if its element type is illegal to copy, non-trivial to copy, or505  address-sensitive, respectively.506 507- A struct type is illegal to copy, non-trivial to copy, or address-sensitive508  if it has a field whose type is illegal to copy, non-trivial to copy, or509  address-sensitive, respectively.510 511- A union type is both illegal and non-trivial to copy if it has a field whose512  type is non-trivial or illegal to copy.513 514- A union type is address-sensitive if it has a field whose type is515  address-sensitive.516 517- A program is ill-formed if it uses a type that is illegal to copy as518  a function parameter, argument, or return type.519 520- A program is ill-formed if an expression requires a type to be copied that is521  illegal to copy.522 523- Otherwise, copying a type that is non-trivial to copy correctly copies its524  subobjects.525 526- Types that are address-sensitive must always be passed and returned527  indirectly. Thus, changing the address-sensitivity of a type may be528  ABI-breaking even if its size and alignment do not change.529 530``<ptrauth.h>``531~~~~~~~~~~~~~~~532 533This header defines the following types and operations:534 535``ptrauth_key``536^^^^^^^^^^^^^^^537 538This ``enum`` is the type of abstract signing keys.  In addition to defining539the set of implementation-specific signing keys (for example, Armv8.3 defines540``ptrauth_key_asia``), it also defines some portable aliases for those keys.541For example, ``ptrauth_key_function_pointer`` is the key generally used for542C function pointers, which will generally be suitable for other543function-signing schemas.544 545In all the operation descriptions below, key values must be constant values546corresponding to one of the implementation-specific abstract signing keys from547this ``enum``.548 549``ptrauth_extra_data_t``550^^^^^^^^^^^^^^^^^^^^^^^^551 552This is a ``typedef`` of a standard integer type of the correct size to hold553a discriminator value.554 555In the signing and authentication operation descriptions below, discriminator556values must have either pointer type or integer type. If the discriminator is557an integer, it will be coerced to ``ptrauth_extra_data_t``.558 559``ptrauth_blend_discriminator``560^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^561 562.. code-block:: c563 564  ptrauth_blend_discriminator(pointer, integer)565 566Produce a discriminator value which blends information from the given pointer567and the given integer.568 569Implementations may ignore some bits from each value, which is to say, the570blending algorithm may be chosen for speed and convenience over theoretical571strength as a hash-combining algorithm.  For example, arm64e simply overwrites572the high 16 bits of the pointer with the low 16 bits of the integer, which can573be done in a single instruction with an immediate integer.574 575``pointer`` must have pointer type, and ``integer`` must have integer type. The576result has type ``ptrauth_extra_data_t``.577 578``ptrauth_string_discriminator``579^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^580 581.. code-block:: c582 583  ptrauth_string_discriminator(string)584 585Compute a constant discriminator from the given string.586 587``string`` must be a string literal of ``char`` character type.  The result has588type ``ptrauth_extra_data_t``.589 590The result value is never zero and always within range for both the591``__ptrauth`` qualifier and ``ptrauth_blend_discriminator``.592 593This can be used in constant expressions.594 595``ptrauth_type_discriminator``596^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^597 598.. code-block:: c599 600  ptrauth_type_discriminator(type)601 602Compute the constant discriminator derived from the given type, as is computed603for automatically type diversified schemas.604 605``type`` must be a type. The result has the type ``ptrauth_extra_data_t``.606 607This can be used in constant expressions.608 609``ptrauth_function_pointer_type_discriminator``610^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^611 612.. code-block:: c613 614  ptrauth_function_pointer_type_discriminator(function_type)615 616Compute the constant discriminator derived from the provided function type, for617use in contexts where the default function authentication schema. If function618pointer type diversity is enabled, this is equivalent to619`ptrauth_type_discriminator(function_type)`, if it is not enabled this is `0`.620 621``function_type`` must be a function type. The result has the type ``ptrauth_extra_data_t``.622 623This can be used in constant expressions.624 625``ptrauth_strip``626^^^^^^^^^^^^^^^^^627 628.. code-block:: c629 630  ptrauth_strip(signedPointer, key)631 632Given that ``signedPointer`` matches the layout for signed pointers signed with633the given key, extract the raw pointer from it.  This operation does not trap634and cannot fail, even if the pointer is not validly signed.635 636``ptrauth_sign_constant``637^^^^^^^^^^^^^^^^^^^^^^^^^638 639.. code-block:: c640 641  ptrauth_sign_constant(pointer, key, discriminator)642 643Return a signed pointer for a constant address in a manner which guarantees644a non-attackable sequence.645 646``pointer`` must be a constant expression of pointer type which evaluates to647a non-null pointer.648``key``  must be a constant expression of type ``ptrauth_key``.649``discriminator`` must be a constant expression of pointer or integer type;650if an integer, it will be coerced to ``ptrauth_extra_data_t``.651The result will have the same type as ``pointer``.652 653This can be used in constant expressions.654 655``ptrauth_sign_unauthenticated``656^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^657 658.. code-block:: c659 660  ptrauth_sign_unauthenticated(pointer, key, discriminator)661 662Produce a signed pointer for the given raw pointer without applying any663authentication or extra treatment.  This operation is not required to have the664same behavior on a null pointer that the language implementation would.665 666This is a treacherous operation that can easily result in `signing oracles`_.667Programs should use it seldom and carefully.668 669``ptrauth_auth_and_resign``670^^^^^^^^^^^^^^^^^^^^^^^^^^^671 672.. code-block:: c673 674  ptrauth_auth_and_resign(pointer, oldKey, oldDiscriminator, newKey, newDiscriminator)675 676Authenticate that ``pointer`` is signed with ``oldKey`` and677``oldDiscriminator`` and then resign the raw-pointer result of that678authentication with ``newKey`` and ``newDiscriminator``.679 680``pointer`` must have pointer type.  The result will have the same type as681``pointer``.  This operation is not required to have the same behavior on682a null pointer that the language implementation would.683 684The code sequence produced for this operation must not be directly attackable.685However, if the discriminator values are not constant integers, their686computations may still be attackable.  In the future, Clang should be enhanced687to guarantee non-attackability if these expressions are688:ref:`safely-derived<Safe derivation>`.689 690``ptrauth_auth_function``691^^^^^^^^^^^^^^^^^^^^^^^^^692 693.. code-block:: c694 695  ptrauth_auth_function(pointer, key, discriminator)696 697Authenticate that ``pointer`` is signed with ``key`` and ``discriminator`` and698re-sign it to the standard schema for a function pointer of its type.699 700``pointer`` must have function pointer type.  The result will have the same701type as ``pointer``.  This operation is not required to have the same behavior702on a null pointer that the language implementation would.703 704This operation makes the same attackability guarantees as705``ptrauth_auth_and_resign``.706 707If this operation appears syntactically as the function operand of a call,708Clang guarantees that the call will directly authenticate the function value709using the given schema rather than re-signing to the standard schema.710 711``ptrauth_auth_data``712^^^^^^^^^^^^^^^^^^^^^713 714.. code-block:: c715 716  ptrauth_auth_data(pointer, key, discriminator)717 718Authenticate that ``pointer`` is signed with ``key`` and ``discriminator`` and719remove the signature.720 721``pointer`` must have object pointer type.  The result will have the same type722as ``pointer``.  This operation is not required to have the same behavior on723a null pointer that the language implementation would.724 725In the future when Clang makes safe derivation guarantees, the result of726this operation should be considered safely-derived.727 728``ptrauth_sign_generic_data``729^^^^^^^^^^^^^^^^^^^^^^^^^^^^^730 731.. code-block:: c732 733  ptrauth_sign_generic_data(value1, value2)734 735Computes a signature for the given pair of values, incorporating a secret736signing key.737 738This operation can be used to verify that arbitrary data has not been tampered739with by computing a signature for the data, storing that signature, and then740repeating this process and verifying that it yields the same result.  This can741be reasonably done in any number of ways; for example, a library could compute742an ordinary checksum of the data and just sign the result in order to get the743tamper-resistance advantages of the secret signing key (since otherwise an744attacker could reliably overwrite both the data and the checksum).745 746``value1`` and ``value2`` must be either pointers or integers.  If the integers747are larger than ``uintptr_t`` then data not representable in ``uintptr_t`` may748be discarded.749 750The result will have type ``ptrauth_generic_signature_t``, which is an integer751type.  Implementations are not required to make all bits of the result equally752significant; in particular, some implementations are known to not leave753meaningful data in the low bits.754 755Standard ``__ptrauth`` qualifiers756^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^757 758``<ptrauth.h>`` additionally provides several macros which expand to759``__ptrauth`` qualifiers for common ABI situations.760 761For convenience, these macros expand to nothing when pointer authentication is762disabled.763 764These macros can be found in the header; some details of these macros may be765unstable or implementation-specific.766 767 768Theory of operation769-------------------770 771The threat model of pointer authentication is as follows:772 773- The attacker has the ability to read and write to a certain range of774  addresses, possibly the entire address space.  However, they are constrained775  by the normal rules of the process: for example, they cannot write to memory776  that is mapped read-only, and if they access unmapped memory it will trigger777  a trap.778 779- The attacker has no ability to add arbitrary executable code to the program.780  For example, the program does not include malicious code to begin with, and781  the attacker cannot alter existing instructions, load a malicious shared782  library, or remap writable pages as executable.  If the attacker wants to get783  the process to perform a specific sequence of actions, they must somehow784  subvert the normal control flow of the process.785 786In both of the above paragraphs, it is merely assumed that the attacker's787*current* capabilities are restricted; that is, their current exploit does not788directly give them the power to do these things.  The attacker's immediate goal789may well be to leverage their exploit to gain these capabilities, e.g. to load790a malicious dynamic library into the process, even though the process does not791directly contain code to do so.792 793Note that any bug that fits the above threat model can be immediately exploited794as a denial-of-service attack by simply performing an illegal access and795crashing the program.  Pointer authentication cannot protect against this.796While denial-of-service attacks are unfortunate, they are also unquestionably797the best possible result of a bug this severe. Therefore, pointer authentication798enthusiastically embraces the idea of halting the program on a pointer799authentication failure rather than continuing in a possibly-compromised state.800 801Pointer authentication is a form of control-flow integrity (CFI) enforcement.802The basic security hypothesis behind CFI enforcement is that many bugs can only803be usefully exploited (other than as a denial-of-service) by leveraging them to804subvert the control flow of the program.  If this is true, then by inhibiting or805limiting that subversion, it may be possible to largely mitigate the security806consequences of those bugs by rendering them impractical (or, ideally,807impossible) to exploit.808 809Every indirect branch in a program has a purpose.  Using human intelligence, a810programmer can describe where a particular branch *should* go according to this811purpose: a ``return`` in ``printf`` should return to the call site, a particular812call in ``qsort`` should call the comparator that was passed in as an argument,813and so on.  But for CFI to enforce that every branch in a program goes where it814*should* in this sense would require CFI to perfectly enforce every semantic815rule of the program's abstract machine; that is, it would require making the816programming environment perfectly sound.  That is out of scope.  Instead, the817goal of CFI is merely to catch attempts to make a branch go somewhere that its818obviously *shouldn't* for its purpose: for example, to stop a call from819branching into the middle of a function rather than its beginning.  As the820information available to CFI gets better about the purpose of the branch, CFI821can enforce tighter and tighter restrictions on where the branch is permitted to822go.  Still, ultimately CFI cannot make the program sound.  This may help explain823why pointer authentication makes some of the choices it does: for example, to824sign and authenticate mostly code pointers rather than every pointer in the825program.  Preventing attackers from redirecting branches is both particularly826important and particularly approachable as a goal.  Detecting corruption more827broadly is infeasible with these techniques, and the attempt would have far828higher cost.829 830Attacks on pointer authentication831~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~832 833Pointer authentication works as follows.  Every indirect branch in a program has834a purpose.  For every purpose, the implementation chooses a835:ref:`signing schema<Signing schemas>`.  At some place where a pointer is known836to be correct for its purpose, it is signed according to the purpose's schema.837At every place where the pointer is needed for its purpose, it is authenticated838according to the purpose's schema.  If that authentication fails, the program is839halted.840 841There are a variety of ways to attack this.842 843Attacks of interest to programmers844^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^845 846These attacks arise from weaknesses in the default protections offered by847pointer authentication.  They can be addressed by using attributes or intrinsics848to opt in to stronger protection.849 850Substitution attacks851++++++++++++++++++++852 853An attacker can simply overwrite a pointer intended for one purpose with a854pointer intended for another purpose if both purposes use the same signing855schema and that schema does not use address diversity.856 857The most common source of this weakness is when code relies on using the default858language rules for C function pointers.  The current implementation uses the859exact same signing schema for all C function pointers, even for functions of860substantially different type.  While efforts are ongoing to improve constant861diversity for C function pointers of different type, there are necessary limits862to this.  The C standard requires function pointers to be copyable with863``memcpy``, which means that function pointers can never use address diversity.864Furthermore, even if a function pointer can only be replaced with another865function of the exact same type, that can still be useful to an attacker, as in866the following example of a hand-rolled "v-table":867 868.. code-block:: c869 870  struct ObjectOperations {871    void (*retain)(Object *);872    void (*release)(Object *);873    void (*deallocate)(Object *);874    void (*logStatus)(Object *);875  };876 877The weakness in this design is that by lacking any context specific878discriminator, this means an attacker can substitute any of these fields with879any other function pointer signed with the default schema. Similarly the lack of880address diversity allows an attacker to replace the functions in one type's881"v-table" with those of another. This can be mitigated by overriding the default882authentication schema with a more specific signing schema for each purpose.  For883instance, in this example, the ``__ptrauth`` qualifier can be used with a884different constant discriminator for each field.  Since there's no particular885reason it's important for this v-table to be copyable with ``memcpy``, the886functions can also be signed with address diversity:887 888.. code-block:: c889 890  #if defined(__PTRAUTH__)891  #define objectOperation(discriminator) \892    __ptrauth(ptrauth_key_function_pointer, 1, discriminator)893  #else894  #define objectOperation(discriminator)895  #endif896 897  struct ObjectOperations {898    void (*objectOperation(0xf017) retain)(Object *);899    void (*objectOperation(0x2639) release)(Object *);900    void (*objectOperation(0x8bb0) deallocate)(Object *);901    void (*objectOperation(0xc5d4) logStatus)(Object *);902  };903 904This weakness can also sometimes be mitigated by simply keeping the signed905pointer in constant memory, but this is less effective than using better signing906diversity.907 908.. _Access path attacks:909 910Access path attacks911+++++++++++++++++++912 913If a signed pointer is often accessed indirectly (that is, by first loading the914address of the object where the signed pointer is stored), an attacker can915affect uses of it by overwriting the intermediate pointer in the access path.916 917The most common scenario exhibiting this weakness is an object with a pointer to918a "v-table" (a structure holding many function pointers). An attacker does not919need to replace a signed function pointer in the v-table if they can instead920simply replace the v-table pointer in the object with their own pointer ---921perhaps to memory where they've constructed their own v-table, or to existing922memory that coincidentally happens to contain a signed pointer at the right923offset that's been signed with the right signing schema.924 925This attack arises because data pointers are not signed by default. It works926even if the signed pointer uses address diversity: address diversity merely927means that each pointer is signed with its own storage address,928which (by design) is invariant to changes in the accessing pointer.929 930Using sufficiently diverse signing schemas within the v-table can provide931reasonably strong mitigation against this weakness.  Always use address and type932diversity in v-tables to prevent attackers from assembling their own v-table.933Avoid re-using constant discriminators to prevent attackers from replacing a934v-table pointer with a pointer to totally unrelated memory that just happens to935contain an similarly-signed pointer, or reused memory containing a different936type.937 938Further mitigation can be attained by signing pointers to v-tables. Any939signature at all should prevent attackers from forging v-table pointers; they940will need to somehow harvest an existing signed pointer from elsewhere in941memory.  Using a meaningful constant discriminator will force this to be942harvested from an object with similar structure (e.g. a different implementation943of the same interface).  Using address diversity will prevent such harvesting944entirely.  However, care must be taken when sourcing the v-table pointer945originally; do not blindly sign a pointer that is not946:ref:`safely derived<Safe derivation>`.947 948.. _Signing oracles:949 950Signing oracles951+++++++++++++++952 953A signing oracle is a bit of code which can be exploited by an attacker to sign954an arbitrary pointer in a way that can later be recovered.  Such oracles can be955used by attackers to forge signatures matching the oracle's signing schema,956which is likely to cause a total compromise of pointer authentication's957effectiveness.958 959This attack only affects ordinary programmers if they are using certain960treacherous patterns of code.  Currently this includes:961 962- all uses of the ``__ptrauth_sign_unauthenticated`` intrinsic and963- assigning values to ``__ptrauth``-qualified l-values.964 965Care must be taken in these situations to ensure that the pointer being signed966has been :ref:`safely derived<Safe derivation>` or is otherwise not possible to967attack.  (In some cases, this may be challenging without compiler support.)968 969A diagnostic will be added in the future for implicitly dangerous patterns of970code, such as assigning a non-safely-derived values to a971``__ptrauth``-qualified l-value.972 973.. _Authentication oracles:974 975Authentication oracles976++++++++++++++++++++++977 978An authentication oracle is a bit of code which can be exploited by an attacker979to leak whether a signed pointer is validly signed without halting the program980if it isn't.  Such oracles can be used to forge signatures matching the oracle's981signing schema if the attacker can repeatedly invoke the oracle for different982candidate signed pointers. This is likely to cause a total compromise of pointer983authentication's effectiveness.984 985There should be no way for an ordinary programmer to create an authentication986oracle using the current set of operations. However, implementation flaws in the987past have occasionally given rise to authentication oracles due to a failure to988immediately trap on authentication failure.989 990The likelihood of creating an authentication oracle is why there is currently no991intrinsic which queries whether a signed pointer is validly signed.992 993 994Attacks of interest to implementors995^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^996 997These attacks are not inherent to the model; they arise from mistakes in either998implementing or using the `sign` and `auth` operations. Avoiding these mistakes999requires careful work throughout the system.1000 1001Failure to trap on authentication failure1002+++++++++++++++++++++++++++++++++++++++++1003 1004Any failure to halt the program on an authentication failure is likely to be1005exploitable by attackers to create an1006:ref:`authentication oracle<Authentication oracles>`.1007 1008There are several different ways to introduce this problem:1009 1010- The implementation might try to halt the program in some way that can be1011  intercepted.1012 1013  For example, the Armv8.3 ``aut`` instructions do not directly trap on1014  authentication failure on processors that lack the ``FPAC`` extension.1015  Instead, they corrupt their results to be invalid pointers, with the idea that1016  subsequent uses of those pointers will trigger traps as bad memory accesses.1017  However, most kernels do not immediately halt programs that trap due to bad1018  memory accesses; instead, they notify the process to give it an opportunity to1019  recover. If this happens with an ``auth`` failure, the attacker may be able to1020  exploit the recovery path in a way that creates an oracle. Kernels must1021  provide a way for a process to trap unrecoverably, and this should cover all1022  ``FPAC`` traps. Compilers must ensure that ``auth`` failures trigger an1023  unrecoverable trap, ideally by taking advantage of ``FPAC``, but if necessary1024  by emitting extra instructions.1025 1026- A compiler might use an intermediate representation (IR) for ``sign`` and1027  ``auth`` operations that cannot make adequate correctness guarantees.1028 1029  For example, suppose that an IR uses ARMv8.3-like semantics for ``auth``: the1030  operation merely corrupts its result on failure instead of promising to trap.1031  A frontend might emit patterns of IR that always follow an ``auth`` with a1032  memory access, thinking that this ensures correctness. But if the IR can be1033  transformed to insert code between the ``auth`` and the access, or if the1034  ``auth`` can be speculated, then this potentially creates an oracle.  It is1035  better for ``auth`` to semantically guarantee to trap, potentially requiring1036  an explicit check in the generated code. An ARMv8.3-like target can avoid this1037  explicit check in the common case by recognizing the pattern of an ``auth``1038  followed immediately by an access.1039 1040Attackable code sequences1041+++++++++++++++++++++++++1042 1043If code that is part of a pointer authentication operation is interleaved with1044code that may itself be vulnerable to attacks, an attacker may be able to use1045this to create a :ref:`signing<Signing oracles>` or1046:ref:`authentication<Authentication oracles>` oracle.1047 1048For example, suppose that the compiler is generating a call to a function and1049passing two arguments: a signed constant pointer and a value derived from a1050call.  In ARMv8.3, this code might look like so:1051 1052.. code-block:: asm1053 1054  adr x19, _callback.        ; compute &_callback1055  paciza x19                 ; sign it with a constant discriminator of 01056  blr _argGenerator          ; call _argGenerator() (returns in x0)1057  mov x1, x0                 ; move call result to second arg register1058  mov x0, x19                ; move signed &_callback to first arg register1059  blr _function              ; call _function1060 1061This code is correct, as would be a sequencing that does *both* the ``adr`` and1062the ``paciza`` after the call to ``_argGenerator``.  But a sequence that1063computes the address of ``_callback`` but leaves it as a raw pointer in a1064register during the call to ``_argGenerator`` would be vulnerable:1065 1066.. code-block:: asm1067 1068  adr x19, _callback.        ; compute &_callback1069  blr _argGenerator          ; call _argGenerator() (returns in x0)1070  mov x1, x0                 ; move call result to second arg register1071  paciza x19                 ; sign &_callback1072  mov x0, x19                ; move signed &_callback to first arg register1073  blr _function              ; call _function1074 1075If ``_argGenerator`` spills ``x19`` (a callee-save register), and if the1076attacker can perform a write during this call, then the attacker can overwrite1077the spill slot with an arbitrary pointer that will eventually be unconditionally1078signed after the function returns.  This would be a signing oracle.1079 1080The implementation can avoid this by obeying two basic rules:1081 1082- The compiler's intermediate representations (IR) should not provide operations1083  that expose intermediate raw pointers.  This may require providing extra1084  operations that perform useful combinations of operations.1085 1086  For example, there should be an "atomic" auth-and-resign operation that should1087  be used instead of emitting an ``auth`` operation whose result is fed into a1088  ``sign``.1089 1090  Similarly, if a pointer should be authenticated as part of doing a memory1091  access or a call, then the access or call should be decorated with enough1092  information to perform the authentication; there should not be a separate1093  ``auth`` whose result is used as the pointer operand for the access or call.1094  (In LLVM IR, we do this for calls, but not yet for loads or stores.)1095 1096  "Operations" includes things like materializing a signed value to a known1097  function or global variable.  The compiler must be able to recognize and emit1098  this as a unified operation, rather than potentially splitting it up as in1099  the example above.1100 1101- The compiler backend should not be too aggressive about scheduling1102  instructions that are part of a pointer authentication operation. This may1103  require custom code-generation of these operations in some cases.1104 1105Register clobbering1106+++++++++++++++++++1107 1108As a refinement of the section on `Attackable code sequences`_, if the attacker1109has the ability to modify arbitrary *register* state at arbitrary points in the1110program, then special care must be taken.1111 1112For example, ARMv8.3 might materialize a signed function pointer like so:1113 1114.. code-block:: asm1115 1116  adr x0, _callback.        ; compute &_callback1117  paciza x0                 ; sign it with a constant discriminator of 01118 1119If an attacker has the ability to overwrite ``x0`` between these two1120instructions, this code sequence is vulnerable to becoming a signing oracle.1121 1122For the most part, this sort of attack is not possible: it is a basic element of1123the design of modern computation that register state is private and inviolable.1124However, in systems that support asynchronous interrupts, this property requires1125the cooperation of the interrupt-handling code. If that code saves register1126state to memory, and that memory can be overwritten by an attacker, then1127essentially the attack can overwrite arbitrary register state at an arbitrary1128point.  This could be a concern if the threat model includes attacks on the1129kernel or if the program uses user-space preemptive multitasking.1130 1131(Readers might object that an attacker cannot rely on asynchronous interrupts1132triggering at an exact instruction boundary.  In fact, researchers have had some1133success in doing exactly that.  Even ignoring that, though, we should aim to1134protect against lucky attackers just as much as good ones.)1135 1136To protect against this, saved register state must be at least partially signed1137(using something like `ptrauth_sign_generic_data`_).  This is required for1138correctness anyway because saved thread states include security-critical1139registers such as SP, FP, PC, and LR (where applicable).  Ideally, this1140signature would cover all the registers, but since saving and restoring1141registers can be very performance-sensitive, that may not be acceptable. It is1142sufficient to set aside a small number of scratch registers that will be1143guaranteed to be preserved correctly; the compiler can then be careful to only1144store critical values like intermediate raw pointers in those registers.1145 1146``setjmp`` and ``longjmp`` should sign and authenticate the core registers (SP,1147FP, PC, and LR), but they do not need to worry about intermediate values because1148``setjmp`` can only be called synchronously, and the compiler should never1149schedule pointer-authentication operations interleaved with arbitrary calls.1150 1151.. _Relative addresses:1152 1153Attacks on relative addressing1154++++++++++++++++++++++++++++++1155 1156Relative addressing is a technique used to compress and reduce the load-time1157cost of infrequently-used global data.  The pointer authentication system is1158unlikely to support signing or authenticating a relative address, and in most1159cases it would defeat the point to do so: it would take additional storage1160space, and applying the signature would take extra work at load time.1161 1162Relative addressing is not precluded by the use of pointer authentication, but1163it does take extra considerations to make it secure:1164 1165- Relative addresses must only be stored in read-only memory.  A writable1166  relative address can be overwritten to point nearly anywhere, making it1167  inherently insecure; this danger can only be compensated for with techniques1168  for protecting arbitrary data like `ptrauth_sign_generic_data`_.1169 1170- Relative addresses must only be accessed through signed pointers with adequate1171  diversity.  If an attacker can perform an `access path attack` to replace the1172  pointer through which the relative address is accessed, they can easily cause1173  the relative address to point wherever they want.1174 1175Signature forging1176+++++++++++++++++1177 1178If an attacker can exactly reproduce the behavior of the signing algorithm, and1179they know all the correct inputs to it, then they can perfectly forge a1180signature on an arbitrary pointer.1181 1182There are three components to avoiding this mistake:1183 1184- The abstract signing algorithm should be good: it should not have glaring1185  flaws which would allow attackers to predict its result with better than1186  random accuracy without knowing all the inputs (like the key values).1187 1188- The key values should be kept secret.  If at all possible, they should never1189  be stored in accessible memory, or perhaps only stored encrypted.1190 1191- Contexts that are meant to be independently protected should use different1192  key values.  For example, the kernel should not use the same keys as user1193  processes.  Different user processes should also use different keys from each1194  other as much as possible, although this may pose its own technical1195  challenges.1196 1197Remapping1198+++++++++1199 1200If an attacker can change the memory protections on certain pages of the1201program's memory, that can substantially weaken the protections afforded by1202pointer authentication.1203 1204- If an attacker can inject their own executable code, they can also certainly1205  inject code that can be used as a :ref:`signing oracle<Signing Oracles>`.1206  The same is true if they can write to the instruction stream.1207 1208- If an attacker can remap read-only program data sections to be writable, then1209  any use of :ref:`relative addresses` in global data becomes insecure.1210 1211- On platforms that use them, if an attacker can remap the memory containing1212  the `global offset tables`_ as writable, then any unsigned pointers in those1213  tables are insecure.1214 1215Remapping memory in this way often requires the attacker to have already1216substantively subverted the control flow of the process.  Nonetheless, if the1217operating system has a mechanism for mapping pages in a way that cannot be1218remapped, this should be used wherever possible.1219 1220.. _Safe Derivation:1221 1222Safe derivation1223~~~~~~~~~~~~~~~1224 1225Whether a data pointer is stored, even briefly, as a raw pointer can affect the1226security-correctness of a program.  (Function pointers are never implicitly1227stored as raw pointers; raw pointers to functions can only be produced with the1228``<ptrauth.h>`` intrinsics.)  Repeated re-signing can also impact performance.1229Clang makes a modest set of guarantees in this area:1230 1231- An expression of pointer type is said to be **safely derived** if:1232 1233  - it takes the address of a global variable or function, or1234 1235  - it is a load from a gl-value of ``__ptrauth``-qualified type, or1236 1237  - it is a load from read-only memory that has been initialized from a safely1238    derived source, such as the `data const` section of a binary or library.1239 1240- If a value that is safely derived is assigned to a ``__ptrauth``-qualified1241  object, including by initialization, then the value will be directly signed as1242  appropriate for the target qualifier and will not be stored as a raw pointer.1243 1244- If the function expression of a call is a gl-value of ``__ptrauth``-qualified1245  type, then the call will be authenticated directly according to the source1246  qualifier and will not be resigned to the default rule for a function pointer1247  of its type.1248 1249These guarantees are known to be inadequate for data pointer security. In1250particular, Clang should be enhanced to make the following guarantees:1251 1252- A pointer should additionally be considered safely derived if it is:1253 1254  - the address of a gl-value that is safely derived,1255 1256  - the result of pointer arithmetic on a pointer that is safely derived (with1257    some restrictions on the integer operand),1258 1259  - the result of a comma operator where the second operand is safely derived,1260 1261  - the result of a conditional operator where the selected operand is safely1262    derived, or1263 1264  - the result of loading from a safely derived gl-value.1265 1266- A gl-value should be considered safely derived if it is:1267 1268  - a dereference of a safely derived pointer,1269 1270  - a member access into a safely derived gl-value, or1271 1272  - a reference to a variable.1273 1274- An access to a safely derived gl-value should be guaranteed to not allow1275  replacement of any of the safely-derived component values at any point in the1276  access.  "Access" should include loading a function pointer.1277 1278- Assignments should include pointer-arithmetic operators like ``+=``.1279 1280Making these guarantees will require further work, including significant new1281support in LLVM IR.1282 1283Furthermore, Clang should implement a warning when assigning a data pointer that1284is not safely derived to a ``__ptrauth``-qualified gl-value.1285 1286 1287Language ABI1288------------1289 1290This section describes the pointer-authentication ABI currently implemented in1291Clang for the Apple arm64e target.  As other targets adopt pointer1292authentication, this section should be generalized to express their ABIs as1293well.1294 1295Key assignments1296~~~~~~~~~~~~~~~1297 1298ARMv8.3 provides four abstract signing keys: ``IA``, ``IB``, ``DA``, and ``DB``.1299The architecture designates ``IA`` and ``IB`` for signing code pointers and1300``DA`` and ``DB`` for signing data pointers; this is reinforced by two1301properties:1302 1303- The ISA provides instructions that perform combined auth+call and auth+load1304  operations; these instructions can only use the ``I`` keys and ``D`` keys,1305  respectively.1306 1307- AArch64's TBI feature can be separately enabled for code pointers (controlling1308  whether indirect-branch instructions ignore those bits) and data pointers1309  (controlling whether memory-access instructions) ignore those bits. If TBI is1310  enabled for a kind of pointer, the sign and auth operations preserve the TBI1311  bits when signing with an associated keys (at the cost of shrinking the number1312  of available signing bits by 8).1313 1314arm64e then further subdivides the keys as follows:1315 1316- The ``A`` keys are used for primarily "global" purposes like signing v-tables1317  and function pointers.  These keys are sometimes called *process-independent*1318  or *cross-process* because on existing OSes they are not changed when changing1319  processes, although this is not a platform guarantee.1320 1321- The ``B`` keys are used for primarily "local" purposes like signing return1322  addresses.  These keys are sometimes called *process-specific* because they1323  are typically different between processes. However, they are in fact shared1324  across processes in one situation: systems which provide ``fork`` cannot1325  change these keys in the child process; they can only be changed during1326  ``exec``.1327 1328Implementation-defined algorithms and quantities1329~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1330 1331The cryptographic hash algorithm used to compute signatures in ARMv8.3 is a1332private detail of the hardware implementation.1333 1334arm64e restricts constant discriminators (used in ``__ptrauth`` and1335``ptrauth_blend_discriminator``) to the range from 0 to 65535, inclusive.  A 01336discriminator generally signifies that no blending is required; see the1337documentation for ``ptrauth_blend_discriminator``.  This range is somewhat1338narrow but has two advantages:1339 1340- The AArch64 ISA allows an arbitrary 16-bit immediate to be written over the1341  top 16 bits of a register in a single instruction:1342 1343  .. code-block:: asm1344 1345    movk xN, #0x4849, LSL 481346 1347  This is ideal for the discriminator blending operation because it adds minimal1348  code-size overhead and avoids overwriting any interesting bits from the1349  pointer.  Blending in a wider constant discriminator would either clobber1350  interesting bits (e.g. if it was loaded with ``movk xN, #0x4c4f, LSL 32``) or1351  require significantly more code (e.g. if the discriminator was loaded with a1352  ``mov+bfi`` sequence).1353 1354- It is possible to pack a 16-bit discriminator into loader metadata with1355  minimal compromises, whereas a wider discriminator would require extra1356  metadata storage and therefore significantly impact load times.1357 1358The string hash used by ``ptrauth_string_discriminator`` is a 64-bit SipHash-2-41359using the constant seed ``b5d4c9eb79104a796fec8b1b428781d4`` (big-endian), with1360the result reduced by modulo to the range of non-zero discriminators (i.e.1361``(rawHash % 65535) + 1``).1362 1363Return addresses1364~~~~~~~~~~~~~~~~1365 1366The kernel must ensure that attackers cannot replace LR due to an asynchronous1367exception; see `Register clobbering`_.  If this is done by generally protecting1368LR, then functions which don't spill LR to the stack can avoid signing it1369entirely.  Otherwise, the return address must be signed; on arm64e it is signed1370with the ``IB`` key using the stack pointer on entry as the discriminator.1371 1372Protecting return addresses is of such particular importance that the ``IB`` key1373is almost entirely reserved for this purpose.1374 1375Global offset tables1376~~~~~~~~~~~~~~~~~~~~1377 1378The global offset table (GOT) is not part of the language ABI, but it is a1379common implementation technique for dynamic linking which deserves special1380discussion here.1381 1382Whenever possible, signed pointers should be materialized directly in code1383rather than via the GOT, e.g. using an ``adrp+add+pac`` sequence on ARMv8.3.1384This decreases the amount of work necessary at load time to initialize the GOT,1385but more importantly, it defines away the potential for several attacks:1386 1387- Attackers cannot change instructions, so there is no way to cause this code1388  sequence to materialize a different pointer, whereas an access via the GOT1389  always has *at minimum* a probabilistic chance to be the target of successful1390  `substitution attacks`_.1391 1392- The GOT is a dense pool of fixed pointers at a fixed offset relative to code;1393  attackers can search this pool for useful pointers that can be used in1394  `substitution attacks`_, whereas pointers that are only materialized directly1395  are not so easily available.1396 1397- Similarly, attackers can use `access path attacks`_ to replace a pointer to a1398  signed pointer with a pointer to the GOT if the signing schema used within the1399  GOT happens to be the same as the original pointer.  This kind of collision1400  becomes much less likely to be useful the fewer pointers are in the GOT in the1401  first place.1402 1403If this can be done for a symbol, then the compiler need only ensure that it1404materializes the signed pointer using registers that are safe against1405`register clobbering`_.1406 1407However, many symbols can only be accessed via the GOT, e.g. because they1408resolve to definitions outside of the current image.  In this case, care must1409be taken to ensure that using the GOT does not introduce weaknesses.1410 1411- If the entire GOT can be mapped read-only after loading, then no signing is1412  required within the GOT.  In fact, not signing pointers in the GOT is1413  preferable in this case because it makes the GOT useless for the harvesting1414  and access-path attacks above.  Storing raw pointers in this way is usually1415  extremely unsafe, but for the special case of an immutable GOT entry it's fine1416  because the GOT is always accessed via an address that is directly1417  materialized in code and thus provably unattackable.  (But see `Remapping`_.)1418 1419- Otherwise, GOT entries which are used for producing a signed pointer constant1420  must be signed.  The signing schema used in the GOT need not match the target1421  signing schema for the signed constant.  To counteract the threats of1422  substitution attacks, it's best if GOT entries can be signed with address1423  diversity.  Using a good constant discriminator as well (perhaps derived from1424  the symbol name) can make it less useful to use a pointer to the GOT as the1425  replacement in an :ref:`access path attack<Access path attacks>`.1426 1427In either case, the compiler must ensure that materializing the address of a GOT1428entry as part of producing a signed pointer constant is not vulnerable to1429`register clobbering`_.  If the linker also generates code for this, e.g. for1430call stubs, this generated code must take the same precautions.1431 1432Dynamic symbol lookup1433~~~~~~~~~~~~~~~~~~~~~1434 1435On platforms that support dynamically loading or resolving symbols it is1436necessary for them to define the pointer authentication semantics of the APIs1437provided to perform such lookups. While the platform may choose to reply1438unsigned pointers from such function and rely on the caller performing the1439initial signing, doing so creates the opportunity for caller side errors that1440create :ref:`signing oracles<Signing Oracles>`.1441 1442On arm64e the `dlsym` function is used to resolve a symbol at runtime. If the1443resolved symbol is a function or other code pointer the returned pointer is1444signed using the default function signing schema described in1445:ref:`C function pointers<C function abi>`. If the resolved symbol is not a code pointer it is1446returned as an unsigned pointer.1447 1448.. _C function abi:1449 1450C function pointers1451~~~~~~~~~~~~~~~~~~~1452 1453On arm64e, C function pointers are currently signed with the ``IA`` key without1454address diversity and with a constant discriminator of 0.1455 1456The C and C++ standards do not permit C function pointers to be signed with1457address diversity by default: in C++ terms, function pointer types are required1458to be trivially copyable, which means they must be copyable with ``memcpy``.1459 1460The use of a uniform constant discriminator greatly simplifies the adoption of1461arm64e, but it is a significant weakness in the mitigation because it allows any1462C function pointer to be replaced with another. Clang supports1463`-fptrauth-function-pointer-type-discrimination`, which enables a variant ABI1464that uses type discrimination for function pointers. When generating the type1465based discriminator for a function type all primitive integer types are1466considered equivalent due to the prevalence of mismatching integer parameter1467types in real world code. Type discrimination of function pointers is1468ABI-incompatible with the standard arm64e ABI, but it can be used in constrained1469contexts such as embedded systems or in code that does not require function1470pointer interoperation with the standard ABI (e.g. because it does not pass1471function pointers back and forth, or only does so through1472``__ptrauth``-qualified l-values).1473 1474C++ virtual tables1475~~~~~~~~~~~~~~~~~~1476 1477By default the pointer to a C++ virtual table is currently signed with the1478``DA`` key, address diversity, and a constant discriminator equal to the string1479hash (see `ptrauth_string_discriminator`_) of the mangled v-table identifier1480of the primary base class for the v-table. To support existing code or ABI1481constraints it is possible to use the `ptrauth_vtable_pointer` attribute to1482override the schema used for the v-table pointer of the base type of1483polymorphic class hierarchy. This attribute permits the configuration of the1484key, address diversity mode, and any extra constant discriminator to be used.1485 1486Virtual functions in a C++ virtual table are signed with the ``IA`` key, address1487diversity, and a constant discriminator equal to the string hash (see1488`ptrauth_string_discriminator`_) of the mangled name of the function which1489originally gave rise to the v-table slot.1490 1491C++ dynamic_cast1492~~~~~~~~~~~~~~~~1493 1494C++'s ``dynamic_cast`` presents a difficulty relative to other polymorphic1495languages that have a1496`top type <https://en.wikipedia.org/wiki/Any_type>` as the use of declaration1497diversity for v-table pointers results in distinct signing schemas for each1498isolated type hierarchy. As a result it is not possible for the Itanium ABI1499defined ``__dynamic_cast`` entry point to directly authenticate the v-table1500pointer of the provided object.1501 1502The current implementation uses a forced authentication of the subject object's1503v-table prior to invoking ``__dynamic_cast`` to partially verify that the1504object's vtable is valid. The ``__dynamic_cast`` implementation currently relies1505on this caller side check to limit the substitutability of the v-table pointer1506with an incorrect or invalid v-table. The subsequent implementation of the1507dynamic cast algorithm is built on pointer auth protected ``type_info`` objects.1508 1509In future a richer solution may be developed to support vending the correct1510authentication schema directly to the ``dynamic_cast`` implementation.1511 1512C++ std::type_info v-table pointers1513~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1514 1515The v-table pointer of the ``std::type_info`` type is signed with the ``DA`` key1516and no additional diversity.1517 1518C++ member function pointers1519~~~~~~~~~~~~~~~~~~~~~~~~~~~~1520 1521A member function pointer is signed with the ``IA`` key, no address diversity,1522and a constant discriminator equal to the string hash1523(see `ptrauth_string_discriminator`_) of the member pointer type.  Address1524diversity is not permitted by C++ for member function pointers because they must1525be trivially-copyable types.1526 1527The Itanium C++ ABI specifies that member function pointers to virtual functions1528simply store an offset to the correct v-table slot.  This ABI cannot be used1529securely with pointer authentication because there is no safe place to store the1530constant discriminator for the target v-table slot: if it's stored with the1531offset, an attacker can simply overwrite it with the right discriminator for the1532offset.  Even if the programmer never uses pointers to virtual functions, the1533existence of this code path makes all member function pointer dereferences1534insecure.1535 1536arm64e changes this ABI so that virtual function pointers are stored using1537dispatch thunks with vague linkage.  Because arm64e supports interoperation with1538``arm64`` code when pointer authentication is disabled, an arm64e member1539function pointer dereference still recognizes the virtual-function1540representation but uses an bogus discriminator on that path that should always1541trap if pointer authentication is enabled dynamically.1542 1543The use of dispatch thunks means that ``==`` on member function pointers is no1544longer reliable for virtual functions, but this is acceptable because the1545standard makes no guarantees about it in the first place.1546 1547The use of dispatch thunks also is required to support declaration specific1548authentication schemas for v-table pointers.1549 1550C++ mangling1551~~~~~~~~~~~~1552 1553When the ``__ptrauth`` qualifier appears in a C++ mangled name,1554it is mangled as a vendor qualifier with the signature1555``U9__ptrauthILj<key>ELb<addressDiscriminated>ELj<extraDiscriminator>EE``.1556 1557e.g. ``int * __ptrauth(1, 0, 1234)`` will be mangled as1558``U9__ptrauthILj1ELb0ELj1234EE``.1559 1560If the vtable pointer authentication scheme of a polymorphic class is overridden1561we mangle the override information with the vendor qualifier1562``__vtptrauth(int key, bool addressDiscriminated, unsigned extraDiscriminator)``,1563where the extra discriminator is the explicit value the specified discrimination1564mode evalutes to.1565 1566Blocks1567~~~~~~1568 1569Block pointers are data pointers which must interoperate with the ObjC `id` type1570and therefore cannot be signed themselves. As blocks conform to the ObjC `id`1571type, they contain an ``isa`` pointer signed as described1572:ref:`below<Objc isa and super>`.1573 1574The invocation pointer in a block is signed with the ``IA`` key using address1575diversity and a constant discriminator of 0.  Using a uniform discriminator is1576seen as a weakness to be potentially improved, but this is tricky due to the1577subtype polymorphism directly permitted for blocks.1578 1579Block descriptors and ``__block`` variables can contain pointers to functions1580that can be used to copy or destroy the object.  These functions are signed with1581the ``IA`` key, address diversity, and a constant discriminator of 0.  The1582structure of block descriptors is under consideration for improvement.1583 1584Objective-C runtime1585~~~~~~~~~~~~~~~~~~~1586 1587In addition to the compile time ABI design, the Objective-C runtime provides1588additional protection to methods and other metadata that have been loaded into1589the Objective-C method cache; this protection is private to the runtime.1590 1591Objective-C methods1592~~~~~~~~~~~~~~~~~~~1593 1594Objective-C method lists sign methods with the ``IA`` key using address1595diversity and a constant discriminator of 0.  Using a uniform constant1596discriminator is believed to be acceptable because these tables are only1597accessed internally to the Objective-C runtime.1598 1599Objective-C class method list pointer1600~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1601 1602The method list pointer in Objective-C classes are signed with the ``DA`` key1603using address diversity, and a constant discriminator of 0xC310.1604 1605Objective-C class read-only data pointer1606~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1607 1608The read-only data pointer in Objective-C classes are signed with the ``DA`` key1609using address diversity, and a constant discriminator of 0x61F8.1610 1611.. _Objc isa and super:1612 1613Objective-C ``isa`` and ``super`` pointers1614~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1615 1616An Objective-C object's ``isa`` and ``super`` pointers are both signed with1617the ``DA`` key using address diversity and constant discriminators of 0x6AE11618and 0x25DA respectively.1619 1620Objective-C ``SEL`` pointers1621~~~~~~~~~~~~~~~~~~~~~~~~~~~~1622 1623By default, the type of an Objective-C instance variable of type ``SEL``, when1624the qualifiers do not include an explicit ``__ptrauth`` qualifier, is adjusted1625to be qualified with ``__ptrauth(ptrauth_key_asdb, 1, 0x57C2)``.1626 1627This provides a measure of implicit at-rest protection to  Objective-C classes1628that store selectors, as in the common target-action design pattern. This1629prevents attackers from overriding the selector to invoke an arbitrary different1630method, which is a major attack vector in Objective-C. Since ``SEL`` values are1631not normally passed around as signed pointers, there is a1632:ref:`signing oracle<Signing Oracles>` associated with the initialization of the1633ivar, but the use of address and constant diversity limit the risks.1634 1635The implicit qualifier means that the type of the ivar does not match its1636declaration, which can cause type errors if the address of the ivar is taken:1637 1638.. code-block:: ObjC1639 1640  @interface A : NSObject {1641    SEL _s;1642  }1643  @end1644 1645  void f(SEL *);1646 1647  @implementation A1648  -(void)g1649  {1650     f(&_s);1651  }1652  @end1653 1654To fix such a mismatch the schema macro from `<ptrauth.h>`:1655 1656.. code-block:: ObjC1657 1658  #include <ptrauth.h>1659 1660  void f(SEL __ptrauth_objc_sel*);1661 1662or less safely, and introducing the possibility of an1663:ref:`signing or authentication oracle<Signing oracles>`, an unauthenticated1664temporary may be used as intermediate storage.1665 1666Alternative implementations1667---------------------------1668 1669Signature storage1670~~~~~~~~~~~~~~~~~1671 1672It is not critical for the security of pointer authentication that the1673signature be stored "together" with the pointer, as it is in Armv8.3. An1674implementation could just as well store the signature in a separate word, so1675that the ``sizeof`` a signed pointer would be larger than the ``sizeof`` a raw1676pointer.1677 1678Storing the signature in the high bits, as Armv8.3 does, has several trade-offs:1679 1680- Disadvantage: there are substantially fewer bits available for the signature,1681  weakening the mitigation by making it much easier for an attacker to simply1682  guess the correct signature.1683 1684- Disadvantage: future growth of the address space will necessarily further1685  weaken the mitigation.1686 1687- Advantage: memory layouts don't change, so it's possible for1688  pointer-authentication-enabled code (for example, in a system library) to1689  efficiently interoperate with existing code, as long as pointer1690  authentication can be disabled dynamically.1691 1692- Advantage: the size of a signed pointer doesn't grow, which might1693  significantly increase memory requirements, code size, and register pressure.1694 1695- Advantage: the size of a signed pointer is the same as a raw pointer, so1696  generic APIs which work in types like `void *` (such as `dlsym`) can still1697  return signed pointers.  This means that clients of these APIs will not1698  require insecure code in order to correctly receive a function pointer.1699 1700Hashing vs. encrypting pointers1701~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1702 1703Armv8.3 implements ``sign`` by computing a cryptographic hash and storing that1704in the spare bits of the pointer.  This means that there are relatively few1705possible values for the valid signed pointer, since the bits corresponding to1706the raw pointer are known.  Together with an ``auth`` oracle, this can make it1707computationally feasible to discover the correct signature with brute force.1708(The implementation should of course endeavor not to introduce ``auth``1709oracles, but this can be difficult, and attackers can be devious.)1710 1711If the implementation can instead *encrypt* the pointer during ``sign`` and1712*decrypt* it during ``auth``, this brute-force attack becomes far less1713feasible, even with an ``auth`` oracle.  However, there are several problems1714with this idea:1715 1716- It's unclear whether this kind of encryption is even possible without1717  increasing the storage size of a signed pointer.  If the storage size can be1718  increased, brute-force attacks can be equally well mitigated by simply storing1719  a larger signature.1720 1721- It would likely be impossible to implement a ``strip`` operation, which might1722  make debuggers and other out-of-process tools far more difficult to write, as1723  well as generally making primitive debugging more challenging.1724 1725- Implementations can benefit from being able to extract the raw pointer1726  immediately from a signed pointer.  An Armv8.3 processor executing an1727  ``auth``-and-load instruction can perform the load and ``auth`` in parallel;1728  a processor which instead encrypted the pointer would be forced to perform1729  these operations serially.1730