From 7dc516595457594be6db9a18e8ead1aadcdb8e0f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 2 Sep 2012 10:21:34 +0000 Subject: [PATCH] * pseudo-reloc.cc (auto_protect_for): New function. (__write_memory): Call auto_protect_for to handle page protection. (do_pseudo_reloc): Call auto_protect_for to restore old page protection. --- winsup/cygwin/ChangeLog | 7 ++++ winsup/cygwin/pseudo-reloc.cc | 68 +++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 90ac80c04..b35df3805 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,10 @@ +2012-09-02 Jin-woo Ye + Corinna Vinschen + + * pseudo-reloc.cc (auto_protect_for): New function. + (__write_memory): Call auto_protect_for to handle page protection. + (do_pseudo_reloc): Call auto_protect_for to restore old page protection. + 2012-08-26 Christopher Faylor * pinfo.cc (pinfo::init): Remove assertion. diff --git a/winsup/cygwin/pseudo-reloc.cc b/winsup/cygwin/pseudo-reloc.cc index e6b7ebf2b..df91e5889 100644 --- a/winsup/cygwin/pseudo-reloc.cc +++ b/winsup/cygwin/pseudo-reloc.cc @@ -126,6 +126,49 @@ __report_error (const char *msg, ...) #endif } +/* + * This function automatically sets addr as PAGE_EXECUTE_READWRITE + * by deciding whether VirtualQuery for the addr is actually needed. + * And it assumes that it is called in LdrpCallInitRoutine. + * Hence not thread safe. + */ +static void +auto_protect_for (void* addr) +{ + static MEMORY_BASIC_INFORMATION mbi; + static bool state = false; + static DWORD oldprot; + + if (!addr) + { + /* Restore original protection. */ + if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE))) + VirtualProtect (mbi.BaseAddress, mbi.RegionSize, oldprot, &oldprot); + state = false; + return; + } + if (state) + { + /* We have valid region information. Are we still within this region? + If so, just leave. */ + void *ptr = ((void*) ((ptrdiff_t) mbi.BaseAddress + mbi.RegionSize)); + if (addr >= mbi.BaseAddress && addr < ptr) + return; + /* Otherwise, restore original protection and fall through to querying + and potentially changing next region. */ + if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE))) + VirtualProtect (mbi.BaseAddress, mbi.RegionSize, oldprot, &oldprot); + } + else + state = true; + /* Query region and temporarily allow write access to read-only protected + memory. */ + VirtualQuery (addr, &mbi, sizeof mbi); + if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE))) + VirtualProtect (mbi.BaseAddress, mbi.RegionSize, + PAGE_EXECUTE_READWRITE, &oldprot); +} + /* This function temporarily marks the page containing addr * writable, before copying len bytes from *src to *addr, and * then restores the original protection settings to the page. @@ -142,27 +185,12 @@ __report_error (const char *msg, ...) static void __write_memory (void *addr, const void *src, size_t len) { - MEMORY_BASIC_INFORMATION b; - DWORD oldprot; - if (!len) return; - - if (!VirtualQuery (addr, &b, sizeof (b))) - { - __report_error (" VirtualQuery failed for %d bytes at address %p", - (int) sizeof (b), addr); - } - - /* Temporarily allow write access to read-only protected memory. */ - if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE) - VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, - &oldprot); + /* Fix page protection for writing. */ + auto_protect_for (addr); /* write the data. */ memcpy (addr, src, len); - /* Restore original protection. */ - if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE) - VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot); } #define RP_VERSION_V1 0 @@ -232,6 +260,8 @@ do_pseudo_reloc (void * start, void * end, void * base) newval = (*((DWORD*) reloc_target)) + o->addend; __write_memory ((void *) reloc_target, &newval, sizeof (DWORD)); } + /* Restore original protection. */ + auto_protect_for (NULL); return; } @@ -322,7 +352,9 @@ do_pseudo_reloc (void * start, void * end, void * base) break; #endif } - } + } + /* Restore original protection. */ + auto_protect_for (NULL); } #ifdef __CYGWIN__