kern: allocate the shadow stack
This commit is contained in:
@@ -119,6 +119,8 @@ namespace ams::kern {
|
||||
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
||||
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical
|
||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||
|
||||
KMemoryState_ShadowStack = ams::svc::MemoryState_ShadowStack,
|
||||
};
|
||||
|
||||
#if 1
|
||||
@@ -147,6 +149,7 @@ namespace ams::kern {
|
||||
static_assert(KMemoryState_CodeOut == 0x04402015);
|
||||
static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */
|
||||
static_assert(KMemoryState_Insecure == 0x055C3817);
|
||||
static_assert(KMemoryState_ShadowStack == 0x0000001A);
|
||||
#endif
|
||||
|
||||
enum KMemoryPermission : u8 {
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace ams::kern {
|
||||
class KProcess;
|
||||
class KConditionVariable;
|
||||
class KAddressArbiter;
|
||||
class KPageBuffer;
|
||||
|
||||
using KThreadFunction = void (*)(uintptr_t);
|
||||
|
||||
@@ -305,6 +306,8 @@ namespace ams::kern {
|
||||
u32 *m_light_ipc_data;
|
||||
KProcessAddress m_tls_address;
|
||||
void *m_tls_heap_address;
|
||||
KProcessAddress m_shadow_stack_address;
|
||||
KPageBuffer *m_shadow_stack_page;
|
||||
KLightLock m_activity_pause_lock;
|
||||
SyncObjectBuffer m_sync_object_buffer;
|
||||
s64 m_schedule_count;
|
||||
@@ -347,7 +350,7 @@ namespace ams::kern {
|
||||
: KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>(util::ConstantInitialize), KTimerTask(util::ConstantInitialize),
|
||||
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
|
||||
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
|
||||
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
|
||||
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_shadow_stack_address{Null<KProcessAddress>}, m_shadow_stack_page{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
|
||||
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{},
|
||||
m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
|
||||
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
|
||||
|
||||
@@ -214,6 +214,10 @@ namespace ams::kern {
|
||||
m_tls_address = 0;
|
||||
m_tls_heap_address = 0;
|
||||
|
||||
/* Set shadow stack address and page. */
|
||||
m_shadow_stack_address = Null<KProcessAddress>;
|
||||
m_shadow_stack_page = nullptr;
|
||||
|
||||
/* Set parent and condvar tree. */
|
||||
m_parent = nullptr;
|
||||
m_condvar_tree = nullptr;
|
||||
@@ -281,6 +285,29 @@ namespace ams::kern {
|
||||
R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address)));
|
||||
m_tls_heap_address = owner->GetThreadLocalRegionPointer(m_tls_address);
|
||||
std::memset(m_tls_heap_address, 0, ams::svc::ThreadLocalRegionSize);
|
||||
|
||||
/* If the owning process has a shadow stack, allocate and map a page for this thread. */
|
||||
if (owner->GetCreateProcessFlags() & ams::svc::CreateProcessFlag_EnableShadowStack) {
|
||||
/* Allocate the backing page. */
|
||||
KPageBuffer *page = KPageBuffer::AllocateChecked<PageSize>();
|
||||
if (page == nullptr) {
|
||||
owner->DeleteThreadLocalRegion(m_tls_address);
|
||||
m_tls_address = Null<KProcessAddress>;
|
||||
R_THROW(svc::ResultOutOfMemory());
|
||||
}
|
||||
|
||||
/* If we fail to map the page, free it and undo the TLS region we just created. */
|
||||
ON_RESULT_FAILURE {
|
||||
KPageBuffer::Free(page);
|
||||
owner->DeleteThreadLocalRegion(m_tls_address);
|
||||
m_tls_address = Null<KProcessAddress>;
|
||||
};
|
||||
|
||||
/* Map the page into the process's shadow stack region. */
|
||||
R_TRY(owner->GetPageTable().MapPages(std::addressof(m_shadow_stack_address), 1, PageSize, page->GetPhysicalAddress(), KMemoryState_ShadowStack, KMemoryPermission_UserReadWrite));
|
||||
|
||||
m_shadow_stack_page = page;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set parent, if relevant. */
|
||||
@@ -390,6 +417,12 @@ namespace ams::kern {
|
||||
m_parent->UnregisterThread(this);
|
||||
}
|
||||
|
||||
/* If the thread has a shadow stack, unmap and free its page. */
|
||||
if (m_shadow_stack_address != Null<KProcessAddress>) {
|
||||
MESOSPHERE_R_ABORT_UNLESS(m_parent->GetPageTable().UnmapPages(m_shadow_stack_address, 1, KMemoryState_ShadowStack));
|
||||
KPageBuffer::Free(m_shadow_stack_page);
|
||||
}
|
||||
|
||||
/* If the thread has a local region, delete it. */
|
||||
if (m_tls_address != Null<KProcessAddress>) {
|
||||
m_parent->DeleteThreadLocalRegion(m_tls_address);
|
||||
|
||||
Reference in New Issue
Block a user