core: never create executable host memory for guest pages

This commit is contained in:
mchughalex 2026-07-24 19:40:35 +01:00
parent 5aa8c4c727
commit 3b0328da62
5 changed files with 18 additions and 39 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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

View file

@ -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 {

View file

@ -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: