From 9ce9a99e18d3f00d8be6ee0a4a8b9090a272aefc Mon Sep 17 00:00:00 2001 From: Andrew Whatson Date: Tue, 31 Oct 2017 13:33:49 +1000 Subject: [PATCH] Fix page faults when installing/uninstalling jumper - page fault occurs when running DARKSOULS.exe in 64bit wine prefix - mprotect was being called with wrong length, so src pointers near the end of a page wouldn't be properly unprotected - something re-protects the page after our initial mprotect() call, fixed by always calling mprotect() before overwriting src - install/uninstall were identical, refactored into wrappers around swap_header() with a sanity check --- jumper.h | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/jumper.h b/jumper.h index 3b39d9e..02dec00 100644 --- a/jumper.h +++ b/jumper.h @@ -14,6 +14,7 @@ namespace koku { template struct jumper { F *src = nullptr; F *dst = nullptr; + bool installed = false; #if UINTPTR_MAX == UINT64_MAX std::array header = {{0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, @@ -45,31 +46,35 @@ template struct jumper { #error "Unsupported architecture" #endif - unprotect(); install(); } - void unprotect() { + void swap_header() { assert(src != nullptr); + auto pagesize = sysconf(_SC_PAGESIZE); - auto address = (void *)((uintptr_t)src & ~(pagesize - 1)); - auto result = - mprotect(address, header.size(), PROT_READ | PROT_WRITE | PROT_EXEC); - assert(result == 0); - } + assert((pagesize & (pagesize - 1)) == 0); + + auto address = (uintptr_t)src & ~(pagesize - 1); + auto length = (uintptr_t)src + header.size() - address; + int rc = mprotect((void *)address, length, PROT_READ|PROT_WRITE|PROT_EXEC); + assert(rc == 0); - void install() { - assert(src != nullptr); auto tmp = header; std::memcpy(&header[0], (const void *)src, header.size()); std::memcpy((void *)src, &tmp[0], tmp.size()); } + void install() { + assert(!installed); + swap_header(); + installed = true; + } + void uninstall() { - assert(src != nullptr); - auto tmp = header; - std::memcpy(&header[0], (const void *)src, header.size()); - std::memcpy((void *)src, &tmp[0], tmp.size()); + assert(installed); + swap_header(); + installed = false; } struct scoped_uninstall {