| Index: third_party/mach_override/mach_override.c
|
| ===================================================================
|
| --- third_party/mach_override/mach_override.c (revision 150900)
|
| +++ third_party/mach_override/mach_override.c (working copy)
|
| @@ -23,7 +23,6 @@
|
| #pragma mark -
|
| #pragma mark (Constants)
|
|
|
| -#define kPageSize 4096
|
| #if defined(__ppc__) || defined(__POWERPC__)
|
|
|
| long kIslandTemplate[] = {
|
| @@ -77,6 +76,9 @@
|
|
|
| #endif
|
|
|
| +#define kAllocateHigh 1
|
| +#define kAllocateNormal 0
|
| +
|
| /**************************
|
| *
|
| * Data Types
|
| @@ -87,6 +89,7 @@
|
|
|
| typedef struct {
|
| char instructions[sizeof(kIslandTemplate)];
|
| + int allocatedHigh;
|
| } BranchIsland;
|
|
|
| /**************************
|
| @@ -100,6 +103,7 @@
|
| mach_error_t
|
| allocateBranchIsland(
|
| BranchIsland **island,
|
| + int allocateHigh,
|
| void *originalFunctionAddress);
|
|
|
| mach_error_t
|
| @@ -130,17 +134,7 @@
|
| unsigned char *code,
|
| uint64_t *newInstruction,
|
| int *howManyEaten,
|
| - char *originalInstructions,
|
| - int *originalInstructionCount,
|
| - uint8_t *originalInstructionSizes );
|
| -
|
| - static void
|
| -fixupInstructions(
|
| - void *originalFunction,
|
| - void *escapeIsland,
|
| - void *instructionsToFix,
|
| - int instructionCount,
|
| - uint8_t *instructionSizes );
|
| + char *originalInstructions );
|
| #endif
|
|
|
| /*******************************************************************************
|
| @@ -154,10 +148,12 @@
|
| #if defined(__i386__) || defined(__x86_64__)
|
| mach_error_t makeIslandExecutable(void *address) {
|
| mach_error_t err = err_none;
|
| - uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
|
| + vm_size_t pageSize;
|
| + host_page_size( mach_host_self(), &pageSize );
|
| + uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
|
| int e = err_none;
|
| - e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
|
| - e |= msync((void *)page, kPageSize, MS_INVALIDATE );
|
| + e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
|
| + e |= msync((void *)page, pageSize, MS_INVALIDATE );
|
| if (e) {
|
| err = err_cannot_override;
|
| }
|
| @@ -176,16 +172,17 @@
|
|
|
| // this addresses overriding such functions as AudioOutputUnitStart()
|
| // test with modified DefaultOutputUnit project
|
| -#if defined(__x86_64__)
|
| +#if defined(__x86_64__) || defined(__i386__)
|
| for(;;){
|
| - if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
|
| + if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+0x????????
|
| + originalFunctionAddress=(void*)((char*)originalFunctionAddress+5+*(int32_t *)((char*)originalFunctionAddress+1));
|
| +#if defined(__x86_64__)
|
| + else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
|
| originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
|
| - else break;
|
| - }
|
| #elif defined(__i386__)
|
| - for(;;){
|
| - if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
|
| + else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
|
| originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
|
| +#endif
|
| else break;
|
| }
|
| #endif
|
| @@ -203,15 +200,11 @@
|
| err = err_cannot_override;
|
| #elif defined(__i386__) || defined(__x86_64__)
|
| int eatenCount = 0;
|
| - int originalInstructionCount = 0;
|
| char originalInstructions[kOriginalInstructionsSize];
|
| - uint8_t originalInstructionSizes[kOriginalInstructionsSize];
|
| uint64_t jumpRelativeInstruction = 0; // JMP
|
|
|
| Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
|
| - &jumpRelativeInstruction, &eatenCount,
|
| - originalInstructions, &originalInstructionCount,
|
| - originalInstructionSizes );
|
| + &jumpRelativeInstruction, &eatenCount, originalInstructions);
|
| if (eatenCount > kOriginalInstructionsSize) {
|
| //printf ("Too many instructions eaten\n");
|
| overridePossible = false;
|
| @@ -235,7 +228,7 @@
|
| // Allocate and target the escape island to the overriding function.
|
| BranchIsland *escapeIsland = NULL;
|
| if( !err )
|
| - err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
|
| + err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress );
|
| if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
|
|
|
|
|
| @@ -271,13 +264,10 @@
|
| }
|
| #endif
|
|
|
| - // Optionally allocate & return the reentry island. This may contain relocated
|
| - // jmp instructions and so has all the same addressing reachability requirements
|
| - // the escape island has to the original function, except the escape island is
|
| - // technically our original function.
|
| + // Optionally allocate & return the reentry island.
|
| BranchIsland *reentryIsland = NULL;
|
| if( !err && originalFunctionReentryIsland ) {
|
| - err = allocateBranchIsland( &reentryIsland, escapeIsland);
|
| + err = allocateBranchIsland( &reentryIsland, kAllocateHigh, NULL);
|
| if( !err )
|
| *originalFunctionReentryIsland = reentryIsland;
|
| }
|
| @@ -320,9 +310,6 @@
|
| //
|
| // Note that on i386, we do not support someone else changing the code under our feet
|
| if ( !err ) {
|
| - fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
|
| - originalInstructionCount, originalInstructionSizes );
|
| -
|
| if( reentryIsland )
|
| err = setBranchIslandTarget_i386( reentryIsland,
|
| (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
|
| @@ -361,6 +348,9 @@
|
| Implementation: Allocates memory for a branch island.
|
|
|
| @param island <- The allocated island.
|
| + @param allocateHigh -> Whether to allocate the island at the end of the
|
| + address space (for use with the branch absolute
|
| + instruction).
|
| @result <- mach_error_t
|
|
|
| ***************************************************************************/
|
| @@ -368,63 +358,60 @@
|
| mach_error_t
|
| allocateBranchIsland(
|
| BranchIsland **island,
|
| + int allocateHigh,
|
| void *originalFunctionAddress)
|
| {
|
| assert( island );
|
| - assert( sizeof( BranchIsland ) <= kPageSize );
|
| -
|
| - vm_map_t task_self = mach_task_self();
|
| - vm_address_t original_address = (vm_address_t) originalFunctionAddress;
|
| - static vm_address_t last_allocated = 0;
|
| - vm_address_t address =
|
| - last_allocated ? last_allocated : original_address;
|
| -
|
| - for (;;) {
|
| - vm_size_t vmsize = 0;
|
| - memory_object_name_t object = 0;
|
| - kern_return_t kr = 0;
|
| - vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
|
| - // Find the page the address is in.
|
| -#if __WORDSIZE == 32
|
| - vm_region_basic_info_data_t info;
|
| - mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
|
| - kr = vm_region(task_self, &address, &vmsize, flavor,
|
| - (vm_region_info_t)&info, &info_count, &object);
|
| +
|
| + mach_error_t err = err_none;
|
| +
|
| + if( allocateHigh ) {
|
| + vm_size_t pageSize;
|
| + err = host_page_size( mach_host_self(), &pageSize );
|
| + if( !err ) {
|
| + assert( sizeof( BranchIsland ) <= pageSize );
|
| +#if defined(__x86_64__)
|
| + vm_address_t first = (uint64_t)originalFunctionAddress & ~(uint64_t)(((uint64_t)1 << 31) - 1) | ((uint64_t)1 << 31); // start in the middle of the page?
|
| + vm_address_t last = 0x0;
|
| #else
|
| - vm_region_basic_info_data_64_t info;
|
| - mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
|
| - kr = vm_region_64(task_self, &address, &vmsize, flavor,
|
| - (vm_region_info_t)&info, &info_count, &object);
|
| + vm_address_t first = 0xffc00000;
|
| + vm_address_t last = 0xfffe0000;
|
| #endif
|
| - if (kr != KERN_SUCCESS)
|
| - return kr;
|
|
|
| - // Don't underflow. This could be made to work, but this is a
|
| - // convenient place to give up.
|
| - assert((address & (kPageSize - 1)) == 0);
|
| - if (address == 0)
|
| - break;
|
| + vm_address_t page = first;
|
| + int allocated = 0;
|
| + vm_map_t task_self = mach_task_self();
|
| +
|
| + while( !err && !allocated && page != last ) {
|
|
|
| - // Go back one page.
|
| - vm_address_t new_address = address - kPageSize;
|
| -#if __WORDSIZE == 64
|
| - if(original_address - new_address - 5 > INT32_MAX)
|
| - break;
|
| + err = vm_allocate( task_self, &page, pageSize, 0 );
|
| + if( err == err_none )
|
| + allocated = 1;
|
| + else if( err == KERN_NO_SPACE ) {
|
| +#if defined(__x86_64__)
|
| + page -= pageSize;
|
| +#else
|
| + page += pageSize;
|
| #endif
|
| - address = new_address;
|
| -
|
| - // Try to allocate this page.
|
| - kr = vm_allocate(task_self, &address, kPageSize, 0);
|
| - if (kr == KERN_SUCCESS) {
|
| - *island = (BranchIsland*) address;
|
| - last_allocated = address;
|
| - return err_none;
|
| + err = err_none;
|
| + }
|
| + }
|
| + if( allocated )
|
| + *island = (BranchIsland*) page;
|
| + else if( !allocated && !err )
|
| + err = KERN_NO_SPACE;
|
| }
|
| - if (kr != KERN_NO_SPACE)
|
| - return kr;
|
| + } else {
|
| + void *block = malloc( sizeof( BranchIsland ) );
|
| + if( block )
|
| + *island = block;
|
| + else
|
| + err = KERN_NO_SPACE;
|
| }
|
| -
|
| - return KERN_NO_SPACE;
|
| + if( !err )
|
| + (**island).allocatedHigh = allocateHigh;
|
| +
|
| + return err;
|
| }
|
|
|
| /***************************************************************************//**
|
| @@ -441,9 +428,24 @@
|
| {
|
| assert( island );
|
| assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
|
| - assert( sizeof( BranchIsland ) <= kPageSize );
|
| - return vm_deallocate( mach_task_self(), (vm_address_t) island,
|
| - kPageSize );
|
| + assert( island->allocatedHigh );
|
| +
|
| + mach_error_t err = err_none;
|
| +
|
| + if( island->allocatedHigh ) {
|
| + vm_size_t pageSize;
|
| + err = host_page_size( mach_host_self(), &pageSize );
|
| + if( !err ) {
|
| + assert( sizeof( BranchIsland ) <= pageSize );
|
| + err = vm_deallocate(
|
| + mach_task_self(),
|
| + (vm_address_t) island, pageSize );
|
| + }
|
| + } else {
|
| + free( island );
|
| + }
|
| +
|
| + return err;
|
| }
|
|
|
| /***************************************************************************//**
|
| @@ -545,7 +547,6 @@
|
|
|
| #if defined(__i386__)
|
| static AsmInstructionMatch possibleInstructions[] = {
|
| - { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
|
| { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
|
| { 0x1, {0xFF}, {0x90} }, // nop
|
| { 0x1, {0xFF}, {0x55} }, // push %esp
|
| @@ -559,24 +560,19 @@
|
| { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
|
| { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
|
| { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
|
| - { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
|
| { 0x0 }
|
| };
|
| #elif defined(__x86_64__)
|
| static AsmInstructionMatch possibleInstructions[] = {
|
| - { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
|
| { 0x1, {0xFF}, {0x90} }, // nop
|
| { 0x1, {0xF8}, {0x50} }, // push %rX
|
| { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
|
| { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
|
| { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
|
| - { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} }, // movsbl %sil, %ecx
|
| { 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
|
| { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
|
| { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
|
| { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
|
| - { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
|
| - { 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %eax
|
| { 0x0 }
|
| };
|
| #endif
|
| @@ -601,21 +597,17 @@
|
| #if defined(__i386__) || defined(__x86_64__)
|
| static Boolean
|
| eatKnownInstructions(
|
| - unsigned char *code,
|
| - uint64_t *newInstruction,
|
| - int *howManyEaten,
|
| - char *originalInstructions,
|
| - int *originalInstructionCount,
|
| - uint8_t *originalInstructionSizes )
|
| + unsigned char *code,
|
| + uint64_t* newInstruction,
|
| + int* howManyEaten,
|
| + char* originalInstructions )
|
| {
|
| Boolean allInstructionsKnown = true;
|
| int totalEaten = 0;
|
| unsigned char* ptr = code;
|
| int remainsToEat = 5; // a JMP instruction takes 5 bytes
|
| - int instructionIndex = 0;
|
|
|
| if (howManyEaten) *howManyEaten = 0;
|
| - if (originalInstructionCount) *originalInstructionCount = 0;
|
| while (remainsToEat > 0) {
|
| Boolean curInstructionKnown = false;
|
|
|
| @@ -638,10 +630,6 @@
|
| ptr += eaten;
|
| remainsToEat -= eaten;
|
| totalEaten += eaten;
|
| -
|
| - if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
|
| - instructionIndex += 1;
|
| - if (originalInstructionCount) *originalInstructionCount = instructionIndex;
|
| }
|
|
|
|
|
| @@ -672,30 +660,6 @@
|
|
|
| return allInstructionsKnown;
|
| }
|
| -
|
| - static void
|
| -fixupInstructions(
|
| - void *originalFunction,
|
| - void *escapeIsland,
|
| - void *instructionsToFix,
|
| - int instructionCount,
|
| - uint8_t *instructionSizes )
|
| -{
|
| - int index;
|
| - for (index = 0;index < instructionCount;index += 1)
|
| - {
|
| - if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
|
| - {
|
| - uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
|
| - uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
|
| - *jumpOffsetPtr += offset;
|
| - }
|
| -
|
| - originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
|
| - escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
|
| - instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
|
| - }
|
| -}
|
| #endif
|
|
|
| #if defined(__i386__)
|
|
|