-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Description
#143230 introduces libunwind hardening which could be used with pauth-enabled ABIs (such as arm64e for Apple and pauthtest for Linux). This includes handling of signed return addresses. Both mentioned ABIs implicitly enable -fptrauth-returns flag, which sets __has_feature(ptrauth_returns) to true and triggers RA signing in codegen via setting "ptrauth-returns" attribute for functions in IR.
The existing logic in libunwind already handles signed RA - such handling was introduced previously to support signed RA appearing when -mbranch-protection=pac-ret is used:
llvm-project/libunwind/src/DwarfInstructions.hpp
Lines 303 to 344 in 3cb2174
| #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| // If the target is aarch64 then the return address may have been signed | |
| // using the v8.3 pointer authentication extensions. The original | |
| // return address needs to be authenticated before the return address is | |
| // restored. autia1716 is used instead of autia as autia1716 assembles | |
| // to a NOP on pre-v8.3a architectures. | |
| if ((R::getArch() == REGISTERS_ARM64) && | |
| isReturnAddressSigned(addressSpace, registers, cfa, prolog) && | |
| returnAddress != 0) { | |
| #if !defined(_LIBUNWIND_IS_NATIVE_ONLY) | |
| return UNW_ECROSSRASIGNING; | |
| #else | |
| register unsigned long long x17 __asm("x17") = returnAddress; | |
| register unsigned long long x16 __asm("x16") = cfa; | |
| // We use the hint versions of the authentication instructions below to | |
| // ensure they're assembled by the compiler even for targets with no | |
| // FEAT_PAuth/FEAT_PAuth_LR support. | |
| if (isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) { | |
| register unsigned long long x15 __asm("x15") = | |
| prolog.ptrAuthDiversifier; | |
| if (cieInfo.addressesSignedWithBKey) { | |
| asm("hint 0x27\n\t" // pacm | |
| "hint 0xe" | |
| : "+r"(x17) | |
| : "r"(x16), "r"(x15)); // autib1716 | |
| } else { | |
| asm("hint 0x27\n\t" // pacm | |
| "hint 0xc" | |
| : "+r"(x17) | |
| : "r"(x16), "r"(x15)); // autia1716 | |
| } | |
| } else { | |
| if (cieInfo.addressesSignedWithBKey) | |
| asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716 | |
| else | |
| asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716 | |
| } | |
| returnAddress = x17; | |
| #endif | |
| } | |
| #endif |
Note that existing implementation in libunwind supports different RA sign state in different stack frames. For example, we can build libunwind itself w/o pac-ret enabled, and build user code with pac-ret enabled, and unwinding would work fine since we look at RA sign state in each individual frame.
After #143230, signed RA handling looks as follows:
- If libunwind is built with pauth-enabled ABIs such as arm64e and pauthtest (which imply
__has_feature(ptrauth_calls) && __has_feature(ptrauth_returns), we skip old signed RA handling logic and use signed RA handling logic from [runtimes][PAC] Harden unwinding when possible #143230. - Otherwise, we use old signed RA handling logic.
Actual codegen is the same for -fptrauth-returns and -mbranch-protection=pac-ret, we just have different ways enabling that (see also #143230 (comment)).
We should unify logic in libunwind for these two cases as well.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status