-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libunwind, c18n: Support backtrace/exceptions.
- Loading branch information
Showing
19 changed files
with
897 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
contrib/subrepo-cheri-libunwind/src/CompartmentInfo.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
// | ||
// Abstracts unwind information when used with a compartmentalizing runtime | ||
// linker. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef __COMPARTMENT_INFO_HPP__ | ||
#define __COMPARTMENT_INFO_HPP__ | ||
|
||
#include "AddressSpace.hpp" | ||
|
||
#if defined(__CHERI_PURE_CAPABILITY__) | ||
namespace libunwind { | ||
template <typename A> | ||
class _LIBUNWIND_HIDDEN CompartmentInfo { | ||
typedef typename A::capability_t capability_t; | ||
public: | ||
static const uintcap_t kInvalidRCSP = (uintcap_t)0; | ||
// Per-architecture trusted stack frame layout. | ||
#if defined(_LIBUNWIND_TARGET_AARCH64) | ||
static const uint32_t kOldSPOffset = 48; | ||
static const uint32_t kNextOffset = 32; | ||
static const uint32_t kFPOffset = 0; | ||
static const uint32_t kCalleeSavedOffset = 64; | ||
static const uint32_t kCalleeSavedCount = 10; | ||
static const uint32_t kCalleeSavedSize = 16; | ||
static const uint32_t kReturnAddressOffset = 40; | ||
static const uint32_t kPCOffset = 16; | ||
// kCalleeSavedCount - 1 because kCalleeSavedOffset is the first one. | ||
static const uint32_t kTrustedFrameSize = | ||
kCalleeSavedOffset + (kCalleeSavedCount - 1) * kCalleeSavedSize; | ||
#else | ||
#error "Unsupported architecture for compartmentalization" | ||
#endif | ||
private: | ||
// CompartmentInfo understands how compartments are represented when running | ||
// with a sandboxing runtime linker and is responsible for simulating how the | ||
// runtime linker juggles restricted stacks. | ||
// | ||
// If _LIBUNWIND_SANDBOX_HARDENED is specified, the table pointer will always | ||
// be sealed so that the caller cannot access it. | ||
// | ||
// XXX: Have this call into rtld to get a notion of a "compartent ID" as | ||
// opposed to understanding how rtld juggles stacks under the hood? | ||
struct StackTableEntry { | ||
uintcap_t key = kInvalidRCSP; | ||
uintcap_t value = kInvalidRCSP; | ||
StackTableEntry *next = nullptr; | ||
}; | ||
static const uint32_t kStackTableSize = 1 << 10; // XXX: Is this a good size? | ||
static const uint32_t kStackTableMask = kStackTableSize - 1; | ||
// stackTable : start of restricted stack -> top of next caller's stack | ||
StackTableEntry *stackTable; | ||
A &addressSpace; | ||
#if defined(_LIBUNWIND_SANDBOX_OTYPES) | ||
public: | ||
CompartmentInfo(A &as) : addressSpace(as) { | ||
stackTable = | ||
(StackTableEntry *)malloc(kStackTableSize * sizeof(StackTableEntry)); | ||
// FIXME: Calling abort() here might be unacceptable. In fact, allocating | ||
// memory here in general might be unacceptable, especially on and targets | ||
// that don't need to use this. | ||
if (stackTable == nullptr) | ||
_LIBUNWIND_ABORT("failed to allocate stack table in CompartmentInfo"); | ||
memset(stackTable, 0, sizeof(StackTableEntry) * kStackTableSize); | ||
#ifdef _LIBUNWIND_SANDBOX_HARDENED | ||
capability_t sealer = addressSpace.getUnwindSealer(); | ||
if (sealer != addressSpace.to_capability_t(-1)) | ||
stackTable = __builtin_cheri_seal(stackTable, sealer); | ||
#endif | ||
CHERI_DBG("allocated new stack table: %#p\n", (void *)stackTable); | ||
} | ||
~CompartmentInfo() { reset(); } | ||
|
||
private: | ||
static uint32_t stackHash(uintcap_t stack) { | ||
ptraddr_t stackAddr = (ptraddr_t)stack; | ||
return stackAddr & kStackTableMask; | ||
} | ||
StackTableEntry *findStack(uintcap_t startOfRCSP) { | ||
uint32_t hashIndex = stackHash(startOfRCSP); | ||
CHERI_DBG("findStack(): hashIndex = %u\n", hashIndex); | ||
assert(hashIndex < kStackTableSize); | ||
#ifdef _LIBUNWIND_SANDBOX_HARDENED | ||
capability_t sealer = addressSpace.getUnwindSealer(); | ||
StackTableEntry *unsealedTable = __builtin_cheri_unseal(stackTable, sealer); | ||
#else | ||
StackTableEntry *unsealedTable = stackTable; | ||
#endif | ||
StackTableEntry *entry = &unsealedTable[hashIndex]; | ||
assert(entry != nullptr); | ||
CHERI_DBG("findStack(): looking for 0x%lx\n", (ptraddr_t)startOfRCSP); | ||
while (entry && entry->key != startOfRCSP) { | ||
CHERI_DBG("findStack(): entry->key = 0x%lx\n", (ptraddr_t)entry->key); | ||
entry = entry->next; | ||
} | ||
return entry; | ||
} | ||
bool insertNewStack(uintcap_t k, uintcap_t v) { | ||
uint32_t hashIndex = stackHash(k); | ||
#ifdef _LIBUNWIND_SANDBOX_HARDENED | ||
capability_t sealer = addressSpace.getUnwindSealer(); | ||
StackTableEntry *unsealedTable = __builtin_cheri_unseal(stackTable, sealer); | ||
#else | ||
StackTableEntry *unsealedTable = stackTable; | ||
#endif | ||
StackTableEntry *entry = &unsealedTable[hashIndex]; | ||
if (entry == nullptr) | ||
_LIBUNWIND_ABORT("failed to allocate a stack table entry"); | ||
if (entry->key == kInvalidRCSP) { | ||
entry->key = k; | ||
entry->value = v; | ||
return true; | ||
} | ||
while (entry->next) { | ||
entry = entry->next; | ||
} | ||
StackTableEntry *newEntry = | ||
(StackTableEntry *)malloc(sizeof(StackTableEntry)); | ||
newEntry->key = k; | ||
newEntry->value = v; | ||
newEntry->next = nullptr; | ||
entry->next = newEntry; | ||
CHERI_DBG("insertNewStack(): 0x%lx ==> 0x%lx\n", (ptraddr_t)k, | ||
(ptraddr_t)v); | ||
return true; | ||
} | ||
|
||
public: | ||
uintcap_t getAndUpdateRestrictedStack(uintcap_t startOfRCSP, | ||
uintcap_t oldCallerSPTop, | ||
uintcap_t nextRCSP) { | ||
CHERI_DBG("getAndUpdateRestrictedStack(0x%lx, 0x%lx)\n", | ||
(ptraddr_t)startOfRCSP, (ptraddr_t)nextRCSP); | ||
StackTableEntry *entry = findStack(startOfRCSP); | ||
if (entry == nullptr) { | ||
// If there is no entry in our table for a given restricted stack, we will | ||
// simply return nextRCSP which the runtime linker gave us. | ||
CHERI_DBG("stack not found in compartment info, adding 0x%lx ==> 0x%lx\n", | ||
(ptraddr_t)startOfRCSP, (ptraddr_t)oldCallerSPTop); | ||
insertNewStack(startOfRCSP, oldCallerSPTop); | ||
return nextRCSP; | ||
} | ||
// There's already an entry for the restricted stack. Return the next | ||
// restricted stack we expect to unwind or resume from and update the value | ||
// to the next one. | ||
uintcap_t stackToReturn = entry->value; | ||
entry->value = oldCallerSPTop; | ||
CHERI_DBG("getAndUpdateRestrictedStack(): return 0x%lx\n", | ||
(ptraddr_t)stackToReturn); | ||
return stackToReturn; | ||
} | ||
void reset(void) { | ||
// Reinitialize the table to 0 and free everything | ||
#ifdef _LIBUNWIND_SANDBOX_HARDENED | ||
capability_t sealer = addressSpace.getUnwindSealer(); | ||
stackTable = __builtin_cheri_unseal(stackTable, sealer); | ||
#endif | ||
for (size_t i = 0; i < kStackTableSize; i++) { | ||
StackTableEntry *entry = &stackTable[i]; | ||
assert(entry != nullptr); | ||
StackTableEntry *heapEntry = entry->next; | ||
while (heapEntry) { | ||
StackTableEntry *temp = heapEntry; | ||
heapEntry = heapEntry->next; | ||
free(temp); | ||
} | ||
} | ||
free(stackTable); | ||
} | ||
#else // _LIBUNWIND_SANDBOX_OTYPES | ||
public: | ||
CompartmentInfo(A &as) : addressSpace(as) {} | ||
#endif // _LIBUNWIND_SANDBOX_OTYPES | ||
}; | ||
} // namespace libunwind | ||
#endif // __CHERI_PURE_CAPABILITY__ | ||
#endif // __COMPARTMENT_INFO_HPP__ |
Oops, something went wrong.