arch/arm/arm64: Introduce Pointer Authentication support#369
arch/arm/arm64: Introduce Pointer Authentication support#369michpappas wants to merge 2 commits intounikraft:stagingfrom
Conversation
|
This PR depends on #368 |
|
Hey @michpappas, I did an initial pass of everything and the PR seems good! I will come back to it to test it once the other PR is merged. Cezar |
118cef0 to
b0412ce
Compare
|
Rebased and fixed a bug in the |
craciunoiuc
left a comment
There was a problem hiding this comment.
Hey @michpappas,
This PR looks good. I have just a small comment. After that I can approve it 🙂
| /* Macro to disable the global branch-protection settings for a specific | ||
| * function. This needs to be declared on any functions in the boot-chain | ||
| * up to the caller of ukplat_pauth_init() to avoid PAuth errors upon return. | ||
| */ | ||
| #if CONFIG_ARM64_FEAT_PAUTH | ||
| #define __no_branch_protection __attribute__((target("branch-protection=none"))) | ||
| #else | ||
| #define __no_branch_protection | ||
| #endif |
There was a problem hiding this comment.
I don't really get the #if brace here.
-
There might be other cases where branch protection needs to be disabled apart from the
PAUTHcase -
This macro is in the
pauth.hfile. It should be used only in the context ofpauthanyway.
There was a problem hiding this comment.
Hi @craciunoiuc,
- There might be other cases where branch protection needs to be disabled apart from the PAUTH case
Yes in general the branch-protection option can also be used for BTI, so my on-off logic was in the current scope of BTI not supported yet. But that should change soon, as I have a PR on BTI almost ready.
With BTI enabled the macro will have to include additional logic to take into account whether CONFIG_ARM64_FEAT_BTI is enabled or not, and change the value of branch-protection accordingly. Saying that, a more suitable name for that macro would be something like _no_pauth_prot or something similar.
- This macro is in the pauth.h file. It should be used only in the context of pauth anyway.
Well, it depends, one could include the header unconditionally, but overall I agree. Especially as GCC uses the same parameter for PAuth and BTI, this should probably be moved to a generic header.
I'll think about it a bit more as I work on the BTI PR. Will push an update soon.
Introduce a header for architecture-specific compiler definitions. Architectures add compiler definitions in uk/asm/compiler.h, which are made available through uk/essentials.h This commit adds empty headers for arm, arm64, and x86_64. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
b0412ce to
4d7db7d
Compare
Changes in this updateConfig.uk:
Makefile.uk:
compiler.h:
pauth.c:
pauth.h:
lcpu.h:
|
|
PR description and commit message updated based on latest changes. |
craciunoiuc
left a comment
There was a problem hiding this comment.
Hello again @michpappas,
The PR looks good now, but before adding my tag, here are some typos from the second commit message 😅:
"stored in registerers. The PAC" -> "stored in registers. The PAC"
"been tampered." -> "been tampered with."
"Pointer Authenticaiton" ->"Pointer Authentication"
"equired to" -> "required to"
After this, we can finally close this PR 😆.
| help | ||
| Enable signing and authentication of pointers. This | ||
| provides protections against classes of attacks that | ||
| rely on memory corruption, such as smash stacking and |
There was a problem hiding this comment.
| rely on memory corruption, such as smash stacking and | |
| rely on memory corruption, such as stack smashing and |
Pointer Authentication (FEAT_PAuth) allows signing and authenticating pointers to harden systems against classes of attacks that rely on memory corruption, such as stack smashing and ROP. Pointer Authentication Codes (PACs) are created by signing a pointer and a 64-bit modifier with an 128-bit key. The modifier is a value that is used to restrict the PAC to a specific context (eg the SP). Keys are stored in registers. The PAC is stored in the unused upper bits of the memory address, and can be later verified to ensure that the pointer has not been tampered with. This commit adds basic Pointer Authentication support for platforms that support arm64. Specifically, it introduces: - The CONFIG_ARM64_FEAT_PAUTH option. When enabled, GCC is instructed to generate PACIASP/RETAA sequences to protect the return address of functions using the PACIA_Key. - An API to set up and enable Pointer Authentication. Platforms are required to implement a key generation function that uses a secure source of randomness. - A macro to disable Pointer Authentication in certain functions. This is required on any returning function that is called prior to the initialization of Pointer Authentication. Unikraft images generated with FEAT_PAuth are compatible with architectures that implement Armv8.3 and above. That is due to the fact that, although the basic set of Pointer Authentication instructions is implemented in the NOP space, combined instructions and registers holding the keys are not. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
4d7db7d to
140af00
Compare
|
@craciunoiuc, typos are fixed now |
|
✅ Checkpatch passed Beep boop! I ran Unikraft's
|
razvand
left a comment
There was a problem hiding this comment.
@michpappas , this looks good. Before approving, please check the copyright information.
razvand
left a comment
There was a problem hiding this comment.
Approved-by: Razvan Deaconescu razvan.deaconescu@cs.pub.ro
Pointer Authentication (FEAT_PAuth) allows signing and authenticating pointers to harden systems against classes of attacks that rely on memory corruption, such as stack smashing and ROP. Pointer Authentication Codes (PACs) are created by signing a pointer and a 64-bit modifier with an 128-bit key. The modifier is a value that is used to restrict the PAC to a specific context (eg the SP). Keys are stored in registers. The PAC is stored in the unused upper bits of the memory address, and can be later verified to ensure that the pointer has not been tampered with. This commit adds basic Pointer Authentication support for platforms that support arm64. Specifically, it introduces: - The CONFIG_ARM64_FEAT_PAUTH option. When enabled, GCC is instructed to generate PACIASP/RETAA sequences to protect the return address of functions using the PACIA_Key. - An API to set up and enable Pointer Authentication. Platforms are required to implement a key generation function that uses a secure source of randomness. - A macro to disable Pointer Authentication in certain functions. This is required on any returning function that is called prior to the initialization of Pointer Authentication. Unikraft images generated with FEAT_PAuth are compatible with architectures that implement Armv8.3 and above. That is due to the fact that, although the basic set of Pointer Authentication instructions is implemented in the NOP space, combined instructions and registers holding the keys are not. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@gmail.com> Approved-by: Razvan Deaconescu <razvan.deaconescu@cs.pub.ro> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: #369
Prerequisite checklist
checkpatch.plon your commit series before opening this PR;Base target
Additional configuration
This PR introduces
CONFIG_ARM64_FEAT_PAUTHto enable Pointer Authentication support.Description of changes
Pointer Authentication (PAuth) allows signing and authenticating pointers to harden the system against classes of attacks that rely on the manipulation of pointers, such as ROP. Pointer Authentication Codes (PACs) are created by signing a pointer and a 64-bit modifier with an 128-bit key. The modifier is a value that is normally used to restrict the PAC to a specific context (eg the SP). Keys are stored in registerers.
The PAC is stored in the unused upper bits of the memory address, and can be later verified to ensure that the pointer has not been tampered.
The reference algorithm is the QARMA block cipher, but it is possible for architectures to use an IMPLEMENTATION DEFINED algorithm instead.
Basic Instructions:
Combined Instructions:
Keys:
For more background see:
Architecture support
Armv8.3:
Armv8.6. FEAT_PAuth2 changes the way the PAC is applied to the address
(XOR vs replace).
fails. FEAT_FPAC is an optional feature and depends on FEAT_PAuth2.
GCC support
GCC 7:
--msign-return-address=[none|non-leaf|all]The parameters passed to
--msign-return-addressare interpreted as:none: Do not sign return addressesnon-leaf: Sign/auth the return address of non-leaf functions.all: Sign/auth the return address of non-leaf and leaf functions.GCC implements the Basic Set of PAuth instructions using the HINT instruction, in the so-called NOP space. This allows executing protected binaries on older platforms that do not implement Armv8.3-a. In these platforms PAuth instructions
execute as NOP.
When
sign-return-addressis enabled without setting-march=armv8.3-a, GCC generates PACIASP / AUTIASP sequences that sign and authenticate the LR upon function entry and exit. In the following snippet notice the opcode of theHINT instruction (0xd5032300) that GCC generates for PACIASP and AUTIASP.
When
-msign-return-addressis used along with-march=armv8.3-a, GCCgenerates PACIASP / RETAA sequences instead. In the snippet below notice the
opcode of RETAA (0xd65f0bff) which is in the fused space (instructions in the
Combined Set do not have HINT implementations). Clearly, this code cannot be
executed in architectures earlier than Armv8.3-a.
GCC 9:
-msign-return-address-mbranch-protection=[none|pac-ret{+leaf}|bti|standard]--enable-standard-branch-protectionas a short tombranch-protection=standardThe parameters passed to
-mbranch-protectionare interpreted as:none: Disables all protectionspac-ret: Enables PAuth for function returns on non-leaf functions. The+leafmodifier enables protection for leaf functions.bti: Enables Branch Target Identificationstandard: Enables all protectionsGCC 10:
--mbranch-protection.This allows using the APIB_Key instead of the APIA_Key when signing
return pointers.
Changes introduced in this series
This PR provides platforms with an API to initialize PAuth keys, and enable PAuth.
A platform can initialize PAuth as:
To generate PAyth keys, it is required that platforms provide an implementation of the key generation function that uses an adequate source of randomness.
Platforms that support Armv8.5 can use the random number generation instructions introduced into the architecture (
RNDR/RNDRSS). Others can initialize drivers of an HWRNG/TRNG, or request randomness from the TEE.Since the above functions are used for the initialization of PAuth, it is required that GCC excludes them when generating PACIASP/RETAA sequences. Otherwise, once PAuth is enabled, authentication will fail upon return. A macro is provided to help overriding the global gcc settings per function:
This macro is used by
pauth_enable(), and should be used by all functions generated by GCC in the boot chain, up to - and including - the caller ofpauth_init().Additionally to the above, the following choices are made:
Do not enable backwards compatibility mode.
If
-march=armv8.3-ais not set, it is not possible to initialize the keys.GCC exits with the following error:
I believe that Arm's intention behind compatibility mode was mostly to provide backwards compatibility on userspace libraries. Clearly on Unikraft this feature cannot be utilized, except from the case of linking with prebuilt libraries.
Because of that this PR sets
-march=armv8.3-awhen enablingCONFIG_ARM64_FEAT_PAUTH.Enable leaf protection by default
Although it's not strictly required as leaf functions do not save the LR, it doesn't hurt to be there as an additional protection.
Initialize only the PACIA_Key
The motivation for that is minimizing the impact on boot time. Additional keys can be enabled later, if needed.
Do not introduce additional APIs for sign / auth / strip
The intention of this PR is to provide initial PAuth support. As such, its scope is limited to the signing and verification of the function return address. Nevertheless, Pointer Authentication provides the possibility to harden the system further by signing more pointers. Additional functionality can be introduced into the Unkraft API later, on demand.