Reduce the minimum required hot patching size from 14 to 5 on x86_64
if the distance from a hot-patch target function to the trampoline memory is within 2GB.pull/142/head
parent
4c8f9694a2
commit
1cc4406358
|
@ -14,9 +14,7 @@
|
|||
|
||||
#define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
|
||||
|
||||
unsigned int jump_size();
|
||||
|
||||
int hot_patch_function(void* targetFunction, void* newFunction, void* trampolineFunction, unsigned int *trampolinesize, bool log_info);
|
||||
int hot_patch_function(void* targetFunction, void* newFunction, void* trampolineFunction, unsigned int *trampolinesize, unsigned int *usedsize, bool log_info);
|
||||
|
||||
void remove_hot_patch_function(void* targetFunction, void* trampolineFunction, unsigned int trampolinesize, bool log_info);
|
||||
|
||||
|
|
|
@ -1317,8 +1317,9 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
|
|||
*trampoline_func_pp = (void*)(addrs & ~0x0F);
|
||||
|
||||
// hot patch functions
|
||||
unsigned int used_size;
|
||||
int res = hot_patch_function(target_function, audit_function,
|
||||
*trampoline_func_pp, trampoline_size, true);
|
||||
*trampoline_func_pp, trampoline_size, &used_size, true);
|
||||
if (res != 0)
|
||||
{
|
||||
// hot patch failed.
|
||||
|
@ -1327,9 +1328,9 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
|
|||
return 1;
|
||||
}
|
||||
sql_print_information(
|
||||
"%s hot patch for: %s (%p) complete. Audit func: %p, Trampoline address: %p size: %u.",
|
||||
log_prefix, func_name, target_function, audit_function, *trampoline_func_pp, *trampoline_size);
|
||||
trampoline_mem_free = (void *)(((DATATYPE_ADDRESS)*trampoline_func_pp) + *trampoline_size + jump_size());
|
||||
"%s hot patch for: %s (%p) complete. Audit func: %p, Trampoline address: %p, size: %u, used: %u.",
|
||||
log_prefix, func_name, target_function, audit_function, *trampoline_func_pp, *trampoline_size, used_size);
|
||||
trampoline_mem_free = (void *)(((DATATYPE_ADDRESS)*trampoline_func_pp) + used_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1614,7 +1615,22 @@ static int audit_plugin_init(void *p)
|
|||
// align our trampoline mem on its own page
|
||||
const unsigned long page_size = GETPAGESIZE();
|
||||
const unsigned long std_page_size = 4096;
|
||||
if (page_size <= std_page_size)
|
||||
bool use_static_memory = (page_size <= std_page_size);
|
||||
int mmap_flags = MAP_PRIVATE|MAP_ANONYMOUS;
|
||||
|
||||
#ifdef __x86_64__
|
||||
size_t func_in_mysqld = (size_t)log_slow_statement;
|
||||
size_t func_in_plugin = (size_t)trampoline_dummy_func_for_mem;
|
||||
if (func_in_mysqld < INT_MAX && func_in_plugin > INT_MAX)
|
||||
{
|
||||
// When the distance from a hot patch function to trampoline_mem is within 2GB,
|
||||
// the minimum size of hot patching is reduced from 14 to 6.
|
||||
mmap_flags |= MAP_32BIT;
|
||||
use_static_memory = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (use_static_memory)
|
||||
{
|
||||
// use static executable memory we alocated via trampoline_dummy_func_for_mem
|
||||
DATATYPE_ADDRESS addrs = (DATATYPE_ADDRESS)trampoline_dummy_func_for_mem + (page_size - 1);
|
||||
|
@ -1625,7 +1641,7 @@ static int audit_plugin_init(void *p)
|
|||
}
|
||||
else // big pages for some reason. allocate mem using mmap
|
||||
{
|
||||
trampoline_mem = mmap(NULL, page_size, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
trampoline_mem = mmap(NULL, page_size, PROT_READ|PROT_EXEC, mmap_flags, -1, 0);
|
||||
if (MAP_FAILED == trampoline_mem)
|
||||
{
|
||||
sql_print_error("%s unable to mmap memory size: %lu, errno: %d. Aborting.",
|
||||
|
|
106
src/hot_patch.cc
106
src/hot_patch.cc
|
@ -145,19 +145,6 @@ static DATATYPE_ADDRESS get_page_address(void *pointer)
|
|||
return (longp & pageMask);
|
||||
}
|
||||
|
||||
//
|
||||
// This function retrieves the necessary size for the jump
|
||||
//
|
||||
|
||||
unsigned int jump_size()
|
||||
{
|
||||
#ifndef __x86_64__
|
||||
return 5;
|
||||
#else
|
||||
return 14;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// This function writes unconditional jumps
|
||||
// both for x86 and x64
|
||||
|
@ -189,11 +176,48 @@ static void WriteJump(void *pAddress, ULONG_PTR JumpTo)
|
|||
protect((void*)AddressPage, PAGE_SIZE);
|
||||
}
|
||||
|
||||
#ifndef __x86_64__
|
||||
|
||||
#define JUMP_SIZE 5
|
||||
|
||||
#else
|
||||
|
||||
#define JUMP_SIZE 14 // jump size of WriteJump()
|
||||
#define JUMP32_SIZE 5 // jump size of WriteJump32()
|
||||
|
||||
static bool CanUseJump32(void *pAddress, ULONG_PTR JumpTo)
|
||||
{
|
||||
int64_t diff = JumpTo - ((ULONG_PTR)pAddress + JUMP32_SIZE);
|
||||
if (INT32_MIN <= diff && diff <= INT32_MAX)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteJump32(void *pAddress, ULONG_PTR JumpTo)
|
||||
{
|
||||
int64_t diff = JumpTo - ((ULONG_PTR)pAddress + JUMP32_SIZE);
|
||||
DATATYPE_ADDRESS AddressPage = get_page_address(pAddress);
|
||||
unprotect((void*)AddressPage, PAGE_SIZE);
|
||||
|
||||
BYTE *pCur = (BYTE *) pAddress;
|
||||
*pCur++ = 0xE9; // jmp +imm32
|
||||
*(DWORD *)pCur = (DWORD)diff;
|
||||
|
||||
protect((void*)AddressPage, PAGE_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Hooks a function
|
||||
//
|
||||
static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_PTR trampolineFunction,
|
||||
unsigned int *trampolinesize)
|
||||
unsigned int *trampolinesize, unsigned int *usedsize)
|
||||
{
|
||||
#define MAX_INSTRUCTIONS 100
|
||||
uint8_t raw[MAX_INSTRUCTIONS];
|
||||
|
@ -203,6 +227,18 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_
|
|||
#define ASM_MODE 32
|
||||
#else
|
||||
#define ASM_MODE 64
|
||||
enum {
|
||||
// overwrite 14 bytes in targetFunction.
|
||||
// jump to newFunction by WriteJump().
|
||||
Jump64,
|
||||
// overwrite 5 bytes in targetFunction.
|
||||
// jump to newFunction by WriteJump32().
|
||||
Jump32,
|
||||
// overwrite 5 bytes in targetFunction.
|
||||
// jump to a region in trampolineFunction by WriteJump32()
|
||||
// and then jump to newFunction by WriteJump().
|
||||
IndirectJump,
|
||||
} jumpType = Jump64;
|
||||
#endif
|
||||
memcpy(raw, (void*)targetFunction, MAX_INSTRUCTIONS);
|
||||
ud_t ud_obj;
|
||||
|
@ -250,11 +286,28 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_
|
|||
|
||||
uCurrentSize += ud_insn_len (&ud_obj);
|
||||
InstrSize += ud_insn_len (&ud_obj);
|
||||
if (InstrSize >= jump_size()) // we have enough space so break
|
||||
if (InstrSize >= JUMP_SIZE) // we have enough space so break
|
||||
{
|
||||
disassemble_valid = true;
|
||||
break;
|
||||
}
|
||||
#ifdef __x86_64__
|
||||
if (InstrSize >= JUMP32_SIZE)
|
||||
{
|
||||
if (CanUseJump32((void *)targetFunction, newFunction))
|
||||
{
|
||||
disassemble_valid = true;
|
||||
jumpType = Jump32;
|
||||
break;
|
||||
}
|
||||
if (CanUseJump32((void *)targetFunction, trampolineFunction + uCurrentSize + JUMP_SIZE))
|
||||
{
|
||||
disassemble_valid = true;
|
||||
jumpType = IndirectJump;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (protect((void*)trampolineFunctionPage, PAGE_SIZE)) // 0 valid return
|
||||
|
@ -271,7 +324,26 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_
|
|||
}
|
||||
|
||||
WriteJump((BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
||||
*usedsize = uCurrentSize + JUMP_SIZE;
|
||||
#ifndef __x86_64__
|
||||
WriteJump((void *) targetFunction, newFunction);
|
||||
#else
|
||||
switch (jumpType) {
|
||||
ULONG_PTR addr;
|
||||
case Jump64:
|
||||
WriteJump((void *)targetFunction, newFunction);
|
||||
break;
|
||||
case Jump32:
|
||||
WriteJump32((void *)targetFunction, newFunction);
|
||||
break;
|
||||
case IndirectJump:
|
||||
addr = trampolineFunction + uCurrentSize + JUMP_SIZE;
|
||||
WriteJump32((void *)targetFunction, addr);
|
||||
WriteJump((void*)addr, newFunction);
|
||||
*usedsize += JUMP_SIZE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
*trampolinesize = uCurrentSize;
|
||||
return true;
|
||||
}
|
||||
|
@ -312,12 +384,12 @@ static void UnhookFunction(ULONG_PTR Function, ULONG_PTR trampolineFunction, uns
|
|||
* @Return 0 on success otherwise failure
|
||||
* @See MS Detours paper: http:// research.microsoft.com/pubs/68568/huntusenixnt99.pdf for some background info.
|
||||
*/
|
||||
int hot_patch_function(void *targetFunction, void *newFunction, void *trampolineFunction, unsigned int *trampolinesize, bool info_print)
|
||||
int hot_patch_function(void *targetFunction, void *newFunction, void *trampolineFunction, unsigned int *trampolinesize, unsigned int *usedsize, bool info_print)
|
||||
{
|
||||
DATATYPE_ADDRESS trampolinePage = get_page_address(trampolineFunction);
|
||||
cond_info_print(info_print, "%s hot patching function: %p, trampolineFunction: %p trampolinePage: %p",log_prefix, (void *)targetFunction, (void *)trampolineFunction, (void *)trampolinePage);
|
||||
if (HookFunction((ULONG_PTR) targetFunction, (ULONG_PTR) newFunction,
|
||||
(ULONG_PTR) trampolineFunction, trampolinesize))
|
||||
(ULONG_PTR) trampolineFunction, trampolinesize, usedsize))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue