loader: use os apis for interacting with process memory

This commit is contained in:
Michael Scire 2022-04-17 18:51:36 -07:00
parent 1ac83a92e5
commit aecf739a7c
10 changed files with 188 additions and 15 deletions

View File

@ -25,6 +25,7 @@
#include <stratosphere/os/os_virtual_address_memory.hpp> #include <stratosphere/os/os_virtual_address_memory.hpp>
#include <stratosphere/os/os_native_handle.hpp> #include <stratosphere/os/os_native_handle.hpp>
#include <stratosphere/os/os_process_handle_api.hpp> #include <stratosphere/os/os_process_handle_api.hpp>
#include <stratosphere/os/os_process_memory_api.hpp>
#include <stratosphere/os/os_random.hpp> #include <stratosphere/os/os_random.hpp>
#include <stratosphere/os/os_mutex.hpp> #include <stratosphere/os/os_mutex.hpp>
#include <stratosphere/os/os_condition_variable.hpp> #include <stratosphere/os/os_condition_variable.hpp>

View File

@ -23,11 +23,13 @@ namespace ams::os {
constexpr inline size_t MemoryBlockUnitSize = 0x200000; constexpr inline size_t MemoryBlockUnitSize = 0x200000;
enum MemoryPermission { enum MemoryPermission {
MemoryPermission_None = (0 << 0), MemoryPermission_None = (0 << 0),
MemoryPermission_ReadOnly = (1 << 0), MemoryPermission_ReadOnly = (1 << 0),
MemoryPermission_WriteOnly = (1 << 1), MemoryPermission_WriteOnly = (1 << 1),
MemoryPermission_ExecuteOnly = (1 << 2),
MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly, MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly,
MemoryPermission_ReadExecute = MemoryPermission_ReadOnly | MemoryPermission_ExecuteOnly,
}; };
#if defined(ATMOSPHERE_OS_HORIZON) #if defined(ATMOSPHERE_OS_HORIZON)

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/os/os_native_handle.hpp>
#include <stratosphere/os/os_memory_common.hpp>
namespace ams::os {
Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size);
void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size);
Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm);
}

View File

@ -46,10 +46,10 @@ namespace ams::os::impl {
/* ... */ /* ... */
} }
uintptr_t AllocateSpace(size_t size) { uintptr_t AllocateSpace(size_t size, size_t align_offset) {
/* Try to allocate a large-aligned space, if we can. */ /* Try to allocate a large-aligned space, if we can. */
if (size >= AslrSpaceLargeAlign) { if (align_offset || size >= AslrSpaceLargeAlign) {
if (auto large_align = m_allocator.AllocateSpace(size, AslrSpaceLargeAlign, 0); large_align != 0) { if (auto large_align = m_allocator.AllocateSpace(size, AslrSpaceLargeAlign, align_offset & (AslrSpaceLargeAlign - 1)); large_align != 0) {
return large_align; return large_align;
} }
} }
@ -63,11 +63,11 @@ namespace ams::os::impl {
} }
template<typename MapFunction, typename UnmapFunction> template<typename MapFunction, typename UnmapFunction>
Result MapAtRandomAddress(uintptr_t *out, size_t size, MapFunction map_function, UnmapFunction unmap_function) { Result MapAtRandomAddress(uintptr_t *out, MapFunction map_function, UnmapFunction unmap_function, size_t size, size_t align_offset) {
/* Try to map up to 64 times. */ /* Try to map up to 64 times. */
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
/* Reserve space to map the memory. */ /* Reserve space to map the memory. */
const uintptr_t map_address = this->AllocateSpace(size); const uintptr_t map_address = this->AllocateSpace(size, align_offset);
if (map_address == 0) { if (map_address == 0) {
break; break;
} }

View File

@ -59,7 +59,7 @@ namespace ams::os::impl {
/* Map at a random address. */ /* Map at a random address. */
uintptr_t mapped_address; uintptr_t mapped_address;
R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address),
[handle, svc_perm](uintptr_t map_address, size_t map_size) -> Result { [handle, svc_perm](uintptr_t map_address, size_t map_size) -> Result {
R_TRY_CATCH(svc::MapIoRegion(handle, map_address, map_size, svc_perm)) { R_TRY_CATCH(svc::MapIoRegion(handle, map_address, map_size, svc_perm)) {
/* TODO: What's the correct result for these? */ /* TODO: What's the correct result for these? */
@ -73,7 +73,9 @@ namespace ams::os::impl {
}, },
[handle](uintptr_t map_address, size_t map_size) -> void { [handle](uintptr_t map_address, size_t map_size) -> void {
return IoRegionImpl::UnmapIoRegion(handle, reinterpret_cast<void *>(map_address), map_size); return IoRegionImpl::UnmapIoRegion(handle, reinterpret_cast<void *>(map_address), map_size);
} },
size,
0
)); ));
/* Return the address we mapped at. */ /* Return the address we mapped at. */

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::os::impl {
class ProcessMemoryImpl {
public:
static Result Map(void **out, NativeHandle handle, u64 process_address, size_t size);
static void Unmap(void *mapped_memory, NativeHandle handle, u64 process_address, size_t size);
static Result SetMemoryPermission(NativeHandle handle, u64 process_address, u64 size, MemoryPermission perm);
};
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "os_process_memory_impl.hpp"
#include "os_aslr_space_manager.hpp"
namespace ams::os::impl {
namespace {
svc::MemoryPermission ConvertToSvcMemoryPermission(os::MemoryPermission perm) {
switch (perm) {
case os::MemoryPermission_None: return svc::MemoryPermission_None;
case os::MemoryPermission_ReadOnly: return svc::MemoryPermission_Read;
case os::MemoryPermission_ReadWrite: return svc::MemoryPermission_ReadWrite;
case os::MemoryPermission_ReadExecute: return svc::MemoryPermission_ReadExecute;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
}
Result ProcessMemoryImpl::Map(void **out, NativeHandle handle, u64 process_address, size_t size) {
/* Map at a random address. */
uintptr_t mapped_address;
R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address),
[handle, process_address](uintptr_t map_address, size_t map_size) -> Result {
R_TRY_CATCH(svc::MapProcessMemory(map_address, handle, process_address, map_size)) {
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource())
R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState())
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
R_SUCCEED();
},
[handle, process_address](uintptr_t map_address, size_t map_size) -> void {
return ProcessMemoryImpl::Unmap(reinterpret_cast<void *>(map_address), handle, process_address, map_size);
},
size,
process_address
));
/* Return the address we mapped at. */
*out = reinterpret_cast<void *>(mapped_address);
R_SUCCEED();
}
void ProcessMemoryImpl::Unmap(void *mapped_memory, NativeHandle handle, u64 process_address, size_t size) {
R_ABORT_UNLESS(svc::UnmapProcessMemory(reinterpret_cast<uintptr_t>(mapped_memory), handle, process_address, size));
}
Result ProcessMemoryImpl::SetMemoryPermission(NativeHandle handle, u64 process_address, u64 size, MemoryPermission perm) {
/* Set the process memory permission. */
R_TRY_CATCH(svc::SetProcessMemoryPermission(handle, process_address, size, ConvertToSvcMemoryPermission(perm))) {
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource())
R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState())
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
R_SUCCEED();
}
}

View File

@ -59,7 +59,7 @@ namespace ams::os::impl {
/* Map at a random address. */ /* Map at a random address. */
uintptr_t mapped_address; uintptr_t mapped_address;
R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address),
[handle, svc_perm](uintptr_t map_address, size_t map_size) -> Result { [handle, svc_perm](uintptr_t map_address, size_t map_size) -> Result {
R_TRY_CATCH(svc::MapSharedMemory(handle, map_address, map_size, svc_perm)) { R_TRY_CATCH(svc::MapSharedMemory(handle, map_address, map_size, svc_perm)) {
R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState())
@ -69,7 +69,9 @@ namespace ams::os::impl {
}, },
[handle](uintptr_t map_address, size_t map_size) -> void { [handle](uintptr_t map_address, size_t map_size) -> void {
return SharedMemoryImpl::Unmap(handle, reinterpret_cast<void *>(map_address), map_size); return SharedMemoryImpl::Unmap(handle, reinterpret_cast<void *>(map_address), map_size);
} },
size,
0
)); ));
/* Return the address we mapped at. */ /* Return the address we mapped at. */

View File

@ -58,7 +58,7 @@ namespace ams::os::impl {
/* Map at a random address. */ /* Map at a random address. */
uintptr_t mapped_address; uintptr_t mapped_address;
R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address),
[handle, svc_owner_perm](uintptr_t map_address, size_t map_size) -> Result { [handle, svc_owner_perm](uintptr_t map_address, size_t map_size) -> Result {
R_TRY_CATCH(svc::MapTransferMemory(handle, map_address, map_size, svc_owner_perm)) { R_TRY_CATCH(svc::MapTransferMemory(handle, map_address, map_size, svc_owner_perm)) {
R_CONVERT(svc::ResultInvalidHandle, os::ResultInvalidHandle()) R_CONVERT(svc::ResultInvalidHandle, os::ResultInvalidHandle())
@ -71,7 +71,9 @@ namespace ams::os::impl {
}, },
[handle](uintptr_t map_address, size_t map_size) -> void { [handle](uintptr_t map_address, size_t map_size) -> void {
return TransferMemoryImpl::Unmap(handle, reinterpret_cast<void *>(map_address), map_size); return TransferMemoryImpl::Unmap(handle, reinterpret_cast<void *>(map_address), map_size);
} },
size,
0
)); ));
/* Return the address we mapped at. */ /* Return the address we mapped at. */

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "impl/os_process_memory_impl.hpp"
namespace ams::os {
Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size) {
R_RETURN(::ams::os::impl::ProcessMemoryImpl::Map(out, handle, process_address, process_size));
}
void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size) {
return ::ams::os::impl::ProcessMemoryImpl::Unmap(mapped_memory, handle, process_address, process_size);
}
Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm) {
R_RETURN(::ams::os::impl::ProcessMemoryImpl::SetMemoryPermission(handle, process_address, process_size, perm));
}
}