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_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
||||||
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical
|
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical
|
||||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
|
KMemoryState_ShadowStack = ams::svc::MemoryState_ShadowStack,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
@@ -147,6 +149,7 @@ namespace ams::kern {
|
|||||||
static_assert(KMemoryState_CodeOut == 0x04402015);
|
static_assert(KMemoryState_CodeOut == 0x04402015);
|
||||||
static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */
|
static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */
|
||||||
static_assert(KMemoryState_Insecure == 0x055C3817);
|
static_assert(KMemoryState_Insecure == 0x055C3817);
|
||||||
|
static_assert(KMemoryState_ShadowStack == 0x0000001A);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum KMemoryPermission : u8 {
|
enum KMemoryPermission : u8 {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace ams::kern {
|
|||||||
class KProcess;
|
class KProcess;
|
||||||
class KConditionVariable;
|
class KConditionVariable;
|
||||||
class KAddressArbiter;
|
class KAddressArbiter;
|
||||||
|
class KPageBuffer;
|
||||||
|
|
||||||
using KThreadFunction = void (*)(uintptr_t);
|
using KThreadFunction = void (*)(uintptr_t);
|
||||||
|
|
||||||
@@ -305,6 +306,8 @@ namespace ams::kern {
|
|||||||
u32 *m_light_ipc_data;
|
u32 *m_light_ipc_data;
|
||||||
KProcessAddress m_tls_address;
|
KProcessAddress m_tls_address;
|
||||||
void *m_tls_heap_address;
|
void *m_tls_heap_address;
|
||||||
|
KProcessAddress m_shadow_stack_address;
|
||||||
|
KPageBuffer *m_shadow_stack_page;
|
||||||
KLightLock m_activity_pause_lock;
|
KLightLock m_activity_pause_lock;
|
||||||
SyncObjectBuffer m_sync_object_buffer;
|
SyncObjectBuffer m_sync_object_buffer;
|
||||||
s64 m_schedule_count;
|
s64 m_schedule_count;
|
||||||
@@ -347,7 +350,7 @@ namespace ams::kern {
|
|||||||
: KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>(util::ConstantInitialize), KTimerTask(util::ConstantInitialize),
|
: 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_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_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_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_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{},
|
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_address = 0;
|
||||||
m_tls_heap_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. */
|
/* Set parent and condvar tree. */
|
||||||
m_parent = nullptr;
|
m_parent = nullptr;
|
||||||
m_condvar_tree = nullptr;
|
m_condvar_tree = nullptr;
|
||||||
@@ -281,6 +285,29 @@ namespace ams::kern {
|
|||||||
R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address)));
|
R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address)));
|
||||||
m_tls_heap_address = owner->GetThreadLocalRegionPointer(m_tls_address);
|
m_tls_heap_address = owner->GetThreadLocalRegionPointer(m_tls_address);
|
||||||
std::memset(m_tls_heap_address, 0, ams::svc::ThreadLocalRegionSize);
|
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. */
|
/* Set parent, if relevant. */
|
||||||
@@ -390,6 +417,12 @@ namespace ams::kern {
|
|||||||
m_parent->UnregisterThread(this);
|
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 the thread has a local region, delete it. */
|
||||||
if (m_tls_address != Null<KProcessAddress>) {
|
if (m_tls_address != Null<KProcessAddress>) {
|
||||||
m_parent->DeleteThreadLocalRegion(m_tls_address);
|
m_parent->DeleteThreadLocalRegion(m_tls_address);
|
||||||
|
|||||||
Reference in New Issue
Block a user