Commit db0c3185 authored by mmaerean@adobe.com's avatar mmaerean@adobe.com

Update third_party/mach_override from...

Update third_party/mach_override from https://github.com/rentzsch/mach_star/mach_override to include the fix for building Chromium on 64 bits.

BUG=138535

Review URL: https://chromiumcodereview.appspot.com/10834127

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150529 0039d316-1c4b-4281-b951-d872f2087c98
parent 752ad239
...@@ -2,8 +2,8 @@ Name: mach_override ...@@ -2,8 +2,8 @@ Name: mach_override
Short Name: Part of the mach_star project Short Name: Part of the mach_star project
Version: Unknown Version: Unknown
URL: https://github.com/rentzsch/mach_star URL: https://github.com/rentzsch/mach_star
Date: 08/19/2011 Date: 08/01/2012
Revision: 87f491f8acef924d2ba90dd55fc23ad64f9d5bbd Revision: 6c4965586d28b931d19b428832fe5de968fd7d82
License: MIT License: MIT
Security Critical: Yes Security Critical: Yes
...@@ -11,18 +11,10 @@ Security Critical: Yes ...@@ -11,18 +11,10 @@ Security Critical: Yes
Description: Description:
This is the mach_override part of mach_star, namely: This is the mach_override part of mach_star, namely:
https://github.com/rentzsch/mach_star/tree/87f491f8acef924d2ba90dd55fc23ad64f9d5bbd https://github.com/rentzsch/mach_star/tree/6c4965586d28b931d19b428832fe5de968fd7d82
This package is used to replace framework functions with different This package is used to replace framework functions with different
implementations at run time. implementations at run time.
Local Modifications: Local Modifications: None
reentryIsland is allocated in high memory with vm_allocate rather than the
heap with malloc by changing the allocation policy to kAllocateHigh. It
appears probable that putting the reentry island in the heap causes its page
to lose execute permission at some point under some circumstances, which
results in a crash on Lion. This modification is temoprary to simply test
out the theory. If proven, the code will be improved somewhat.
http://crbug.com/93736.
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#pragma mark - #pragma mark -
#pragma mark (Constants) #pragma mark (Constants)
#define kPageSize 4096
#if defined(__ppc__) || defined(__POWERPC__) #if defined(__ppc__) || defined(__POWERPC__)
long kIslandTemplate[] = { long kIslandTemplate[] = {
...@@ -76,9 +77,6 @@ char kIslandTemplate[] = { ...@@ -76,9 +77,6 @@ char kIslandTemplate[] = {
#endif #endif
#define kAllocateHigh 1
#define kAllocateNormal 0
/************************** /**************************
* *
* Data Types * Data Types
...@@ -89,7 +87,6 @@ char kIslandTemplate[] = { ...@@ -89,7 +87,6 @@ char kIslandTemplate[] = {
typedef struct { typedef struct {
char instructions[sizeof(kIslandTemplate)]; char instructions[sizeof(kIslandTemplate)];
int allocatedHigh;
} BranchIsland; } BranchIsland;
/************************** /**************************
...@@ -103,7 +100,6 @@ typedef struct { ...@@ -103,7 +100,6 @@ typedef struct {
mach_error_t mach_error_t
allocateBranchIsland( allocateBranchIsland(
BranchIsland **island, BranchIsland **island,
int allocateHigh,
void *originalFunctionAddress); void *originalFunctionAddress);
mach_error_t mach_error_t
...@@ -134,7 +130,17 @@ eatKnownInstructions( ...@@ -134,7 +130,17 @@ eatKnownInstructions(
unsigned char *code, unsigned char *code,
uint64_t *newInstruction, uint64_t *newInstruction,
int *howManyEaten, int *howManyEaten,
char *originalInstructions ); char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes );
static void
fixupInstructions(
void *originalFunction,
void *escapeIsland,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes );
#endif #endif
/******************************************************************************* /*******************************************************************************
...@@ -148,12 +154,10 @@ eatKnownInstructions( ...@@ -148,12 +154,10 @@ eatKnownInstructions(
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
mach_error_t makeIslandExecutable(void *address) { mach_error_t makeIslandExecutable(void *address) {
mach_error_t err = err_none; mach_error_t err = err_none;
vm_size_t pageSize; uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
host_page_size( mach_host_self(), &pageSize );
uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
int e = err_none; int e = err_none;
e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE); e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
e |= msync((void *)page, pageSize, MS_INVALIDATE ); e |= msync((void *)page, kPageSize, MS_INVALIDATE );
if (e) { if (e) {
err = err_cannot_override; err = err_cannot_override;
} }
...@@ -172,17 +176,16 @@ mach_override_ptr( ...@@ -172,17 +176,16 @@ mach_override_ptr(
// this addresses overriding such functions as AudioOutputUnitStart() // this addresses overriding such functions as AudioOutputUnitStart()
// test with modified DefaultOutputUnit project // test with modified DefaultOutputUnit project
#if defined(__x86_64__) || defined(__i386__)
for(;;){
if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+0x????????
originalFunctionAddress=(void*)((char*)originalFunctionAddress+5+*(int32_t *)((char*)originalFunctionAddress+1));
#if defined(__x86_64__) #if defined(__x86_64__)
else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????] for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1)); originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
else break;
}
#elif defined(__i386__) #elif defined(__i386__)
else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x???????? for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1); originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
#endif
else break; else break;
} }
#endif #endif
...@@ -200,11 +203,15 @@ mach_override_ptr( ...@@ -200,11 +203,15 @@ mach_override_ptr(
err = err_cannot_override; err = err_cannot_override;
#elif defined(__i386__) || defined(__x86_64__) #elif defined(__i386__) || defined(__x86_64__)
int eatenCount = 0; int eatenCount = 0;
int originalInstructionCount = 0;
char originalInstructions[kOriginalInstructionsSize]; char originalInstructions[kOriginalInstructionsSize];
uint8_t originalInstructionSizes[kOriginalInstructionsSize];
uint64_t jumpRelativeInstruction = 0; // JMP uint64_t jumpRelativeInstruction = 0; // JMP
Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr, Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
&jumpRelativeInstruction, &eatenCount, originalInstructions); &jumpRelativeInstruction, &eatenCount,
originalInstructions, &originalInstructionCount,
originalInstructionSizes );
if (eatenCount > kOriginalInstructionsSize) { if (eatenCount > kOriginalInstructionsSize) {
//printf ("Too many instructions eaten\n"); //printf ("Too many instructions eaten\n");
overridePossible = false; overridePossible = false;
...@@ -228,7 +235,7 @@ mach_override_ptr( ...@@ -228,7 +235,7 @@ mach_override_ptr(
// Allocate and target the escape island to the overriding function. // Allocate and target the escape island to the overriding function.
BranchIsland *escapeIsland = NULL; BranchIsland *escapeIsland = NULL;
if( !err ) if( !err )
err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress ); err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
...@@ -264,10 +271,13 @@ mach_override_ptr( ...@@ -264,10 +271,13 @@ mach_override_ptr(
} }
#endif #endif
// Optionally allocate & return the reentry island. // 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.
BranchIsland *reentryIsland = NULL; BranchIsland *reentryIsland = NULL;
if( !err && originalFunctionReentryIsland ) { if( !err && originalFunctionReentryIsland ) {
err = allocateBranchIsland( &reentryIsland, kAllocateHigh, NULL); err = allocateBranchIsland( &reentryIsland, escapeIsland);
if( !err ) if( !err )
*originalFunctionReentryIsland = reentryIsland; *originalFunctionReentryIsland = reentryIsland;
} }
...@@ -310,6 +320,9 @@ mach_override_ptr( ...@@ -310,6 +320,9 @@ mach_override_ptr(
// //
// Note that on i386, we do not support someone else changing the code under our feet // Note that on i386, we do not support someone else changing the code under our feet
if ( !err ) { if ( !err ) {
fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
originalInstructionCount, originalInstructionSizes );
if( reentryIsland ) if( reentryIsland )
err = setBranchIslandTarget_i386( reentryIsland, err = setBranchIslandTarget_i386( reentryIsland,
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
...@@ -348,9 +361,6 @@ mach_override_ptr( ...@@ -348,9 +361,6 @@ mach_override_ptr(
Implementation: Allocates memory for a branch island. Implementation: Allocates memory for a branch island.
@param island <- The allocated 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 @result <- mach_error_t
***************************************************************************/ ***************************************************************************/
...@@ -358,60 +368,63 @@ mach_override_ptr( ...@@ -358,60 +368,63 @@ mach_override_ptr(
mach_error_t mach_error_t
allocateBranchIsland( allocateBranchIsland(
BranchIsland **island, BranchIsland **island,
int allocateHigh,
void *originalFunctionAddress) void *originalFunctionAddress)
{ {
assert( island ); assert( island );
assert( sizeof( BranchIsland ) <= kPageSize );
mach_error_t err = err_none;
vm_map_t task_self = mach_task_self();
if( allocateHigh ) { vm_address_t original_address = (vm_address_t) originalFunctionAddress;
vm_size_t pageSize; static vm_address_t last_allocated = 0;
err = host_page_size( mach_host_self(), &pageSize ); vm_address_t address =
if( !err ) { last_allocated ? last_allocated : original_address;
assert( sizeof( BranchIsland ) <= pageSize );
#if defined(__x86_64__) for (;;) {
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_size_t vmsize = 0;
vm_address_t last = 0x0; 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);
#else #else
vm_address_t first = 0xffc00000; vm_region_basic_info_data_64_t info;
vm_address_t last = 0xfffe0000; 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);
#endif #endif
if (kr != KERN_SUCCESS)
return kr;
vm_address_t page = first; // Don't underflow. This could be made to work, but this is a
int allocated = 0; // convenient place to give up.
vm_map_t task_self = mach_task_self(); assert((address & (kPageSize - 1)) == 0);
if (address == 0)
while( !err && !allocated && page != last ) { break;
err = vm_allocate( task_self, &page, pageSize, 0 ); // Go back one page.
if( err == err_none ) vm_address_t new_address = address - kPageSize;
allocated = 1; #if __WORDSIZE == 64
else if( err == KERN_NO_SPACE ) { if(original_address - new_address - 5 > INT32_MAX)
#if defined(__x86_64__) break;
page -= pageSize;
#else
page += pageSize;
#endif #endif
err = err_none; address = new_address;
}
} // Try to allocate this page.
if( allocated ) kr = vm_allocate(task_self, &address, kPageSize, 0);
*island = (BranchIsland*) page; if (kr == KERN_SUCCESS) {
else if( !allocated && !err ) *island = (BranchIsland*) address;
err = KERN_NO_SPACE; last_allocated = address;
return err_none;
} }
} else { if (kr != KERN_NO_SPACE)
void *block = malloc( sizeof( BranchIsland ) ); return kr;
if( block )
*island = block;
else
err = KERN_NO_SPACE;
} }
if( !err )
(**island).allocatedHigh = allocateHigh; return KERN_NO_SPACE;
return err;
} }
/***************************************************************************//** /***************************************************************************//**
...@@ -428,24 +441,9 @@ freeBranchIsland( ...@@ -428,24 +441,9 @@ freeBranchIsland(
{ {
assert( island ); assert( island );
assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] ); assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
assert( island->allocatedHigh ); assert( sizeof( BranchIsland ) <= kPageSize );
return vm_deallocate( mach_task_self(), (vm_address_t) island,
mach_error_t err = err_none; kPageSize );
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;
} }
/***************************************************************************//** /***************************************************************************//**
...@@ -547,6 +545,7 @@ typedef struct { ...@@ -547,6 +545,7 @@ typedef struct {
#if defined(__i386__) #if defined(__i386__)
static AsmInstructionMatch possibleInstructions[] = { 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 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
{ 0x1, {0xFF}, {0x90} }, // nop { 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xFF}, {0x55} }, // push %esp { 0x1, {0xFF}, {0x55} }, // push %esp
...@@ -560,19 +559,24 @@ static AsmInstructionMatch possibleInstructions[] = { ...@@ -560,19 +559,24 @@ static AsmInstructionMatch possibleInstructions[] = {
{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %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 { 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 } { 0x0 }
}; };
#elif defined(__x86_64__) #elif defined(__x86_64__)
static AsmInstructionMatch possibleInstructions[] = { static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x1, {0xFF}, {0x90} }, // nop { 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xF8}, {0x50} }, // push %rX { 0x1, {0xF8}, {0x50} }, // push %rX
{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp { 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, {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}, {0x41, 0x00} }, // push %rXX
{ 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
{ 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi) { 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 } { 0x0 }
}; };
#endif #endif
...@@ -597,17 +601,21 @@ static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* ...@@ -597,17 +601,21 @@ static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
static Boolean static Boolean
eatKnownInstructions( eatKnownInstructions(
unsigned char *code, unsigned char *code,
uint64_t* newInstruction, uint64_t *newInstruction,
int* howManyEaten, int *howManyEaten,
char* originalInstructions ) char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes )
{ {
Boolean allInstructionsKnown = true; Boolean allInstructionsKnown = true;
int totalEaten = 0; int totalEaten = 0;
unsigned char* ptr = code; unsigned char* ptr = code;
int remainsToEat = 5; // a JMP instruction takes 5 bytes int remainsToEat = 5; // a JMP instruction takes 5 bytes
int instructionIndex = 0;
if (howManyEaten) *howManyEaten = 0; if (howManyEaten) *howManyEaten = 0;
if (originalInstructionCount) *originalInstructionCount = 0;
while (remainsToEat > 0) { while (remainsToEat > 0) {
Boolean curInstructionKnown = false; Boolean curInstructionKnown = false;
...@@ -630,6 +638,10 @@ eatKnownInstructions( ...@@ -630,6 +638,10 @@ eatKnownInstructions(
ptr += eaten; ptr += eaten;
remainsToEat -= eaten; remainsToEat -= eaten;
totalEaten += eaten; totalEaten += eaten;
if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
instructionIndex += 1;
if (originalInstructionCount) *originalInstructionCount = instructionIndex;
} }
...@@ -660,6 +672,30 @@ eatKnownInstructions( ...@@ -660,6 +672,30 @@ eatKnownInstructions(
return allInstructionsKnown; 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 #endif
#if defined(__i386__) #if defined(__i386__)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment