Skip to content

Commit

Permalink
[PAuthLR] Add support for FEAT_PAuth_LR to libunwind
Browse files Browse the repository at this point in the history
This introduces support for unwinding programs where return addresses
have been signed using FEAT_PAuth_Lr, where the value of PC is used as
a diversifier (-mbranch-protection=pac-ret+pc).

A new vendor specific call frame instruction is added,
named `DW_CFA_AARCH64_negate_ra_state_with_pc`, to instruct the unwinder
tocapture the value of PC at the point of signing and update bit 1 of
the existing `RA_SIGN_STATE` pseudo-register to flag the need to use it
for authentication.

See ARM-software/abi-aa#245 for the ABI change.

Authored-by: pratlucas <[email protected]>
  • Loading branch information
Stylie777 committed Oct 14, 2024
1 parent 7fc3491 commit ef8f52e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 13 deletions.
54 changes: 42 additions & 12 deletions libunwind/src/DwarfInstructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ class DwarfInstructions {
__builtin_unreachable();
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
PrologInfo &prolog);
static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa,
PrologInfo &prolog);
static bool isReturnAddressSignedWithPC(A &addressSpace, R registers,
pint_t cfa, PrologInfo &prolog);
#endif
};

Expand Down Expand Up @@ -173,8 +175,9 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
template <typename A, typename R>
bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
pint_t cfa, PrologInfo &prolog) {
bool DwarfInstructions<A, R>::isReturnAddressSigned(A &addressSpace,
R registers, pint_t cfa,
PrologInfo &prolog) {
pint_t raSignState;
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
Expand All @@ -185,6 +188,22 @@ bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
// Only bit[0] is meaningful.
return raSignState & 0x01;
}

template <typename A, typename R>
bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
R registers,
pint_t cfa,
PrologInfo &prolog) {
pint_t raSignState;
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
raSignState = static_cast<pint_t>(regloc.value);
else
raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);

// Only bit[1] is meaningful.
return raSignState & 0x02;
}
#endif

template <typename A, typename R>
Expand Down Expand Up @@ -288,21 +307,32 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
if ((R::getArch() == REGISTERS_ARM64) &&
getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
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;

// These are the autia1716/autib1716 instructions. The hint instructions
// are used here as gcc does not assemble autia1716/autib1716 for pre
// armv8.3a targets.
if (cieInfo.addressesSignedWithBKey)
asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
else
asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
// 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
}
Expand Down
20 changes: 20 additions & 0 deletions libunwind/src/DwarfParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class CFI_Parser {
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
#if defined(_LIBUNWIND_TARGET_AARCH64)
pint_t ptrAuthDiversifier;
#endif
enum class InitializeTime { kLazy, kNormal };

// When saving registers, this data structure is lazily initialized.
Expand Down Expand Up @@ -799,6 +802,23 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
}
break;

#if defined(_LIBUNWIND_TARGET_AARCH64)
case DW_CFA_AARCH64_negate_ra_state_with_pc: {
int64_t value =
results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
initialState);
// When calucating the value of the PC, it is assumed that the CFI instruction
// is placed before the signing instruction, however it is placed after. Because
// of this, we need to take into account the CFI instruction is one instruction
// call later than expected, and reduce the PC value by 4 bytes to compensate.
results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
static_cast<uint64_t>(results->ptrAuthDiversifier));
}
break;
#endif

#else
(void)arch;
#endif
Expand Down
3 changes: 2 additions & 1 deletion libunwind/src/dwarf2.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ enum {
DW_CFA_GNU_negative_offset_extended = 0x2F,

// AARCH64 extensions
DW_CFA_AARCH64_negate_ra_state = 0x2D
DW_CFA_AARCH64_negate_ra_state_with_pc = 0x2C,
DW_CFA_AARCH64_negate_ra_state = 0x2D
};


Expand Down

0 comments on commit ef8f52e

Please sign in to comment.