diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index 23b55e7a..276a6be1 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -23,16 +23,22 @@ using NTSTATUS = std::uint32_t; #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define STATUS_WAIT_1 ((NTSTATUS)0x00000001L) - #define STATUS_ALERTED ((NTSTATUS)0x00000101L) +#define STATUS_PIPE_LISTENING ((NTSTATUS)0x00000105L) +#define STATUS_PIPE_CONNECTED ((NTSTATUS)0x00000106L) #define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) +#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) #define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) #define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL) #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS)0xC0000018L) +#define STATUS_NOT_MAPPED_VIEW ((NTSTATUS)0xC0000019L) +#define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS)0xC000001BL) #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) @@ -40,14 +46,35 @@ using NTSTATUS = std::uint32_t; #define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) #define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) #define STATUS_SECTION_NOT_IMAGE ((NTSTATUS)0xC0000049L) +#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) #define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) #define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS)0xC000009FL) #define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) +#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL) +#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL) +#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL) +#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L) +#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L) #define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) #define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) +#define STATUS_PIPE_NOT_CONNECTED ((NTSTATUS)0xC00000BEL) +#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L) #define STATUS_INTERNAL_ERROR ((NTSTATUS)0xC00000E5L) -#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) +#define STATUS_INVALID_PARAMETER_1 ((NTSTATUS)0xC00000EFL) +#define STATUS_INVALID_PARAMETER_2 ((NTSTATUS)0xC00000F0L) +#define STATUS_INVALID_PARAMETER_3 ((NTSTATUS)0xC00000F1L) +#define STATUS_INVALID_PARAMETER_4 ((NTSTATUS)0xC00000F2L) +#define STATUS_INVALID_PARAMETER_5 ((NTSTATUS)0xC00000F3L) +#define STATUS_INVALID_PARAMETER_6 ((NTSTATUS)0xC00000F4L) +#define STATUS_INVALID_PARAMETER_7 ((NTSTATUS)0xC00000F5L) +#define STATUS_INVALID_PARAMETER_8 ((NTSTATUS)0xC00000F6L) +#define STATUS_INVALID_PARAMETER_9 ((NTSTATUS)0xC00000F7L) +#define STATUS_INVALID_PARAMETER_10 ((NTSTATUS)0xC00000F8L) +#define STATUS_INVALID_PARAMETER_11 ((NTSTATUS)0xC00000F9L) +#define STATUS_INVALID_PARAMETER_12 ((NTSTATUS)0xC00000FAL) #define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L) +#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL) #define STATUS_CONNECTION_RESET ((NTSTATUS)0xC000020DL) #define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) #define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L) @@ -55,20 +82,6 @@ using NTSTATUS = std::uint32_t; #define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000328L) #define STATUS_PORT_NOT_SET ((NTSTATUS)0xC0000353L) #define STATUS_DEBUGGER_INACTIVE ((NTSTATUS)0xC0000354L) -#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL) -#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L) -#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL) -#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L) -#define STATUS_PIPE_LISTENING ((NTSTATUS)0x00000105L) -#define STATUS_PIPE_CONNECTED ((NTSTATUS)0x00000106L) -#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L) -#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL) -#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL) -#define STATUS_PIPE_NOT_CONNECTED ((NTSTATUS)0xC00000BEL) - -#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) - -#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) #define FILE_DEVICE_NETWORK 0x00000012 #define FSCTL_AFD_BASE FILE_DEVICE_NETWORK diff --git a/src/windows-emulator/memory_manager.cpp b/src/windows-emulator/memory_manager.cpp index 125a40b9..f245b43a 100644 --- a/src/windows-emulator/memory_manager.cpp +++ b/src/windows-emulator/memory_manager.cpp @@ -78,7 +78,7 @@ namespace utils static void serialize(buffer_serializer& buffer, const memory_manager::reserved_region& region) { - buffer.write(region.is_mmio); + buffer.write(region.kind); buffer.write(region.initial_permission); buffer.write(region.length); buffer.write_map(region.committed_regions); @@ -86,7 +86,7 @@ namespace utils static void deserialize(buffer_deserializer& buffer, memory_manager::reserved_region& region) { - buffer.read(region.is_mmio); + buffer.read(region.kind); buffer.read(region.initial_permission); region.length = static_cast(buffer.read()); buffer.read_map(region.committed_regions); @@ -133,7 +133,7 @@ void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer, co for (const auto& reserved_region : this->reserved_regions_) { - if (reserved_region.second.is_mmio) + if (reserved_region.second.kind == memory_region_kind::mmio) { continue; } @@ -169,7 +169,7 @@ void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer for (auto i = this->reserved_regions_.begin(); i != this->reserved_regions_.end();) { auto& reserved_region = i->second; - if (reserved_region.is_mmio) + if (reserved_region.kind == memory_region_kind::mmio) { i = this->reserved_regions_.erase(i); continue; @@ -183,7 +183,9 @@ void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer buffer.read(data.data(), region.second.length); - this->map_memory(region.first, region.second.length, region.second.permissions); + const auto effective_permission = + region.second.permissions.is_guarded() ? memory_permission::none : region.second.permissions.common; + this->map_memory(region.first, region.second.length, effective_permission); this->write_memory(region.first, data.data(), region.second.length); } } @@ -211,6 +213,8 @@ bool memory_manager::protect_memory(const uint64_t address, const size_t size, c auto& committed_regions = entry->second.committed_regions; split_regions(committed_regions, {address, end}); + const auto effective_permission = permissions.is_guarded() ? memory_permission::none : permissions.common; + for (auto& sub_region : committed_regions) { if (sub_region.first >= end) @@ -226,7 +230,7 @@ bool memory_manager::protect_memory(const uint64_t address, const size_t size, c old_first_permissions = sub_region.second.permissions; } - this->apply_memory_protection(sub_region.first, sub_region.second.length, permissions); + this->apply_memory_protection(sub_region.first, sub_region.second.length, effective_permission); sub_region.second.permissions = permissions; } } @@ -256,7 +260,7 @@ bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mm .try_emplace(address, reserved_region{ .length = size, - .is_mmio = true, + .kind = memory_region_kind::mmio, }) .first; @@ -268,7 +272,7 @@ bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mm } bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const nt_memory_permission permissions, - const bool reserve_only) + const bool reserve_only, const memory_region_kind kind) { if (this->overlaps_reserved_region(address, size)) { @@ -280,6 +284,7 @@ bool memory_manager::allocate_memory(const uint64_t address, const size_t size, reserved_region{ .length = size, .initial_permission = permissions, + .kind = kind, }) .first; @@ -316,6 +321,8 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co uint64_t last_region_start{}; const committed_region* last_region{nullptr}; + const auto effective_permission = permissions.is_guarded() ? memory_permission::none : permissions.common; + for (auto& sub_region : committed_regions) { if (sub_region.first >= end) @@ -331,7 +338,7 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co if (map_length > 0) { - this->map_memory(map_start, static_cast(map_length), permissions); + this->map_memory(map_start, static_cast(map_length), effective_permission); committed_regions[map_start] = committed_region{static_cast(map_length), permissions}; } @@ -345,7 +352,7 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co const auto map_start = last_region ? (last_region_start + last_region->length) : address; const auto map_length = end - map_start; - this->map_memory(map_start, static_cast(map_length), permissions); + this->map_memory(map_start, static_cast(map_length), effective_permission); committed_regions[map_start] = committed_region{static_cast(map_length), permissions}; } @@ -364,7 +371,7 @@ bool memory_manager::decommit_memory(const uint64_t address, const size_t size) return false; } - if (entry->second.is_mmio) + if (entry->second.kind == memory_region_kind::mmio) { throw std::runtime_error("Not allowed to decommit MMIO!"); } @@ -406,38 +413,59 @@ bool memory_manager::decommit_memory(const uint64_t address, const size_t size) bool memory_manager::release_memory(const uint64_t address, size_t size) { - const auto entry = this->reserved_regions_.find(address); + if (!size) + { + const auto entry = this->reserved_regions_.find(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } + + auto& committed_regions = entry->second.committed_regions; + for (auto i = committed_regions.begin(); i != committed_regions.end();) + { + this->unmap_memory(i->first, i->second.length); + i = committed_regions.erase(i); + } + + this->reserved_regions_.erase(entry); + this->update_layout_version(); + return true; + } + + const auto aligned_start = page_align_down(address); + const auto aligned_end = page_align_up(address + size); + size = static_cast(aligned_end - aligned_start); + + const auto entry = this->find_reserved_region(aligned_start); if (entry == this->reserved_regions_.end()) { return false; } - if (!size) - { - size = entry->second.length; - } + const auto reserved_start = entry->first; + const auto reserved_end = entry->first + entry->second.length; - size = static_cast(page_align_up(size)); - - if (size > entry->second.length) + if (reserved_end < aligned_end) { throw std::runtime_error("Cross region release not supported yet!"); } - const auto end = address + size; - auto& committed_regions = entry->second.committed_regions; + reserved_region region = std::move(entry->second); + this->reserved_regions_.erase(entry); - split_regions(committed_regions, {end}); + auto& committed_regions = region.committed_regions; + split_regions(committed_regions, {aligned_start, aligned_end}); for (auto i = committed_regions.begin(); i != committed_regions.end();) { - if (i->first >= end) + if (i->first >= aligned_end) { break; } const auto sub_region_end = i->first + i->second.length; - if (i->first >= address && sub_region_end <= end) + if (i->first >= aligned_start && sub_region_end <= aligned_end) { this->unmap_memory(i->first, i->second.length); i = committed_regions.erase(i); @@ -448,13 +476,41 @@ bool memory_manager::release_memory(const uint64_t address, size_t size) } } - entry->second.length -= size; - if (entry->second.length > 0) + committed_region_map left_committed{}; + committed_region_map right_committed{}; + + for (auto& sub_region : committed_regions) { - this->reserved_regions_[address + size] = std::move(entry->second); + if (sub_region.first < aligned_start) + { + left_committed.emplace(sub_region.first, std::move(sub_region.second)); + } + else if (sub_region.first >= aligned_end) + { + right_committed.emplace(sub_region.first, std::move(sub_region.second)); + } + } + + if (reserved_start < aligned_start) + { + reserved_region left_region{}; + left_region.length = static_cast(aligned_start - reserved_start); + left_region.initial_permission = region.initial_permission; + left_region.kind = region.kind; + left_region.committed_regions = std::move(left_committed); + this->reserved_regions_.try_emplace(reserved_start, std::move(left_region)); + } + + if (aligned_end < reserved_end) + { + reserved_region right_region{}; + right_region.length = static_cast(reserved_end - aligned_end); + right_region.initial_permission = region.initial_permission; + right_region.kind = region.kind; + right_region.committed_regions = std::move(right_committed); + this->reserved_regions_.try_emplace(aligned_end, std::move(right_region)); } - this->reserved_regions_.erase(entry); this->update_layout_version(); return true; } @@ -472,10 +528,11 @@ void memory_manager::unmap_all_memory() this->reserved_regions_.clear(); } -uint64_t memory_manager::allocate_memory(const size_t size, const nt_memory_permission permissions, const bool reserve_only, uint64_t start) +uint64_t memory_manager::allocate_memory(const size_t size, const nt_memory_permission permissions, const bool reserve_only, uint64_t start, + const memory_region_kind kind) { const auto allocation_base = this->find_free_allocation_base(size, start); - if (!allocate_memory(allocation_base, size, permissions, reserve_only)) + if (!allocate_memory(allocation_base, size, permissions, reserve_only, kind)) { return 0; } @@ -569,6 +626,7 @@ region_info memory_manager::get_region_info(const uint64_t address) result.start = result.allocation_base; result.length = result.allocation_length; result.initial_permissions = entry->second.initial_permission; + result.kind = reserved_region.kind; if (committed_regions.empty()) { @@ -634,6 +692,28 @@ bool memory_manager::overlaps_reserved_region(const uint64_t address, const size return false; } +memory_region_kind memory_manager::get_region_kind(const uint64_t address) const +{ + if (this->reserved_regions_.empty()) + { + return memory_region_kind::free; + } + + auto upper_bound = this->reserved_regions_.upper_bound(address); + if (upper_bound == this->reserved_regions_.begin()) + { + return memory_region_kind::free; + } + + const auto entry = --upper_bound; + if (entry->first + entry->second.length <= address) + { + return memory_region_kind::free; + } + + return entry->second.kind; +} + void memory_manager::read_memory(const uint64_t address, void* data, const size_t size) const { this->memory_->read_memory(address, data, size); diff --git a/src/windows-emulator/memory_manager.hpp b/src/windows-emulator/memory_manager.hpp index c7c3ea8f..aff40dc7 100644 --- a/src/windows-emulator/memory_manager.hpp +++ b/src/windows-emulator/memory_manager.hpp @@ -1,4 +1,5 @@ #pragma once +#include "std_include.hpp" #include #include #include @@ -16,6 +17,15 @@ constexpr auto MAX_ALLOCATION_END_EXCL = MAX_ALLOCATION_ADDRESS + 1ULL; constexpr auto DEFAULT_ALLOCATION_ADDRESS_64BIT = 0x100000000ULL; constexpr auto DEFAULT_ALLOCATION_ADDRESS_32BIT = 0x10000ULL; +enum class memory_region_kind : uint8_t +{ + free = 0, + private_allocation, + section_view, + section_image, + mmio, +}; + // This maps to the `basic_memory_region` struct defined in // emulator\memory_region.hpp struct region_info : basic_memory_region @@ -25,6 +35,7 @@ struct region_info : basic_memory_region bool is_reserved{}; bool is_committed{}; nt_memory_permission initial_permissions{}; + memory_region_kind kind{memory_region_kind::free}; }; using mmio_read_callback = std::function; @@ -57,7 +68,7 @@ class memory_manager : public memory_interface size_t length{}; memory_permission initial_permission{}; committed_region_map committed_regions{}; - bool is_mmio{false}; + memory_region_kind kind{memory_region_kind::private_allocation}; }; using reserved_region_map = std::map; @@ -70,7 +81,8 @@ class memory_manager : public memory_interface bool protect_memory(uint64_t address, size_t size, nt_memory_permission permissions, nt_memory_permission* old_permissions = nullptr); bool allocate_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb); - bool allocate_memory(uint64_t address, size_t size, nt_memory_permission permissions, bool reserve_only = false); + bool allocate_memory(uint64_t address, size_t size, nt_memory_permission permissions, bool reserve_only = false, + memory_region_kind kind = memory_region_kind::private_allocation); bool commit_memory(uint64_t address, size_t size, nt_memory_permission permissions); bool decommit_memory(uint64_t address, size_t size); @@ -79,7 +91,8 @@ class memory_manager : public memory_interface void unmap_all_memory(); - uint64_t allocate_memory(size_t size, nt_memory_permission permissions, bool reserve_only = false, uint64_t start = 0); + uint64_t allocate_memory(size_t size, nt_memory_permission permissions, bool reserve_only = false, uint64_t start = 0, + memory_region_kind kind = memory_region_kind::private_allocation); uint64_t find_free_allocation_base(size_t size, uint64_t start = 0) const; @@ -89,6 +102,8 @@ class memory_manager : public memory_interface bool overlaps_reserved_region(uint64_t address, size_t size) const; + memory_region_kind get_region_kind(uint64_t address) const; + const reserved_region_map& get_reserved_regions() const { return this->reserved_regions_; @@ -127,3 +142,46 @@ class memory_manager : public memory_interface void update_layout_version(); }; + +namespace memory_region_policy +{ + constexpr bool is_section_kind(const memory_region_kind kind) + { + return kind == memory_region_kind::section_view || kind == memory_region_kind::section_image; + } + + constexpr bool is_mapped_memory_kind(const memory_region_kind kind) + { + return is_section_kind(kind) || kind == memory_region_kind::mmio; + } + + constexpr uint32_t to_memory_basic_information_type(const memory_region_kind kind) + { + switch (kind) + { + case memory_region_kind::section_image: + return MEM_IMAGE; + case memory_region_kind::section_view: + return MEM_MAPPED; + case memory_region_kind::mmio: + return MEM_MAPPED; + default: + return MEM_PRIVATE; + } + } + + constexpr NTSTATUS nt_free_virtual_memory_denied_status(const memory_region_kind kind) + { + if (is_section_kind(kind)) + { + return STATUS_UNABLE_TO_DELETE_SECTION; + } + + if (kind == memory_region_kind::mmio) + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; + } +} diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index 705c2efd..02d71239 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -3,6 +3,7 @@ #include "../cpu_context.hpp" #include "../emulator_utils.hpp" #include "../syscall_utils.hpp" +#include "../memory_manager.hpp" namespace syscalls { @@ -58,7 +59,15 @@ namespace syscalls image_info.Protect = map_emulator_to_nt_protection(region_info.permissions); image_info.AllocationProtect = map_emulator_to_nt_protection(region_info.initial_permissions); - image_info.Type = MEM_PRIVATE; + + if (!region_info.is_reserved) + { + image_info.Type = 0; + } + else + { + image_info.Type = memory_region_policy::to_memory_basic_information_type(region_info.kind); + } }); return STATUS_SUCCESS; @@ -199,6 +208,12 @@ namespace syscalls allocation_bytes = page_align_up(allocation_bytes); bytes_to_allocate.write(allocation_bytes); + const auto base_protection = page_protection & ~static_cast(PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE); + if (base_protection == PAGE_WRITECOPY || base_protection == PAGE_EXECUTE_WRITECOPY) + { + return STATUS_INVALID_PAGE_PROTECTION; + } + const auto protection = try_map_nt_to_emulator_protection(page_protection); if (!protection.has_value()) { @@ -218,7 +233,7 @@ namespace syscalls // initial value of BaseAddress is non-NULL, the region is allocated starting at the specified virtual // address rounded down to the next host page size address boundary. If the initial value of BaseAddress // is NULL, the operating system will determine where to allocate the region. - potential_base = page_align_up(potential_base); + potential_base = page_align_down(potential_base); } if (!potential_base) @@ -267,7 +282,7 @@ namespace syscalls if (free_type == 0) { - return STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER_4; } const auto allocation_base = base_address.read(); @@ -275,14 +290,70 @@ namespace syscalls if (free_type & MEM_RELEASE) { - return c.win_emu.memory.release_memory(allocation_base, static_cast(allocation_size)) ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; + if (!allocation_size) + { + const auto region_info = c.win_emu.memory.get_region_info(allocation_base); + if (!region_info.is_reserved) + { + return STATUS_MEMORY_NOT_ALLOCATED; + } + + if (region_info.allocation_base != allocation_base) + { + return STATUS_FREE_VM_NOT_AT_BASE; + } + } + + const auto region_kind = c.win_emu.memory.get_region_kind(allocation_base); + const auto denied_status = memory_region_policy::nt_free_virtual_memory_denied_status(region_kind); + if (denied_status != STATUS_SUCCESS) + { + return denied_status; + } + + const bool success = c.win_emu.memory.release_memory(allocation_base, static_cast(allocation_size)); + if (success) + { + return STATUS_SUCCESS; + } + + const auto region_info = c.win_emu.memory.get_region_info(allocation_base); + if (!region_info.is_reserved) + { + return STATUS_MEMORY_NOT_ALLOCATED; + } + + return STATUS_FREE_VM_NOT_AT_BASE; } if (free_type & MEM_DECOMMIT) { - return c.win_emu.memory.decommit_memory(allocation_base, static_cast(allocation_size)) ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; + const auto region_kind = c.win_emu.memory.get_region_kind(allocation_base); + const auto denied_status = memory_region_policy::nt_free_virtual_memory_denied_status(region_kind); + if (denied_status != STATUS_SUCCESS) + { + return denied_status; + } + + auto decommit_size = static_cast(allocation_size); + if (!decommit_size) + { + const auto region_info = c.win_emu.memory.get_region_info(allocation_base); + if (!region_info.is_reserved) + { + return STATUS_MEMORY_NOT_ALLOCATED; + } + + if (region_info.allocation_base != allocation_base) + { + return STATUS_FREE_VM_NOT_AT_BASE; + } + + decommit_size = region_info.allocation_length; + } + + const bool success = c.win_emu.memory.decommit_memory(allocation_base, decommit_size); + return success ? STATUS_SUCCESS : STATUS_MEMORY_NOT_ALLOCATED; } throw std::runtime_error("Bad free type"); diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index 327f937f..85f7d7de 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -1,6 +1,7 @@ #include "../std_include.hpp" #include "../emulator_utils.hpp" #include "../syscall_utils.hpp" +#include "../memory_manager.hpp" #include @@ -193,7 +194,8 @@ namespace syscalls constexpr auto shared_section_size = 0x10000; const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size); - c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write); + c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write, false, + memory_region_kind::section_view); c.proc.shared_section_address = address; c.proc.shared_section_size = shared_section_size; @@ -206,7 +208,8 @@ namespace syscalls constexpr auto dbwin_buffer_section_size = 0x1000; const auto address = c.win_emu.memory.find_free_allocation_base(dbwin_buffer_section_size); - c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write); + c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write, false, + memory_region_kind::section_view); c.proc.dbwin_buffer = address; c.proc.dbwin_buffer_size = dbwin_buffer_section_size; @@ -373,7 +376,7 @@ namespace syscalls const auto aligned_size = static_cast(page_align_up(size)); const auto reserve_only = section_entry->allocation_attributes == SEC_RESERVE; const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection); - const auto address = c.win_emu.memory.allocate_memory(aligned_size, protection, reserve_only); + const auto address = c.win_emu.memory.allocate_memory(aligned_size, protection, reserve_only, 0, memory_region_kind::section_view); if (!reserve_only && !file_data.empty()) { @@ -577,24 +580,27 @@ namespace syscalls return STATUS_INVALID_PARAMETER; } - if (base_address == c.proc.shared_section_address) + if (c.proc.shared_section_address && base_address >= c.proc.shared_section_address && + base_address < c.proc.shared_section_address + c.proc.shared_section_size) { + const auto address = c.proc.shared_section_address; c.proc.shared_section_address = 0; - c.win_emu.memory.release_memory(base_address, static_cast(c.proc.shared_section_size)); + c.win_emu.memory.release_memory(address, static_cast(c.proc.shared_section_size)); return STATUS_SUCCESS; } - if (base_address == c.proc.dbwin_buffer) + if (c.proc.dbwin_buffer && base_address >= c.proc.dbwin_buffer && base_address < c.proc.dbwin_buffer + c.proc.dbwin_buffer_size) { + const auto address = c.proc.dbwin_buffer; c.proc.dbwin_buffer = 0; - c.win_emu.memory.release_memory(base_address, static_cast(c.proc.dbwin_buffer_size)); + c.win_emu.memory.release_memory(address, static_cast(c.proc.dbwin_buffer_size)); return STATUS_SUCCESS; } const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); if (mod != nullptr) { - if (c.win_emu.mod_manager.unmap(base_address)) + if (c.win_emu.mod_manager.unmap(mod->image_base)) { return STATUS_SUCCESS; } @@ -602,14 +608,14 @@ namespace syscalls return STATUS_INVALID_PARAMETER; } - if (c.win_emu.memory.release_memory(base_address, 0)) + const auto region_info = c.win_emu.memory.get_region_info(base_address); + if (region_info.is_reserved && memory_region_policy::is_section_kind(region_info.kind) && + c.win_emu.memory.release_memory(region_info.allocation_base, 0)) { return STATUS_SUCCESS; } - c.win_emu.log.error("Unmapping non-module/non-memory section not supported!\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; + return STATUS_NOT_MAPPED_VIEW; } NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, const handle process_handle, const uint64_t base_address,