core: never create executable host memory for guest pages
This commit is contained in:
parent
5aa8c4c727
commit
3b0328da62
5 changed files with 18 additions and 39 deletions
|
|
@ -63,6 +63,9 @@ size_t page_size();
|
|||
// This is likely 64KiB.
|
||||
size_t allocation_granularity();
|
||||
|
||||
// Statically recompiled guest code executes from the host image, never from
|
||||
// guest pages, so the execute variants only describe guest-side intent: the
|
||||
// platform allocators serve them without the host execute bit (W^X).
|
||||
enum class PageAccess {
|
||||
kNoAccess = 0,
|
||||
kReadOnly = 1 << 0,
|
||||
|
|
@ -82,16 +85,6 @@ enum class DeallocationType {
|
|||
kDecommit = 1 << 1,
|
||||
};
|
||||
|
||||
// Whether the host allows the pages to be allocated or mapped with
|
||||
// PageAccess::kExecuteReadWrite - if not, separate mappings backed by the same
|
||||
// memory-mapped file must be used to write to executable pages.
|
||||
bool IsWritableExecutableMemorySupported();
|
||||
|
||||
// Whether PageAccess::kExecuteReadWrite is a supported and preferred way of
|
||||
// writing executable memory, useful for simulating how Xenia would work without
|
||||
// writable executable memory on a system with it.
|
||||
bool IsWritableExecutableMemoryPreferred();
|
||||
|
||||
// Allocates a block of memory at the given page-aligned base address.
|
||||
// Fails if the memory is not available.
|
||||
// Specify nullptr for base_address to leave it up to the system.
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ REXCVAR_DECLARE(bool, kernel_debug_monitor);
|
|||
REXCVAR_DECLARE(bool, kernel_cert_monitor);
|
||||
REXCVAR_DECLARE(bool, ignore_thread_priorities);
|
||||
REXCVAR_DECLARE(bool, ignore_thread_affinities);
|
||||
REXCVAR_DECLARE(bool, writable_executable_memory);
|
||||
REXCVAR_DECLARE(bool, protect_zero);
|
||||
REXCVAR_DECLARE(bool, protect_on_release);
|
||||
REXCVAR_DECLARE(bool, scribble_heap);
|
||||
|
|
|
|||
|
|
@ -13,10 +13,6 @@
|
|||
#include <rex/memory/utils.h>
|
||||
#include <rex/platform.h>
|
||||
|
||||
REXCVAR_DEFINE_BOOL(writable_executable_memory, true, "Memory",
|
||||
"Allow executable memory to be writable")
|
||||
.lifecycle(rex::cvar::Lifecycle::kRequiresRestart);
|
||||
|
||||
#if REX_ARCH_ARM64
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
|
@ -26,10 +22,6 @@ REXCVAR_DEFINE_BOOL(writable_executable_memory, true, "Memory",
|
|||
namespace rex {
|
||||
namespace memory {
|
||||
|
||||
bool IsWritableExecutableMemoryPreferred() {
|
||||
return REXCVAR_GET(writable_executable_memory);
|
||||
}
|
||||
|
||||
// TODO(benvanik): fancy AVX versions.
|
||||
// https://github.com/gnuradio/volk/blob/master/kernels/volk/volk_16u_byteswap.h
|
||||
// https://github.com/gnuradio/volk/blob/master/kernels/volk/volk_32u_byteswap.h
|
||||
|
|
|
|||
|
|
@ -118,19 +118,19 @@ uint32_t ToPosixProtectFlags(PageAccess access) {
|
|||
case PageAccess::kReadWrite:
|
||||
return PROT_READ | PROT_WRITE;
|
||||
case PageAccess::kExecuteReadOnly:
|
||||
return PROT_READ | PROT_EXEC;
|
||||
// Statically recompiled guest code executes from the host image, never
|
||||
// from guest pages, so execute requests are served without PROT_EXEC.
|
||||
// This keeps the process W^X: no path through this layer can create
|
||||
// executable memory.
|
||||
return PROT_READ;
|
||||
case PageAccess::kExecuteReadWrite:
|
||||
return PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
return PROT_READ | PROT_WRITE;
|
||||
default:
|
||||
assert_unhandled_case(access);
|
||||
return PROT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsWritableExecutableMemorySupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(tomc): this needs to go somewhere else. we should utilize the platform namespace more.
|
||||
#if REX_PLATFORM_LINUX
|
||||
namespace {
|
||||
|
|
|
|||
|
|
@ -50,9 +50,13 @@ DWORD ToWin32ProtectFlags(PageAccess access) {
|
|||
case PageAccess::kReadWrite:
|
||||
return PAGE_READWRITE;
|
||||
case PageAccess::kExecuteReadOnly:
|
||||
return PAGE_EXECUTE_READ;
|
||||
// Statically recompiled guest code executes from the host image, never
|
||||
// from guest pages, so execute requests are served without the execute
|
||||
// bit. This keeps the process W^X: no path through this layer can
|
||||
// create executable memory.
|
||||
return PAGE_READONLY;
|
||||
case PageAccess::kExecuteReadWrite:
|
||||
return PAGE_EXECUTE_READWRITE;
|
||||
return PAGE_READWRITE;
|
||||
default:
|
||||
assert_unhandled_case(access);
|
||||
return PAGE_NOACCESS;
|
||||
|
|
@ -81,16 +85,6 @@ PageAccess ToXeniaProtectFlags(DWORD access) {
|
|||
}
|
||||
}
|
||||
|
||||
bool IsWritableExecutableMemorySupported() {
|
||||
#ifdef REX_BASE_MEMORY_WIN_USE_DESKTOP_FUNCTIONS
|
||||
return true;
|
||||
#else
|
||||
// To test FromApp functions on desktop, undefine
|
||||
// REX_BASE_MEMORY_WIN_USE_DESKTOP_FUNCTIONS and link to WindowsApp.lib.
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void* AllocFixed(void* base_address, size_t length, AllocationType allocation_type,
|
||||
PageAccess access) {
|
||||
DWORD alloc_type = 0;
|
||||
|
|
@ -206,10 +200,11 @@ void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, P
|
|||
file_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case PageAccess::kExecuteReadOnly:
|
||||
file_access = FILE_MAP_READ | FILE_MAP_EXECUTE;
|
||||
// See ToWin32ProtectFlags: guest memory is never host-executable.
|
||||
file_access = FILE_MAP_READ;
|
||||
break;
|
||||
case PageAccess::kExecuteReadWrite:
|
||||
file_access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE;
|
||||
file_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case PageAccess::kNoAccess:
|
||||
default:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue