[llvm-dev] [RFC] Pointer authentication for arm64e
John McCall via llvm-dev
llvm-dev at lists.llvm.org
Mon Oct 21 14:50:05 PDT 2019
Hello, LLVM. Apple would like to upstream our implementation of pointer
authentication in LLVM, Clang, and Swift. Pointer authentication is a
language technology which mitigates the security impact of certain kinds
of memory corruption. Principally, it provides a control-flow integrity
(CFI) check which can be implemented at low enough cost that it is
feasible to protect all indirect control flow in the language ABI,
making exploit techniques such as ROP/JOP substantially more difficult.
There are three closely-related terms that readers should know:
* Pointer authentication is a general language technology for signing
and authenticating pointers, protecting against arbitrary replacement by
an attacker. It is not inherently tied to specific hardware or software
* ARMv8.3 is a revision of ARM’s AArch64 architecture that describes
efficient hardware support for pointer authentication. Apple chips have
included this technology since the Apple A12 used in (e.g.) the iPhone
XR and XS.
* arm64e is a specific ABI for pointer authentication in C, C++,
Objective-C, and Swift. It is used on iOS 12+ on systems that provide
ARMv8.3, as well as several other Apple OSes. This ABI is not yet
considered “stable” for third-party use because some of the details
are still evolving. Indeed, part of our goal in open-sourcing this work
is to receive feedback to help improve this ABI.
Pointer authentication is described in detail in the language
documentation, which can temporarily be found here:
We encourage contributors who are deeply interested in this subject to
read that document, which goes in depth into the basic mechanisms of
pointer authentication, their theory of operation, and how they are used
(and exposed for customization) in the four supported programming
languages. For the convenience of reviewers, we’ll also briefly
summarize the main points right now:
* Signing a pointer means computing a cryptographic signature of the
pointer value (not the pointed-to contents) which will be passed along
with the pointer. Signing is generally done when constructing the
pointer, e.g. when taking the address of a function.
* Authenticating a pointer means checking that the passed-along
cryptographic signature is correct. Authentication is generally done
when using a pointer, e.g. when calling an opaque function pointer.
* In ARMv8.3, the signature is stored in the unused high bits of a
64-bit pointer. The number of bits can be adjusted by the operating
system depending on the address-space needs of the system.
* Pointer authentication assumes that an attacker cannot reliably
duplicate the signing step to forge a signed pointer. In ARMv8.3, this
is achieved by incorporating data from private key registers that only
the kernel can access.
* Preventing signature forgery is not enough to prevent reliable
exploitation because attackers can still replace validly-signed pointers
with other signed pointers. This can be blocked by signing pointers
with a discriminator value that is, ideally, unique for the specific
purpose at hand.
* Under pointer authentication, all function pointers are signed, as
well as specific data pointers that are important for protecting the
control flow of the program.
* Language ABIs specify which key register to use and how to compute the
discriminator for any particular signed pointer.
We will also be giving a talk on this work at the LLVM Developer’s
At the LLVM level, pointer authentication requires several different
* basic code-generation support for the ARMv8.3 instructions, which was
contributed to LLVM several years ago by ARM;
* intrinsics to sign, resign, and (unsafely) authenticate pointers, as
well as several other operations;
* the ability to perform an authenticated call, which we’re
representing with a special operand bundle on call sites, which the
optimizer must be made aware of at various points;
* the ability to perform other authenticated operations, such as loads
and stores, which we’re representing using separate auth intrinsics;
* signed pointer constants that can be stored in global memory; and
* special changes to various aspects of AArch64 code-generation, such as
switch lowering and tail calls, in order to avoid creating opportunities
for exploits with over-aggressive scheduling.
Some of the LLVM representations we’re currently using are
problematic, usually because they allow the compiler to break up
critical sequences of code and potentially introduce vulnerabilities.
We’d like to figure out better representations to avoid these
problems, and we intend to start conversations on llvm-dev about them as
they come up in the individual patches. In the short term, however,
we’d like to land what we’ve currently got. These problems are
discussed in depth in the Clang language documentation as well as
covered in our LLVM talk.
At the Clang level, pointer authentication builds on that work:
* Several new builtins have been added to expose the underlying
intrinsic operations; this includes a new <ptrauth.h> header.
* Abstractions for representing a pointer signature have been introduced
* IRGen’s FunctionPointer abstraction now requires signing information
for indirect calls.
* Various places throughout IRGen have been improved to sign and
* There is a new __ptrauth type qualifier to make working with signed
pointers easier. The qualifier can include the storage address in the
discriminator; when added to a struct field, this forces the struct to
be passed indirectly and requires copying the struct to be non-trivial.
Basic support for handling C structs with these restrictions was already
introduced into Clang in order to support structs with Objective-C
__strong and __weak fields.
We also expect substantial future developments in Clang, both to improve
the default pointer-signing rules for various language features and to
add new language features to allow programmers to opt in to stronger
protections for their code.
All of these changes have been broken down into a relatively
fine-grained sequence of patches which we’ll be submitting
individually for review. If you’d like to “skip ahead”, the
entire patch sequence can be found here:
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the llvm-dev