Bug 951827 - Part 3: Give trampolines some structure. r=ehsan
authorDavid Major <dmajor@mozilla.com>
Fri, 14 Feb 2014 14:55:46 -0800
changeset 170032 1109dba48e6bb0a5db97a54833a6e38b064b0337
parent 170031 236ed76eea8b854cb572dfc9e3e9bb076ec29af0
child 170033 8fb155711dfec3c7d6fef608e926aeafd0a19844
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersehsan
bugs951827
milestone30.0a1
Bug 951827 - Part 3: Give trampolines some structure. r=ehsan
toolkit/xre/nsWindowsDllInterceptor.h
--- a/toolkit/xre/nsWindowsDllInterceptor.h
+++ b/toolkit/xre/nsWindowsDllInterceptor.h
@@ -231,17 +231,18 @@ public:
     for (i = 0, p = mHookPage; i < mCurHooks; i++, p += kHookSize) {
 #if defined(_M_IX86)
       size_t nBytes = 1 + sizeof(intptr_t);
 #elif defined(_M_X64)
       size_t nBytes = 2 + sizeof(intptr_t);
 #else
 #error "Unknown processor type"
 #endif
-      byteptr_t origBytes = *((byteptr_t *)p);
+      Trampoline *tramp = (Trampoline*)p;
+      byteptr_t origBytes = (byteptr_t)tramp->origFunction;
 
       // If CreateTrampoline failed, we may have an empty trampoline.
       if (!origBytes) {
         continue;
       }
 
       // If other code has changed this function, it is not safe to modify.
 #if defined(_M_IX86)
@@ -259,17 +260,17 @@ public:
       // ensure we can modify the original code
       DWORD op;
       if (!VirtualProtectEx(GetCurrentProcess(), origBytes, nBytes, PAGE_EXECUTE_READWRITE, &op)) {
         //printf ("VirtualProtectEx failed! %d\n", GetLastError());
         continue;
       }
       // Remove the hook by making the original function jump directly
       // in the trampoline.
-      intptr_t dest = (intptr_t)(p + sizeof(void *));
+      intptr_t dest = (intptr_t)(&tramp->code[0]);
 #if defined(_M_IX86)
       *((intptr_t*)(origBytes+1)) = dest - (intptr_t)(origBytes+5); // target displacement
 #elif defined(_M_X64)
       *((intptr_t*)(origBytes+2)) = dest;
 #else
 #error "Unknown processor type"
 #endif
       // restore protection; if this fails we can't really do anything about it
@@ -339,32 +340,41 @@ public:
     }
 
     return true;
   }
 
 protected:
   const static int kPageSize = 4096;
   const static int kHookSize = 128;
+  const static int kCodeSize = 100;
 
   const static uint8_t opTrampolineRelativeJump = 0xe9;
   const static uint16_t opTrampolineRegLoad = 0xbb49;
 
   HMODULE mModule;
   byteptr_t mHookPage;
   int mMaxHooks;
   int mCurHooks;
 
+  struct Trampoline
+  {
+    void *origFunction;
+    uint8_t code[kCodeSize];
+  };
+
+  static_assert(sizeof(Trampoline) <= kHookSize, "Trampolines too big");
+
   void CreateTrampoline(void *origFunction,
                         intptr_t dest,
                         void **outTramp)
   {
     *outTramp = nullptr;
 
-    byteptr_t tramp = FindTrampolineSpace();
+    Trampoline *tramp = FindTrampolineSpace();
     if (!tramp)
       return;
 
     byteptr_t origBytes = (byteptr_t) origFunction;
 
     int nBytes = 0;
     int pJmp32 = -1;
 
@@ -575,66 +585,65 @@ protected:
       } else {
         return;
       }
     }
 #else
 #error "Unknown processor type"
 #endif
 
