Handle invalid page protections

This fixes #420
This commit is contained in:
momo5502
2025-07-20 09:34:25 +02:00
parent 6a1eb46fd2
commit 6eb4ef33ff
4 changed files with 36 additions and 10 deletions

View File

@@ -36,6 +36,7 @@ using NTSTATUS = std::uint32_t;
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
#define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS)0xC0000045L)
#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) #define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L)
#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) #define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L)
#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) #define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL)

View File

@@ -792,6 +792,11 @@ namespace
bool test_apis() bool test_apis()
{ {
if (VirtualProtect(nullptr, 0, 0, nullptr))
{
return false;
}
wchar_t buffer[0x100]; wchar_t buffer[0x100];
DWORD size = sizeof(buffer) / 2; DWORD size = sizeof(buffer) / 2;
return GetComputerNameExW(ComputerNameNetBIOS, buffer, &size); return GetComputerNameExW(ComputerNameNetBIOS, buffer, &size);

View File

@@ -20,7 +20,7 @@ inline std::string get_permission_string(const memory_permission permission)
return res; return res;
} }
inline nt_memory_permission map_nt_to_emulator_protection(uint32_t nt_protection) inline std::optional<nt_memory_permission> try_map_nt_to_emulator_protection(uint32_t nt_protection)
{ {
memory_permission_ext ext = memory_permission_ext::none; memory_permission_ext ext = memory_permission_ext::none;
// TODO: Check for invalid combinations // TODO: Check for invalid combinations
@@ -51,14 +51,26 @@ inline nt_memory_permission map_nt_to_emulator_protection(uint32_t nt_protection
case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_READWRITE:
common = memory_permission::all; common = memory_permission::all;
break; break;
case 0:
case PAGE_EXECUTE_WRITECOPY: case PAGE_EXECUTE_WRITECOPY:
default: default:
throw std::runtime_error("Failed to map protection"); return std::nullopt;
} }
return nt_memory_permission{common, ext}; return nt_memory_permission{common, ext};
} }
inline nt_memory_permission map_nt_to_emulator_protection(uint32_t nt_protection)
{
const auto protection = try_map_nt_to_emulator_protection(nt_protection);
if (protection.has_value())
{
return *protection;
}
throw std::runtime_error("Failed to map protection: " + std::to_string(nt_protection));
}
inline uint32_t map_emulator_to_nt_protection(const memory_permission permission) inline uint32_t map_emulator_to_nt_protection(const memory_permission permission)
{ {
const bool has_exec = (permission & memory_permission::exec) != memory_permission::none; const bool has_exec = (permission & memory_permission::exec) != memory_permission::none;

View File

@@ -144,15 +144,19 @@ namespace syscalls
base_address.write(aligned_start); base_address.write(aligned_start);
bytes_to_protect.write(static_cast<uint32_t>(aligned_length)); bytes_to_protect.write(static_cast<uint32_t>(aligned_length));
const auto requested_protection = map_nt_to_emulator_protection(protection); const auto requested_protection = try_map_nt_to_emulator_protection(protection);
if (!requested_protection.has_value())
{
return STATUS_INVALID_PAGE_PROTECTION;
}
c.win_emu.callbacks.on_memory_protect(aligned_start, aligned_length, requested_protection); c.win_emu.callbacks.on_memory_protect(aligned_start, aligned_length, *requested_protection);
nt_memory_permission old_protection_value{}; nt_memory_permission old_protection_value{};
try try
{ {
c.win_emu.memory.protect_memory(aligned_start, static_cast<size_t>(aligned_length), requested_protection, c.win_emu.memory.protect_memory(aligned_start, static_cast<size_t>(aligned_length), *requested_protection,
&old_protection_value); &old_protection_value);
} }
catch (...) catch (...)
@@ -180,7 +184,11 @@ namespace syscalls
allocation_bytes = page_align_up(allocation_bytes); allocation_bytes = page_align_up(allocation_bytes);
bytes_to_allocate.write(allocation_bytes); bytes_to_allocate.write(allocation_bytes);
const auto protection = map_nt_to_emulator_protection(page_protection); const auto protection = try_map_nt_to_emulator_protection(page_protection);
if (!protection.has_value())
{
return STATUS_INVALID_PAGE_PROTECTION;
}
auto potential_base = base_address.read(); auto potential_base = base_address.read();
if (!potential_base) if (!potential_base)
@@ -204,15 +212,15 @@ namespace syscalls
} }
if (commit && !reserve && if (commit && !reserve &&
c.win_emu.memory.commit_memory(potential_base, static_cast<size_t>(allocation_bytes), protection)) c.win_emu.memory.commit_memory(potential_base, static_cast<size_t>(allocation_bytes), *protection))
{ {
c.win_emu.callbacks.on_memory_allocate(potential_base, allocation_bytes, protection, true); c.win_emu.callbacks.on_memory_allocate(potential_base, allocation_bytes, *protection, true);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
c.win_emu.callbacks.on_memory_allocate(potential_base, allocation_bytes, protection, false); c.win_emu.callbacks.on_memory_allocate(potential_base, allocation_bytes, *protection, false);
return c.win_emu.memory.allocate_memory(potential_base, static_cast<size_t>(allocation_bytes), protection, return c.win_emu.memory.allocate_memory(potential_base, static_cast<size_t>(allocation_bytes), *protection,
!commit) !commit)
? STATUS_SUCCESS ? STATUS_SUCCESS
: STATUS_MEMORY_NOT_ALLOCATED; : STATUS_MEMORY_NOT_ALLOCATED;