Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] riscv: Add sysarch(2) support for utidc #2142

Closed
wants to merge 12 commits into from
Closed
2 changes: 1 addition & 1 deletion bin/cheribsdtest/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SUBDIR+= purecap \
purecap-dynamic-mt \
purecap-mt

.if ${MACHINE_CPUARCH} == "aarch64" && ${MACHINE_ABI:Mpurecap}
.if ${MACHINE_ABI:Mpurecap}
SUBDIR+= mt-c18n
.endif
.endif
Expand Down
2 changes: 1 addition & 1 deletion bin/cheribsdtest/cheribsdtest_registers.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
(CHERI_PERMS_SWALL & ~CHERI_PERM_SW_VMEM));

/* Check that the raw permission bits match the kernel header: */
#if defined(CHERIBSD_C18N_TESTS) && !defined(__ARM_MORELLO_PURECAP_BENCHMARK_ABI)
#if defined(CHERIBSD_C18N_TESTS) && defined(__aarch64__) && !defined(__ARM_MORELLO_PURECAP_BENCHMARK_ABI)

Check warning on line 175 in bin/cheribsdtest/cheribsdtest_registers.c

View workflow job for this annotation

GitHub Actions / Style Checker

line over 80 characters
if (v != (CHERI_CAP_USER_CODE_PERMS & ~CHERI_PERM_EXECUTIVE))
cheribsdtest_failure_errx("perms %jx (expected %jx)", v,
(uintmax_t)(CHERI_CAP_USER_CODE_PERMS & ~CHERI_PERM_EXECUTIVE));
Expand Down
5 changes: 0 additions & 5 deletions contrib/subrepo-cheri-libunwind/include/__libunwind_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,4 @@
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
#endif // _LIBUNWIND_IS_NATIVE_ONLY

#if defined(_LIBUNWIND_CHERI_C18N_SUPPORT) && \
!defined(_LIBUNWIND_TARGET_AARCH64)
# error "LIBUNWIND_CHERI_C18N_SUPPORT is only supported on Morello"
#endif

#endif // ____LIBUNWIND_CONFIG_H__
24 changes: 0 additions & 24 deletions contrib/subrepo-cheri-libunwind/src/AddressSpace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,6 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace {
return get<v128>(addr);
}
capability_t getCapability(pint_t addr) { return get<capability_t>(addr); }
#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
static pint_t getUnwindSealer();
static bool isValidSealer(pint_t sealer) {
return __builtin_cheri_tag_get(sealer);
}
#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT
__attribute__((always_inline))
uintptr_t getP(pint_t addr);
uint64_t getRegister(pint_t addr);
Expand Down Expand Up @@ -415,24 +409,6 @@ inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
#endif
}

#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
extern "C" {
/// Call into the RTLD to get a sealer capability. This sealer will be used to
/// seal information in the unwinding context.
uintptr_t _rtld_unw_getsealer();
uintptr_t __rtld_unw_getsealer();
_LIBUNWIND_HIDDEN uintptr_t __rtld_unw_getsealer() {
return (uintptr_t)0;
}
_LIBUNWIND_WEAK_ALIAS(__rtld_unw_getsealer, _rtld_unw_getsealer)
}

/// C++ wrapper for calling into RTLD.
inline LocalAddressSpace::pint_t LocalAddressSpace::getUnwindSealer() {
return _rtld_unw_getsealer();
}
#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT

/// Read a ULEB128 into a 64-bit word.
inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
const uint8_t *p = (uint8_t *)addr;
Expand Down
78 changes: 65 additions & 13 deletions contrib/subrepo-cheri-libunwind/src/CompartmentInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,72 @@
#define __COMPARTMENT_INFO_HPP__

