Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Track RWX regions in mapped images #4206

Merged
merged 2 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Source/Windows/ARM64EC/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,10 @@ NTSTATUS ProcessInit() {
CTX->SetSyscallHandler(SyscallHandler.get());
CTX->InitCore();
InvalidationTracker.emplace(*CTX, Threads);

auto MainModule = reinterpret_cast<__TEB*>(NtCurrentTeb())->Peb->ImageBaseAddress;
InvalidationTracker->HandleImageMap(reinterpret_cast<uint64_t>(MainModule));

CPUFeatures.emplace(*CTX);

X64ReturnInstr = ::VirtualAlloc(nullptr, FEXCore::Utils::FEX_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Expand Down Expand Up @@ -694,6 +698,12 @@ void NotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt, BOOL After,
}

NTSTATUS NotifyMapViewOfSection(void* Unk1, void* Address, void* Unk2, SIZE_T Size, ULONG AllocType, ULONG Prot) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return STATUS_SUCCESS;
}

std::scoped_lock Lock(ThreadCreationMutex);
InvalidationTracker->HandleImageMap(reinterpret_cast<uint64_t>(Address));
return STATUS_SUCCESS;
}

Expand Down
19 changes: 17 additions & 2 deletions Source/Windows/Common/InvalidationTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ void InvalidationTracker::HandleMemoryProtectionNotification(uint64_t Address, u
const auto AlignedBase = Address & FEXCore::Utils::FEX_PAGE_MASK;
const auto AlignedSize = (Address - AlignedBase + Size + FEXCore::Utils::FEX_PAGE_SIZE - 1) & FEXCore::Utils::FEX_PAGE_MASK;

if (Prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) {
if (Prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) {
std::scoped_lock Lock(CTX.GetCodeInvalidationMutex());
for (auto Thread : Threads) {
CTX.InvalidateGuestCodeRange(Thread.second, AlignedBase, AlignedSize);
}
}

if (Prot & PAGE_EXECUTE_READWRITE) {
if (Prot & (PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE)) {
LogMan::Msg::DFmt("Add SMC interval: {:X} - {:X}", AlignedBase, AlignedBase + AlignedSize);
std::scoped_lock Lock(RWXIntervalsLock);
RWXIntervals.Insert({AlignedBase, AlignedBase + AlignedSize});
Expand All @@ -35,6 +35,21 @@ void InvalidationTracker::HandleMemoryProtectionNotification(uint64_t Address, u
}
}

void InvalidationTracker::HandleImageMap(uint64_t Address) {
auto* Nt = RtlImageNtHeader(reinterpret_cast<HMODULE>(Address));
auto* SectionsBegin = IMAGE_FIRST_SECTION(Nt);
auto* SectionsEnd = SectionsBegin + Nt->FileHeader.NumberOfSections;

for (auto* Section = SectionsBegin; Section != SectionsEnd; Section++) {
if ((Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (Section->Characteristics & IMAGE_SCN_MEM_WRITE)) {
uint64_t SectionBase = Address + Section->VirtualAddress;
LogMan::Msg::DFmt("Add image SMC interval: {:X} - {:X}", SectionBase, SectionBase + Section->Misc.VirtualSize);
std::scoped_lock Lock(RWXIntervalsLock);
RWXIntervals.Insert({SectionBase, SectionBase + Section->Misc.VirtualSize});
}
}
}

void InvalidationTracker::InvalidateContainingSection(uint64_t Address, bool Free) {
MEMORY_BASIC_INFORMATION Info;
if (NtQueryVirtualMemory(NtCurrentProcess(), reinterpret_cast<void*>(Address), MemoryBasicInformation, &Info, sizeof(Info), nullptr)) {
Expand Down
1 change: 1 addition & 0 deletions Source/Windows/Common/InvalidationTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class InvalidationTracker {
public:
InvalidationTracker(FEXCore::Context::Context& CTX, const std::unordered_map<DWORD, FEXCore::Core::InternalThreadState*>& Threads);
void HandleMemoryProtectionNotification(uint64_t Address, uint64_t Size, ULONG Prot);
void HandleImageMap(uint64_t Address);
void InvalidateContainingSection(uint64_t Address, bool Free);
void InvalidateAlignedInterval(uint64_t Address, uint64_t Size, bool Free);
void ReprotectRWXIntervals(uint64_t Address, uint64_t Size);
Expand Down
4 changes: 4 additions & 0 deletions Source/Windows/WOW64/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,10 @@ void BTCpuProcessInit() {
CTX->SetSyscallHandler(SyscallHandler.get());
CTX->InitCore();
InvalidationTracker.emplace(*CTX, Threads);

auto MainModule = reinterpret_cast<__TEB*>(NtCurrentTeb())->Peb->ImageBaseAddress;
InvalidationTracker->HandleImageMap(reinterpret_cast<uint64_t>(MainModule));

CPUFeatures.emplace(*CTX);

// Allocate the syscall/unixcall trampolines in the lower 2GB of the address space
Expand Down
1 change: 1 addition & 0 deletions Source/Windows/include/winternl.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ NTSTATUS WINAPI RtlDeleteCriticalSection(RTL_CRITICAL_SECTION*);
NTSTATUS WINAPI RtlEnterCriticalSection(RTL_CRITICAL_SECTION*);
ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG);
ULONG WINAPI RtlGetCurrentDirectory_U(ULONG, LPWSTR);
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE);
PVOID WINAPI RtlImageDirectoryEntryToData(HMODULE, BOOL, WORD, ULONG*);
void WINAPI RtlInitializeConditionVariable(RTL_CONDITION_VARIABLE*);
NTSTATUS WINAPI RtlInitializeCriticalSection(RTL_CRITICAL_SECTION*);
Expand Down
Loading