diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h index 1e55d33975f3..b073c38dcb68 100644 --- a/libunwind/include/__libunwind_config.h +++ b/libunwind/include/__libunwind_config.h @@ -18,7 +18,11 @@ #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116 +#ifdef RTLD_SANDBOX +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MORELLO 230 +#else #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MORELLO 229 +#endif #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 @@ -72,9 +76,15 @@ # elif defined(__aarch64__) # define _LIBUNWIND_TARGET_AARCH64 1 # if defined(__CHERI_PURE_CAPABILITY__) -# define _LIBUNWIND_CONTEXT_SIZE 100 +# if defined(RTLD_SANDBOX) +# define _LIBUNWIND_CONTEXT_SIZE 102 +# else +# define _LIBUNWIND_CONTEXT_SIZE 100 +# endif # if defined(__SEH__) # error "Pure-capability aarch64 SEH not supported" +# elif defined(RTLD_SANDBOX) +# define _LIBUNWIND_CURSOR_SIZE 126 # else # define _LIBUNWIND_CURSOR_SIZE 124 # endif diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index 87fdd395dee1..96d4e509a161 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -675,7 +675,8 @@ enum { UNW_ARM64_C30 = 228, UNW_ARM64_CLR = 228, UNW_ARM64_C31 = 229, - UNW_ARM64_CSP = 229 + UNW_ARM64_CSP = 229, + UNW_ARM64_CCSP = 230 }; // 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index 17a9e153a1ff..d88779cdf507 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -21,6 +21,9 @@ #include "DwarfParser.hpp" #include "config.h" +#ifdef __CHERI_PURE_CAPABILITY__ +#include +#endif namespace libunwind { @@ -365,6 +368,20 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, } #endif +#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) + // If the return address is in Executive mode, then it is almost certainly + // pointing to a trampoline. The only exception is when the current PCC is + // also running in Executive mode, that is, when it is already running an + // RTLD function. We ignore this case for now. + if ((cheri_getperm(returnAddress) & CHERI_PERM_EXECUTIVE) != 0) { + uintcap_t ccsp = registers.getCapabilityRegister(UNW_ARM64_CCSP); + newRegisters.setRegister( + UNW_ARM64_CCSP, addressSpace.getCapability(ccsp)); + returnAddress = addressSpace.getCapability(ccsp + 16); + newRegisters.setSP(addressSpace.getCapability(ccsp + 32)); + } +#endif + // Return address is address after call site instruction, so setting IP to // that does simualates a return. newRegisters.setIP(returnAddress); diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index d50978579a83..f0e749813cb9 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -1868,6 +1868,9 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { uintptr_t __lr; // Link register r30 uintptr_t __sp; // Stack pointer r31 uintptr_t __pc; // Program counter +#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) + uintptr_t __csp; // Executive stack pointer +#endif uint64_t __ra_sign_state; // RA sign state register }; @@ -1884,8 +1887,13 @@ inline Registers_arm64::Registers_arm64(const void *registers) { "arm64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); #ifdef __CHERI_PURE_CAPABILITY__ - static_assert(sizeof(GPRs) == 0x220, - "expected VFP registers to be at offset 544"); + #ifdef RTLD_SANDBOX + static_assert(sizeof(GPRs) == 0x230, + "expected VFP registers to be at offset 560"); + #else + static_assert(sizeof(GPRs) == 0x220, + "expected VFP registers to be at offset 544"); + #endif #else static_assert(sizeof(GPRs) == 0x110, "expected VFP registers to be at offset 272"); @@ -1910,6 +1918,8 @@ inline bool Registers_arm64::validRegister(int regNum) const { #ifdef __CHERI_PURE_CAPABILITY__ if ((regNum >= UNW_ARM64_C0) && (regNum <= UNW_ARM64_C31)) return true; + if (regNum == UNW_ARM64_CCSP) + return true; #endif if (regNum > 95) return false; @@ -1936,6 +1946,10 @@ inline uintptr_t Registers_arm64::getRegister(int regNum) const { #ifdef __CHERI_PURE_CAPABILITY__ if ((regNum >= UNW_ARM64_C0) && (regNum <= UNW_ARM64_C31)) return _registers.__x[regNum - UNW_ARM64_C0]; +#ifdef RTLD_SANDBOX + if (regNum == UNW_ARM64_CCSP) + return _registers.__csp; +#endif #endif _LIBUNWIND_ABORT("unsupported arm64 register"); } @@ -1956,6 +1970,10 @@ inline void Registers_arm64::setRegister(int regNum, uintptr_t value) { #ifdef __CHERI_PURE_CAPABILITY__ else if ((regNum >= UNW_ARM64_C0) && (regNum <= UNW_ARM64_C31)) _registers.__x[regNum - UNW_ARM64_C0] = value; +#ifdef RTLD_SANDBOX + else if (regNum == UNW_ARM64_CCSP) + _registers.__csp = value; +#endif #endif else _LIBUNWIND_ABORT("unsupported arm64 register"); @@ -1969,6 +1987,8 @@ inline bool Registers_arm64::validCapabilityRegister(int regNum) const { return true; if ((regNum >= UNW_ARM64_C0) && (regNum <= UNW_ARM64_C31)) return true; + if (regNum == UNW_ARM64_CCSP) + return true; return false; } @@ -2184,6 +2204,8 @@ inline const char *Registers_arm64::getRegisterName(int regNum) { return "clr"; case UNW_ARM64_C31: return "csp"; + case UNW_ARM64_CCSP: + return "ccsp"; default: return "unknown register"; } diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index 3eed33d63675..f5b3ece1ca96 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -663,6 +663,13 @@ Lnovec: #elif defined(__aarch64__) +#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) +DEFINE_LIBUNWIND_FUNCTION(__rtld_unw_setcontext) + ret +END_LIBUNWIND_FUNCTION(__rtld_unw_setcontext) +WEAK_ALIAS(__rtld_unw_setcontext, _rtld_unw_setcontext) +#endif + // // extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); // @@ -688,9 +695,17 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) ldp c24,c25, [c0, #0x180] ldp c26,c27, [c0, #0x1a0] ldp c28,c29, [c0, #0x1c0] +#ifdef RTLD_SANDBOX + add c0, c0, #0x210 + // Restore Executive stack pointer here + bl _rtld_unw_setcontext + ldr c30, [c0, #-0x10] // restore pcc into clr + sub c0, c0, #0x210 + add c16,c0, #0x230 +#else ldr c30, [c0, #0x200] // restore pcc into clr - add c16,c0, #0x220 +#endif ldp d0, d1, [c16, #0x000] ldp d2, d3, [c16, #0x010] ldp d4, d5, [c16, #0x020] diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 17840df26b70..f88fee90a57c 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -824,6 +824,13 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #elif defined(__aarch64__) +#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) +DEFINE_LIBUNWIND_FUNCTION(__rtld_unw_getcontext) + ret +END_LIBUNWIND_FUNCTION(__rtld_unw_getcontext) +WEAK_ALIAS(__rtld_unw_getcontext, _rtld_unw_getcontext) +#endif + // // extern int __unw_getcontext(unw_context_t* thread_state) // @@ -848,12 +855,20 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) stp c24,c25, [c0, #0x180] stp c26,c27, [c0, #0x1a0] stp c28,c29, [c0, #0x1c0] - str c30, [c0, #0x1e0] - mov c1,csp - str c1, [c0, #0x1f0] + mov c1, csp + stp c30,c1, [c0, #0x1e0] str c30, [c0, #0x200] // store return address as pcc +#ifdef RTLD_SANDBOX + add c0, c0, #0x210 + // Store Executive stack pointer here + bl _rtld_unw_getcontext + ldr c30, [c0, #-0x10] + // skip cpsr + add c0, c0, #0x20 +#else // skip cpsr add c0, c0, #0x220 +#endif stp d0, d1, [c0, #0x000] stp d2, d3, [c0, #0x010] stp d4, d5, [c0, #0x020]