namespace libunwind {
class _LIBUNWIND_HIDDEN CompartmentInfo {
public:
#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
static CompartmentInfo sThisCompartmentInfo;
// Per-architecture trusted stack frame layout.

extern "C" {

struct trusted_frame;

// Must mirror the layout in rtld_c18n_machdep.h
#if defined(_LIBUNWIND_TARGET_AARCH64)
static const uint32_t kNewSPOffset = 12 * sizeof(void *);
static const uint32_t kNextOffset = 14 * sizeof(void *);
static const uint32_t kCalleeSavedOffset = 2 * sizeof(void *);
static const uint32_t kCalleeSavedCount = 10;
static const uint32_t kReturnAddressOffset = 15 * sizeof(void *) + 8;
static const uint32_t kPCOffset = sizeof(void *);
#endif // _LIBUNWIND_TARGET_AARCH64
#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT
struct compart_state {
void *fp;
void *pc;
void *regs[10]; // c19 to c28
void *sp;
};
#else
# error "LIBUNWIND_CHERI_C18N_SUPPORT is not supported on this target"
#endif

#pragma weak c18n_is_enabled
bool c18n_is_enabled(void) {
return false;
};

#pragma weak c18n_is_tramp
bool c18n_is_tramp(ptraddr_t, struct trusted_frame *);

#pragma weak c18n_pop_trusted_stk
struct trusted_frame *
c18n_pop_trusted_stk(struct compart_state *, struct trusted_frame *);
}

template <typename A, typename R>
struct CompartmentInfo {
typedef typename A::pint_t pint_t;

static bool isC18NEnabled() {
return c18n_is_enabled();
}

static bool isC18NTramp(pint_t pc, pint_t tf) {
return c18n_is_tramp(pc, (struct trusted_frame *)tf);
}

static pint_t fillC18NState(R &newRegisters, pint_t tf) {
struct compart_state state;
tf = (pint_t)c18n_pop_trusted_stk(&state, (struct trusted_frame *)tf);

newRegisters.setTrustedStack(tf);
CHERI_DBG("C18N: SET TRUSTED STACK %#p\n", (void *)tf);

newRegisters.setFP((pint_t)state.fp);
CHERI_DBG("C18N: SET FP %#p\n", state.fp);

newRegisters.setSP((pint_t)state.sp);
CHERI_DBG("C18N: SET SP: %#p\n", state.sp);

for (size_t i = 0; i < sizeof(state.regs) / sizeof(*state.regs); ++i) {
newRegisters.setCapabilityRegister(UNW_ARM64_C19 + i,
(pint_t)state.regs[i]);
CHERI_DBG("C18N: SET REGISTER: %lu (%s): %#p\n",
UNW_ARM64_C19 + i,
newRegisters.getRegisterName(UNW_ARM64_C19 + i),
state.regs[i]);
}

return (pint_t)state.pc;
}
};
} // namespace libunwind
#endif // __COMPARTMENT_INFO_HPP__
101 changes: 10 additions & 91 deletions contrib/subrepo-cheri-libunwind/src/DwarfInstructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#include "Registers.hpp"
#include "DwarfParser.hpp"
#include "config.h"
#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
#include "CompartmentInfo.hpp"
#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT


namespace libunwind {
Expand Down Expand Up @@ -55,14 +57,6 @@ class DwarfInstructions {
typedef typename CFI_Parser<A>::FDE_Info FDE_Info;
typedef typename CFI_Parser<A>::CIE_Info CIE_Info;

#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
static pint_t restoreRegistersFromSandbox(pint_t csp, A &addressSpace,
R &newRegisters,
CompartmentInfo &CI, pint_t sealer);
static bool isCompartmentTransitionTrampoline(pint_t ecsp, A &addressSpace,
CompartmentInfo &CI,
pint_t returnAddress);
#endif
static pint_t evaluateExpression(pint_t expression, A &addressSpace,
const R &registers,
pint_t initialStackValue);
Expand Down Expand Up @@ -105,6 +99,9 @@ class DwarfInstructions {
static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
PrologInfo &prolog);
#endif
#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
static constexpr CompartmentInfo<A, R> CompartInfo{};
#endif
};

template <typename R>
Expand Down Expand Up @@ -255,75 +252,6 @@ bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
}
#endif

#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
#if defined(_LIBUNWIND_TARGET_AARCH64)
template <typename A, typename R>
typename A::pint_t DwarfInstructions<A, R>::restoreRegistersFromSandbox(
pint_t csp, A &addressSpace, R &newRegisters, CompartmentInfo &CI,
pint_t sealer) {
// Get the unsealed executive CSP
assert(__builtin_cheri_tag_get((void *)csp) &&
"Executive stack should be tagged!");
// Derive the new executive CSP
pint_t nextCSP = addressSpace.getP(csp + CI.kNextOffset);
// Seal ECSP
nextCSP = __builtin_cheri_seal(nextCSP, sealer);
assert(__builtin_cheri_tag_get((void *)nextCSP) &&
"Next executive stack should be tagged!");
CHERI_DBG("SANDBOX: SETTING EXECUTIVE CSP %#p\n", (void *)nextCSP);
newRegisters.setTrustedStack(nextCSP);
// Restore the next RCSP
pint_t nextRCSP = addressSpace.getP(csp + CI.kNewSPOffset);
newRegisters.setSP(nextRCSP);
CHERI_DBG("SANDBOX: SETTING RESTRICTED CSP: %#p\n",
(void *)newRegisters.getSP());
// Restore callee-saved registers
// Restore: c19-c28
for (size_t i = 0, offset = CI.kCalleeSavedOffset; i < CI.kCalleeSavedCount;
++i, offset += sizeof(void *)) {
pint_t regValue = addressSpace.getP(csp + offset);
newRegisters.setCapabilityRegister(UNW_ARM64_C19 + i, regValue);
CHERI_DBG("SETTING CALLEE SAVED CAPABILITY REGISTER: %lu (%s): %#p "
"(offset=%zu)\n",
UNW_ARM64_C19 + i,
newRegisters.getRegisterName(UNW_ARM64_C19 + i), (void *)regValue,
offset);
}
// Restore the frame pointer
pint_t newFP = addressSpace.getP(csp);
CHERI_DBG("SANDBOX: SETTING CFP %#p\n", (void *)newFP);
newRegisters.setFP(newFP);
// Get the new return address.
return addressSpace.getP(csp + CI.kPCOffset);
}

template <typename A, typename R>
bool DwarfInstructions<A, R>::isCompartmentTransitionTrampoline(
pint_t ecsp, A &addressSpace, CompartmentInfo &CI, pint_t returnAddress) {
ptraddr_t expectedReturnAddress =
addressSpace.template get<ptraddr_t>(ecsp + CI.kReturnAddressOffset);
CHERI_DBG(
"isCompartmentTransitionTrampoline(): expectedReturnAddress: 0x%lx\n",
expectedReturnAddress);
return expectedReturnAddress == returnAddress;
}
#else // _LIBUNWIND_TARGET_AARCH64
template <typename A, typename R>
typename A::pint_t DwarfInstructions<A, R>::restoreRegistersFromSandbox(
pint_t csp, A &addressSpace, R &newRegisters, CompartmentInfo &CI,
pint_t sealer) {
assert(0 && "not implemented on this architecture");
return (pint_t)0;
}
template <typename A, typename R>
bool DwarfInstructions<A, R>::isCompartmentTransitionTrampoline(
pint_t ecsp, A &addressSpace, CompartmentInfo &CI, pint_t returnAddress) {
assert(0 && "not implemented on this architecture");
return false;
}
#endif // _LIBUNWIND_TARGET_AARCH64
#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT

template <typename A, typename R>
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pc_t pc,
pint_t fdeStart, R &registers,
Expand Down Expand Up @@ -484,23 +412,14 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pc_t pc,
#endif

#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT)
// If the sealer is not valid (only the case when we're running without
// c18n), check if the return address has the executive mode bit set.
// If so, we should be calling into the c18n RTLD as this is a
// compartment boundary. We need to restore registers from the executive
// stack and ask rtld for it.
uintptr_t sealer = addressSpace.getUnwindSealer();
if (addressSpace.isValidSealer(sealer)) {
// If c18n is enabled, check if we are at a compartment boundary. If so,
// restore registers from the trusted stack by asking rtld for them.
if (CompartInfo.isC18NEnabled()) {
pint_t csp = registers.getTrustedStack();
if (__builtin_cheri_sealed_get(csp))
csp = __builtin_cheri_unseal(csp, sealer);
CompartmentInfo &CI = CompartmentInfo::sThisCompartmentInfo;
if (csp != 0 && isCompartmentTransitionTrampoline(csp, addressSpace, CI,
returnAddress)) {
if (CompartInfo.isC18NTramp(returnAddress, csp)) {
CHERI_DBG("%#p: detected a trampoline, unwinding from sandbox\n",
(void *)returnAddress);
returnAddress = restoreRegistersFromSandbox(
csp, addressSpace, newRegisters, CI, sealer);
returnAddress = CompartInfo.fillC18NState(newRegisters, csp);
}
}
#endif
Expand Down
40 changes: 11 additions & 29 deletions contrib/subrepo-cheri-libunwind/src/UnwindRegistersRestore.S
Original file line number Diff line number Diff line change
Expand Up @@ -703,25 +703,6 @@ Lnovec:

#elif defined(__aarch64__)

//
// extern "C" void __rtld_unw_setcontext(void *c0, void *c1,
// void *rcsp, void **sealed_ecsp);
//
#if defined(__CHERI_PURE_CAPABILITY__)
DEFINE_LIBUNWIND_FUNCTION(__rtld_unw_setcontext)
mov c16, c2
ldp c2, c3, [c3, #(-0x210 + 0x20)]
mov csp, c16
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
and x30, x30, #~1
ret x30
#else
ret
#endif
END_LIBUNWIND_FUNCTION(__rtld_unw_setcontext)
WEAK_ALIAS(__rtld_unw_setcontext, _rtld_unw_setcontext)
#endif

//
// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
//
Expand All @@ -731,8 +712,12 @@ WEAK_ALIAS(__rtld_unw_setcontext, _rtld_unw_setcontext)
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
#ifdef __CHERI_PURE_CAPABILITY__
ldr c1, [c0, #0x1f0] // Pass the target untrusted stack pointer
ldr c2, [c0, #0x210] // Pass the target trusted stack pointer
bl c18n_unwind_trusted_stk

// skip restore of c0,c1 for now
// also skip restoring c2 and c3 because they will get clobbered later on
ldp c2, c3, [c0, #0x020]
ldp c4, c5, [c0, #0x040]
ldp c6, c7, [c0, #0x060]
ldp c8, c9, [c0, #0x080]
Expand Down Expand Up @@ -772,17 +757,14 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
// context struct, because it is allocated on the stack, and an exception
// could clobber the de-allocated portion of the stack after csp has been
// restored.
ldr c2, [c0, #0x1f0]
add c3, c0, #0x210
ldp c0, c1, [c0, #0x000]
// XXX: variant PCS is not yet supported by rtld, work around it
// using a function pointer.
adrp c16, :got:_rtld_unw_setcontext
ldr c16, [c16, :got_lo12:_rtld_unw_setcontext]
ldr c16, [c0, #0x1f0]
ldp c0, c1, [c0, #0x000] // restore c0,c1
mov csp,c16 // restore csp
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
br x16
and x30, x30, #~1
ret x30 // jump to pc
#else
br c16
ret // jump to pcc
#endif
#else
// skip restore of x0,x1 for now
Expand Down
22 changes: 14 additions & 8 deletions contrib/subrepo-cheri-libunwind/src/UnwindRegistersSave.S
Original file line number Diff line number Diff line change
Expand Up @@ -837,13 +837,19 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)

#elif defined(__aarch64__)

#if defined(__CHERI_PURE_CAPABILITY__)
DEFINE_LIBUNWIND_FUNCTION(__rtld_unw_getcontext)
mov c2, csp
str c2, [c1]
ret c30
END_LIBUNWIND_FUNCTION(__rtld_unw_getcontext)
WEAK_ALIAS(__rtld_unw_getcontext, _rtld_unw_getcontext)
#ifdef __CHERI_PURE_CAPABILITY__
DEFINE_LIBUNWIND_FUNCTION(_c18n_noop)
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
and x30, x30, #~1
ret x30
#else
ret
#endif
END_LIBUNWIND_FUNCTION(_c18n_noop)
// uintptr_t c18n_get_trusted_stk(uintptr_t, struct trusted_frame **);
WEAK_ALIAS(_c18n_noop, c18n_get_trusted_stk)
// uintptr_t c18n_unwind_trusted_stk(uintptr_t, void *, struct trusted_frame *);
WEAK_ALIAS(_c18n_noop, c18n_unwind_trusted_stk)
#endif

//
Expand Down Expand Up @@ -898,7 +904,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
str d30, [c0, #0x0f0]
str d31, [c0, #0x0f8]
mov x0, #0 // return UNW_ESUCCESS
b _rtld_unw_getcontext
b c18n_get_trusted_stk
#else
stp x0, x1, [x0, #0x000]
stp x2, x3, [x0, #0x010]
Expand Down
Loading
Loading