-    if (nBytes > 100) {
+    if (nBytes > kCodeSize) {
       //printf ("Too big!");
       return;
     }
 
     // We keep the address of the original function in the first bytes of
     // the trampoline buffer
-    *((void **)tramp) = origFunction;
-    tramp += sizeof(void *);
+    tramp->origFunction = origFunction;
 
-    memcpy(tramp, origFunction, nBytes);
+    memcpy(&tramp->code[0], origFunction, nBytes);
 
     // OrigFunction+N, the target of the trampoline
     byteptr_t trampDest = origBytes + nBytes;
 
 #if defined(_M_IX86)
     if (pJmp32 >= 0) {
       // Jump directly to the original target of the jump instead of jumping to the
       // original function.
       // Adjust jump target displacement to jump location in the trampoline.
-      *((intptr_t*)(tramp+pJmp32+1)) += origBytes - tramp;
+      *((intptr_t*)(&tramp->code[pJmp32+1])) += origBytes - &tramp->code[0];
     } else {
-      tramp[nBytes] = opTrampolineRelativeJump; // jmp
-      *((intptr_t*)(tramp+nBytes+1)) = (intptr_t)trampDest - (intptr_t)(tramp+nBytes+5); // target displacement
+      tramp->code[nBytes] = opTrampolineRelativeJump; // jmp
+      *((intptr_t*)(&tramp->code[nBytes+1])) = (intptr_t)trampDest - (intptr_t)(&tramp->code[nBytes+5]); // target displacement
     }
 #elif defined(_M_X64)
     // If JMP32 opcode found, we don't insert to trampoline jump 
     if (pJmp32 >= 0) {
       // mov r11, address
-      *((uint16_t*)(tramp+pJmp32)) = opTrampolineRegLoad;
-      *((intptr_t*)(tramp+pJmp32+2)) = (intptr_t)directJmpAddr;
+      *((uint16_t*)(&tramp->code[pJmp32])) = opTrampolineRegLoad;
+      *((intptr_t*)(&tramp->code[pJmp32+2])) = (intptr_t)directJmpAddr;
 
       // jmp r11
-      tramp[pJmp32+10] = 0x41;
-      tramp[pJmp32+11] = 0xff;
-      tramp[pJmp32+12] = 0xe3;
+      tramp->code[pJmp32+10] = 0x41;
+      tramp->code[pJmp32+11] = 0xff;
+      tramp->code[pJmp32+12] = 0xe3;
     } else {
       // mov r11, address
-      *((uint16_t*)(tramp+nBytes)) = opTrampolineRegLoad;
-      *((intptr_t*)(tramp+nBytes+2)) = (intptr_t)trampDest;
+      *((uint16_t*)(&tramp->code[nBytes])) = opTrampolineRegLoad;
+      *((intptr_t*)(&tramp->code[nBytes+2])) = (intptr_t)trampDest;
 
       // jmp r11
-      tramp[nBytes+10] = 0x41;
-      tramp[nBytes+11] = 0xff;
-      tramp[nBytes+12] = 0xe3;
+      tramp->code[nBytes+10] = 0x41;
+      tramp->code[nBytes+11] = 0xff;
+      tramp->code[nBytes+12] = 0xe3;
     }
 #endif
 
     // The trampoline is now valid.
-    *outTramp = tramp;
+    *outTramp = &tramp->code[0];
 
     // ensure we can modify the original code
     DWORD op;
     if (!VirtualProtectEx(GetCurrentProcess(), origFunction, nBytes, PAGE_EXECUTE_READWRITE, &op)) {
       //printf ("VirtualProtectEx failed! %d\n", GetLastError());
       return;
     }
 
@@ -652,26 +661,26 @@ protected:
     origBytes[11] = 0xff;
     origBytes[12] = 0xe3;
 #endif
 
     // restore protection; if this fails we can't really do anything about it
     VirtualProtectEx(GetCurrentProcess(), origFunction, nBytes, op, &op);
   }
 
-  byteptr_t FindTrampolineSpace()
+  Trampoline* FindTrampolineSpace()
   {
     if (mCurHooks >= mMaxHooks)
-      return 0;
+      return nullptr;
 
     byteptr_t p = mHookPage + mCurHooks*kHookSize;
 
     mCurHooks++;
 
-    return p;
+    return (Trampoline*)p;
   }
 };
 
 } // namespace internal
 
 class WindowsDllInterceptor
 {
   internal::WindowsDllNopSpacePatcher mNopSpacePatcher;