kern: reject shadow stack accesses in syscalls
This commit is contained in:
@@ -100,8 +100,8 @@ namespace ams::kern {
|
|||||||
KProcessPageTable &target_pt = process->GetPageTable();
|
KProcessPageTable &target_pt = process->GetPageTable();
|
||||||
|
|
||||||
/* Verify that the regions are in range. */
|
/* Verify that the regions are in range. */
|
||||||
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(debugger_pt.IsSafeUserPointer(buffer, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Iterate over the target process's memory blocks. */
|
/* Iterate over the target process's memory blocks. */
|
||||||
KProcessAddress cur_address = address;
|
KProcessAddress cur_address = address;
|
||||||
@@ -166,8 +166,8 @@ namespace ams::kern {
|
|||||||
KProcessPageTable &target_pt = process->GetPageTable();
|
KProcessPageTable &target_pt = process->GetPageTable();
|
||||||
|
|
||||||
/* Verify that the regions are in range. */
|
/* Verify that the regions are in range. */
|
||||||
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(debugger_pt.IsSafeUserPointer(buffer, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Iterate over the target process's memory blocks. */
|
/* Iterate over the target process's memory blocks. */
|
||||||
KProcessAddress cur_address = address;
|
KProcessAddress cur_address = address;
|
||||||
|
|||||||
@@ -3205,7 +3205,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
Result KPageTableBase::CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
|
Result KPageTableBase::CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
|
||||||
/* Lightly validate the range before doing anything else. */
|
/* Lightly validate the range before doing anything else. */
|
||||||
R_UNLESS(this->Contains(src_addr, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->IsSafeUserPointer(src_addr, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Copy the memory. */
|
/* Copy the memory. */
|
||||||
{
|
{
|
||||||
@@ -3354,7 +3354,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
Result KPageTableBase::CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) {
|
Result KPageTableBase::CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) {
|
||||||
/* Lightly validate the range before doing anything else. */
|
/* Lightly validate the range before doing anything else. */
|
||||||
R_UNLESS(this->Contains(dst_addr, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->IsSafeUserPointer(dst_addr, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Copy the memory. */
|
/* Copy the memory. */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsKernelAddress(uintptr_t address) {
|
constexpr bool IsValidAddress(uintptr_t address) {
|
||||||
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
|
if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false;
|
||||||
|
if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsValidSignalType(ams::svc::SignalType type) {
|
constexpr bool IsValidSignalType(ams::svc::SignalType type) {
|
||||||
@@ -50,7 +52,7 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||||
/* Validate input. */
|
/* Validate input. */
|
||||||
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidCurrentMemory());
|
||||||
if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) {
|
if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) {
|
||||||
R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress());
|
R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress());
|
||||||
} else {
|
} else {
|
||||||
@@ -79,7 +81,7 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
Result SignalToAddress(uintptr_t address, ams::svc::SignalType signal_type, int32_t value, int32_t count) {
|
Result SignalToAddress(uintptr_t address, ams::svc::SignalType signal_type, int32_t value, int32_t count) {
|
||||||
/* Validate input. */
|
/* Validate input. */
|
||||||
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
||||||
R_UNLESS(IsValidSignalType(signal_type), svc::ResultInvalidEnumValue());
|
R_UNLESS(IsValidSignalType(signal_type), svc::ResultInvalidEnumValue());
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace ams::kern::svc {
|
|||||||
R_SUCCEED_IF(size == 0);
|
R_SUCCEED_IF(size == 0);
|
||||||
|
|
||||||
/* Validate that the region is within range. */
|
/* Validate that the region is within range. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(address, size), svc::ResultInvalidCurrentMemory()); /* did N intend ResultInvalidPointer like everywhere else? */
|
||||||
|
|
||||||
/* Flush the cache. */
|
/* Flush the cache. */
|
||||||
R_TRY(cpu::FlushDataCache(reinterpret_cast<void *>(address), size));
|
R_TRY(cpu::FlushDataCache(reinterpret_cast<void *>(address), size));
|
||||||
|
|||||||
@@ -21,13 +21,15 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsKernelAddress(uintptr_t address) {
|
constexpr bool IsValidAddress(uintptr_t address) {
|
||||||
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
|
if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false;
|
||||||
|
if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WaitProcessWideKeyAtomic(uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns) {
|
Result WaitProcessWideKeyAtomic(uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns) {
|
||||||
/* Validate input. */
|
/* Validate input. */
|
||||||
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidPointer());
|
||||||
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
||||||
|
|
||||||
/* Convert timeout from nanoseconds to ticks. */
|
/* Convert timeout from nanoseconds to ticks. */
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ namespace ams::kern::svc {
|
|||||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||||
|
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_info.GetUnsafePointer()), sizeof(EventInfoType)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Get the debug object. */
|
/* Get the debug object. */
|
||||||
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
|
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
|
||||||
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
@@ -139,6 +141,8 @@ namespace ams::kern::svc {
|
|||||||
/* Verify that the number of thread ids is valid. */
|
/* Verify that the number of thread ids is valid. */
|
||||||
R_UNLESS((0 <= num_thread_ids && num_thread_ids <= MaximumDebuggableThreadCount), svc::ResultOutOfRange());
|
R_UNLESS((0 <= num_thread_ids && num_thread_ids <= MaximumDebuggableThreadCount), svc::ResultOutOfRange());
|
||||||
|
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_thread_ids.GetUnsafePointer()), num_thread_ids * sizeof(uint64_t)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Copy the threads from userspace. */
|
/* Copy the threads from userspace. */
|
||||||
uint64_t thread_ids[MaximumDebuggableThreadCount];
|
uint64_t thread_ids[MaximumDebuggableThreadCount];
|
||||||
if (num_thread_ids > 0) {
|
if (num_thread_ids > 0) {
|
||||||
@@ -172,6 +176,8 @@ namespace ams::kern::svc {
|
|||||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||||
|
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Validate the context flags. */
|
/* Validate the context flags. */
|
||||||
R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue());
|
R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue());
|
||||||
|
|
||||||
@@ -193,6 +199,8 @@ namespace ams::kern::svc {
|
|||||||
/* Only allow invoking the svc on development hardware. */
|
/* Only allow invoking the svc on development hardware. */
|
||||||
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
|
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
|
||||||
|
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Validate the context flags. */
|
/* Validate the context flags. */
|
||||||
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
|
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
|
||||||
{
|
{
|
||||||
@@ -243,6 +251,8 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result QueryDebugProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uint64_t address) {
|
Result QueryDebugProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uint64_t address) {
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_memory_info.GetUnsafePointer()), sizeof(T)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Get an ams::svc::MemoryInfo for the region. */
|
/* Get an ams::svc::MemoryInfo for the region. */
|
||||||
ams::svc::MemoryInfo info = {};
|
ams::svc::MemoryInfo info = {};
|
||||||
R_TRY(QueryDebugProcessMemory(std::addressof(info), out_page_info, debug_handle, address));
|
R_TRY(QueryDebugProcessMemory(std::addressof(info), out_page_info, debug_handle, address));
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace ams::kern::svc {
|
|||||||
R_SUCCEED_IF(len == 0);
|
R_SUCCEED_IF(len == 0);
|
||||||
|
|
||||||
/* Ensure that the data being output is in range. */
|
/* Ensure that the data being output is in range. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Output the string. */
|
/* Output the string. */
|
||||||
R_RETURN(KDebugLog::PrintUserString(debug_str, len));
|
R_RETURN(KDebugLog::PrintUserString(debug_str, len));
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace ams::kern::svc {
|
|||||||
/* Copy user handles. */
|
/* Copy user handles. */
|
||||||
if (num_handles > 0) {
|
if (num_handles > 0) {
|
||||||
/* Ensure that we can try to get the handles. */
|
/* Ensure that we can try to get the handles. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Get the handles. */
|
/* Get the handles. */
|
||||||
R_TRY(user_handles.CopyArrayTo(handles, num_handles));
|
R_TRY(user_handles.CopyArrayTo(handles, num_handles));
|
||||||
|
|||||||
@@ -21,13 +21,15 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsKernelAddress(uintptr_t address) {
|
constexpr bool IsValidAddress(uintptr_t address) {
|
||||||
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
|
if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false;
|
||||||
|
if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ArbitrateLock(ams::svc::Handle thread_handle, uintptr_t address, uint32_t tag) {
|
Result ArbitrateLock(ams::svc::Handle thread_handle, uintptr_t address, uint32_t tag) {
|
||||||
/* Validate the input address. */
|
/* Validate the input address. */
|
||||||
R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(IsValidAddress(address), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress());
|
R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress());
|
||||||
|
|
||||||
R_RETURN(KConditionVariable::WaitForAddress(thread_handle, address, tag));
|
R_RETURN(KConditionVariable::WaitForAddress(thread_handle, address, tag));
|
||||||
@@ -35,7 +37,7 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
Result ArbitrateUnlock(uintptr_t address) {
|
Result ArbitrateUnlock(uintptr_t address) {
|
||||||
/* Validate the input address. */
|
/* Validate the input address. */
|
||||||
R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(IsValidAddress(address), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress());
|
R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress());
|
||||||
|
|
||||||
R_RETURN(KConditionVariable::SignalToAddress(address));
|
R_RETURN(KConditionVariable::SignalToAddress(address));
|
||||||
|
|||||||
@@ -21,11 +21,22 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static Result GetPortName(char (&name)[KObjectName::NameLengthMax], KUserPointer<const char *> user_name) {
|
||||||
|
/* Copy the provided name from user memory to kernel memory. */
|
||||||
|
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
|
||||||
|
|
||||||
|
/* Oddly enough N here first copies then validates if it's not in forbidden range. */
|
||||||
|
const auto name_len = util::Strnlen(name, sizeof(name));
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_name.GetUnsafePointer()), name_len + 1), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result ManageNamedPort(ams::svc::Handle *out_server_handle, KUserPointer<const char *> user_name, s32 max_sessions) {
|
Result ManageNamedPort(ams::svc::Handle *out_server_handle, KUserPointer<const char *> user_name, s32 max_sessions) {
|
||||||
/* Copy the provided name from user memory to kernel memory. */
|
/* Copy the provided name from user memory to kernel memory. */
|
||||||
char name[KObjectName::NameLengthMax] = {};
|
char name[KObjectName::NameLengthMax] = {};
|
||||||
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
|
R_TRY(GetPortName(name, user_name));
|
||||||
|
|
||||||
/* Validate that sessions and name are valid. */
|
/* Validate that sessions and name are valid. */
|
||||||
R_UNLESS(max_sessions >= 0, svc::ResultOutOfRange());
|
R_UNLESS(max_sessions >= 0, svc::ResultOutOfRange());
|
||||||
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());
|
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());
|
||||||
@@ -106,7 +117,7 @@ namespace ams::kern::svc {
|
|||||||
Result ConnectToNamedPort(ams::svc::Handle *out, KUserPointer<const char *> user_name) {
|
Result ConnectToNamedPort(ams::svc::Handle *out, KUserPointer<const char *> user_name) {
|
||||||
/* Copy the provided name from user memory to kernel memory. */
|
/* Copy the provided name from user memory to kernel memory. */
|
||||||
char name[KObjectName::NameLengthMax] = {};
|
char name[KObjectName::NameLengthMax] = {};
|
||||||
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
|
R_TRY(GetPortName(name, user_name));
|
||||||
|
|
||||||
/* Validate that name is valid. */
|
/* Validate that name is valid. */
|
||||||
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());
|
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
/* Validate that the pointer is in range. */
|
/* Validate that the pointer is in range. */
|
||||||
if (max_out_count > 0) {
|
if (max_out_count > 0) {
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the process list. */
|
/* Get the process list. */
|
||||||
@@ -128,7 +128,7 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS(((num_caps * sizeof(u32)) / sizeof(u32)) == static_cast<size_t>(num_caps), svc::ResultInvalidPointer());
|
R_UNLESS(((num_caps * sizeof(u32)) / sizeof(u32)) == static_cast<size_t>(num_caps), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Validate that the pointer is in range. */
|
/* Validate that the pointer is in range. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate that the parameter flags are valid. */
|
/* Validate that the parameter flags are valid. */
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace ams::kern::svc {
|
|||||||
/* Validate that the mapping is in range. */
|
/* Validate that the mapping is in range. */
|
||||||
auto &page_table = process->GetPageTable();
|
auto &page_table = process->GetPageTable();
|
||||||
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
/* Map the memory. */
|
/* Map the memory. */
|
||||||
R_TRY(page_table.MapCodeMemory(dst_address, src_address, size));
|
R_TRY(page_table.MapCodeMemory(dst_address, src_address, size));
|
||||||
@@ -175,7 +175,7 @@ namespace ams::kern::svc {
|
|||||||
/* Validate that the mapping is in range. */
|
/* Validate that the mapping is in range. */
|
||||||
auto &page_table = process->GetPageTable();
|
auto &page_table = process->GetPageTable();
|
||||||
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
/* Unmap the memory. */
|
/* Unmap the memory. */
|
||||||
R_TRY(page_table.UnmapCodeMemory(dst_address, src_address, size));
|
R_TRY(page_table.UnmapCodeMemory(dst_address, src_address, size));
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result QueryProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) {
|
Result QueryProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) {
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_memory_info.GetUnsafePointer()), sizeof(T)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Get an ams::svc::MemoryInfo for the region. */
|
/* Get an ams::svc::MemoryInfo for the region. */
|
||||||
ams::svc::MemoryInfo info = {};
|
ams::svc::MemoryInfo info = {};
|
||||||
R_TRY(QueryProcessMemory(std::addressof(info), out_page_info, process_handle, address));
|
R_TRY(QueryProcessMemory(std::addressof(info), out_page_info, process_handle, address));
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace ams::kern::svc {
|
|||||||
/* Copy user handles. */
|
/* Copy user handles. */
|
||||||
if (num_handles > 0) {
|
if (num_handles > 0) {
|
||||||
/* Ensure that we can try to get the handles. */
|
/* Ensure that we can try to get the handles. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Get the handles. */
|
/* Get the handles. */
|
||||||
R_TRY(user_handles.CopyArrayTo(handles, num_handles));
|
R_TRY(user_handles.CopyArrayTo(handles, num_handles));
|
||||||
|
|||||||
@@ -204,6 +204,8 @@ namespace ams::kern::svc {
|
|||||||
/* Get the thread from its handle. */
|
/* Get the thread from its handle. */
|
||||||
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle);
|
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle);
|
||||||
R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle());
|
R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer());
|
||||||
|
|
||||||
/* Require the handle be to a non-current thread in the current process. */
|
/* Require the handle be to a non-current thread in the current process. */
|
||||||
R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle());
|
R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle());
|
||||||
@@ -228,7 +230,7 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
/* Validate that the pointer is in range. */
|
/* Validate that the pointer is in range. */
|
||||||
if (max_out_count > 0) {
|
if (max_out_count > 0) {
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the handle table. */
|
/* Get the handle table. */
|
||||||
|
|||||||
Reference in New Issue
Block a user