• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2 	mach_override.c
3 		Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
4 		Some rights reserved: <http://opensource.org/licenses/mit-license.php>
5 
6 	***************************************************************************/
7 #ifdef __APPLE__
8 
9 #include "mach_override.h"
10 
11 #include <mach-o/dyld.h>
12 #include <mach/mach_host.h>
13 #include <mach/mach_init.h>
14 #include <mach/vm_map.h>
15 #include <sys/mman.h>
16 
17 #include <CoreServices/CoreServices.h>
18 
19 //#define DEBUG_DISASM 1
20 #undef DEBUG_DISASM
21 
22 /**************************
23 *
24 *	Constants
25 *
26 **************************/
27 #pragma mark	-
28 #pragma mark	(Constants)
29 
30 #if defined(__ppc__) || defined(__POWERPC__)
31 
32 static
33 long kIslandTemplate[] = {
34 	0x9001FFFC,	//	stw		r0,-4(SP)
35 	0x3C00DEAD,	//	lis		r0,0xDEAD
36 	0x6000BEEF,	//	ori		r0,r0,0xBEEF
37 	0x7C0903A6,	//	mtctr	r0
38 	0x8001FFFC,	//	lwz		r0,-4(SP)
39 	0x60000000,	//	nop		; optionally replaced
40 	0x4E800420 	//	bctr
41 };
42 
43 #define kAddressHi			3
44 #define kAddressLo			5
45 #define kInstructionHi		10
46 #define kInstructionLo		11
47 
48 #elif defined(__i386__)
49 
50 #define kOriginalInstructionsSize 16
51 
52 static
53 char kIslandTemplate[] = {
54 	// kOriginalInstructionsSize nop instructions so that we
55 	// should have enough space to host original instructions
56 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
57 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
58 	// Now the real jump instruction
59 	0xE9, 0xEF, 0xBE, 0xAD, 0xDE
60 };
61 
62 #define kInstructions	0
63 #define kJumpAddress    kInstructions + kOriginalInstructionsSize + 1
64 #elif defined(__x86_64__)
65 
66 #define kOriginalInstructionsSize 32
67 
68 #define kJumpAddress    kOriginalInstructionsSize + 6
69 
70 static
71 char kIslandTemplate[] = {
72 	// kOriginalInstructionsSize nop instructions so that we
73 	// should have enough space to host original instructions
74 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
75 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
76 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
77 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
78 	// Now the real jump instruction
79 	0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
80         0x00, 0x00, 0x00, 0x00,
81         0x00, 0x00, 0x00, 0x00
82 };
83 
84 #endif
85 
86 #define	kAllocateHigh		1
87 #define	kAllocateNormal		0
88 
89 /**************************
90 *
91 *	Data Types
92 *
93 **************************/
94 #pragma mark	-
95 #pragma mark	(Data Types)
96 
97 typedef	struct	{
98 	char	instructions[sizeof(kIslandTemplate)];
99 	int		allocatedHigh;
100 }	BranchIsland;
101 
102 /**************************
103 *
104 *	Funky Protos
105 *
106 **************************/
107 #pragma mark	-
108 #pragma mark	(Funky Protos)
109 
110 
111 	static mach_error_t
112 allocateBranchIsland(
113 		BranchIsland	**island,
114 		int				allocateHigh,
115 		void *originalFunctionAddress) __attribute__((visibility("hidden")));
116 
117 	static mach_error_t
118 freeBranchIsland(
119 		BranchIsland	*island ) __attribute__((visibility("hidden")));
120 
121 	static mach_error_t
122 defaultIslandMalloc(
123 	  void **ptr, size_t unused_size, void *hint) __attribute__((visibility("hidden")));
124 
125 	static mach_error_t
126 defaultIslandFree(
127    	void *ptr) __attribute__((visibility("hidden")));
128 
129 #if defined(__ppc__) || defined(__POWERPC__)
130 	static mach_error_t
131 setBranchIslandTarget(
132 		BranchIsland	*island,
133 		const void		*branchTo,
134 		long			instruction ) __attribute__((visibility("hidden")));
135 #endif
136 
137 #if defined(__i386__) || defined(__x86_64__)
138 static mach_error_t
139 setBranchIslandTarget_i386(
140 						   BranchIsland	*island,
141 						   const void		*branchTo,
142 						   char*			instructions ) __attribute__((visibility("hidden")));
143 // Can't be made static because there's no C implementation for atomic_mov64
144 // on i386.
145 void
146 atomic_mov64(
147 		uint64_t *targetAddress,
148 		uint64_t value ) __attribute__((visibility("hidden")));
149 
150 	static Boolean
151 eatKnownInstructions(
152 	unsigned char	*code,
153 	uint64_t		*newInstruction,
154 	int				*howManyEaten,
155 	char			*originalInstructions,
156 	int				*originalInstructionCount,
157 	uint8_t			*originalInstructionSizes ) __attribute__((visibility("hidden")));
158 
159 	static void
160 fixupInstructions(
161     void		*originalFunction,
162     void		*escapeIsland,
163     void		*instructionsToFix,
164 	int			instructionCount,
165 	uint8_t		*instructionSizes ) __attribute__((visibility("hidden")));
166 
167 #ifdef DEBUG_DISASM
168 	static void
169 dump16Bytes(
170 	void	*ptr);
171 #endif  // DEBUG_DISASM
172 #endif
173 
174 /*******************************************************************************
175 *
176 *	Interface
177 *
178 *******************************************************************************/
179 #pragma mark	-
180 #pragma mark	(Interface)
181 
182 #if defined(__i386__) || defined(__x86_64__)
makeIslandExecutable(void * address)183 static mach_error_t makeIslandExecutable(void *address) {
184 	mach_error_t err = err_none;
185     vm_size_t pageSize;
186     host_page_size( mach_host_self(), &pageSize );
187     uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
188     int e = err_none;
189     e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
190     e |= msync((void *)page, pageSize, MS_INVALIDATE );
191     if (e) {
192         err = err_cannot_override;
193     }
194     return err;
195 }
196 #endif
197 
198 		static mach_error_t
defaultIslandMalloc(void ** ptr,size_t unused_size,void * hint)199 defaultIslandMalloc(
200 	void **ptr, size_t unused_size, void *hint) {
201   return allocateBranchIsland( (BranchIsland**)ptr, kAllocateHigh, hint );
202 }
203 		static mach_error_t
defaultIslandFree(void * ptr)204 defaultIslandFree(
205 	void *ptr) {
206 	return freeBranchIsland(ptr);
207 }
208 
209     mach_error_t
__asan_mach_override_ptr(void * originalFunctionAddress,const void * overrideFunctionAddress,void ** originalFunctionReentryIsland)210 __asan_mach_override_ptr(
211 	void *originalFunctionAddress,
212     const void *overrideFunctionAddress,
213     void **originalFunctionReentryIsland )
214 {
215   return __asan_mach_override_ptr_custom(originalFunctionAddress,
216 		overrideFunctionAddress,
217 		originalFunctionReentryIsland,
218 		defaultIslandMalloc,
219 		defaultIslandFree);
220 }
221 
222     mach_error_t
__asan_mach_override_ptr_custom(void * originalFunctionAddress,const void * overrideFunctionAddress,void ** originalFunctionReentryIsland,island_malloc * alloc,island_free * dealloc)223 __asan_mach_override_ptr_custom(
224 	void *originalFunctionAddress,
225     const void *overrideFunctionAddress,
226     void **originalFunctionReentryIsland,
227 		island_malloc *alloc,
228 		island_free *dealloc)
229 {
230 	assert( originalFunctionAddress );
231 	assert( overrideFunctionAddress );
232 
233 	// this addresses overriding such functions as AudioOutputUnitStart()
234 	// test with modified DefaultOutputUnit project
235 #if defined(__x86_64__)
236     for(;;){
237         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp qword near [rip+0x????????]
238             originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
239         else break;
240     }
241 #elif defined(__i386__)
242     for(;;){
243         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp *0x????????
244             originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
245         else break;
246     }
247 #endif
248 #ifdef DEBUG_DISASM
249   {
250     fprintf(stderr, "Replacing function at %p\n", originalFunctionAddress);
251     fprintf(stderr, "First 16 bytes of the function: ");
252     unsigned char *orig = (unsigned char *)originalFunctionAddress;
253     int i;
254     for (i = 0; i < 16; i++) {
255        fprintf(stderr, "%x ", (unsigned int) orig[i]);
256     }
257     fprintf(stderr, "\n");
258     fprintf(stderr,
259             "To disassemble, save the following function as disas.c"
260             " and run:\n  gcc -c disas.c && gobjdump -d disas.o\n"
261             "The first 16 bytes of the original function will start"
262             " after four nop instructions.\n");
263     fprintf(stderr, "\nvoid foo() {\n  asm volatile(\"nop;nop;nop;nop;\");\n");
264     int j = 0;
265     for (j = 0; j < 2; j++) {
266       fprintf(stderr, "  asm volatile(\".byte ");
267       for (i = 8 * j; i < 8 * (j+1) - 1; i++) {
268         fprintf(stderr, "0x%x, ", (unsigned int) orig[i]);
269       }
270       fprintf(stderr, "0x%x;\");\n", (unsigned int) orig[8 * (j+1) - 1]);
271     }
272     fprintf(stderr, "}\n\n");
273   }
274 #endif
275 
276 	long	*originalFunctionPtr = (long*) originalFunctionAddress;
277 	mach_error_t	err = err_none;
278 
279 #if defined(__ppc__) || defined(__POWERPC__)
280 	//	Ensure first instruction isn't 'mfctr'.
281 	#define	kMFCTRMask			0xfc1fffff
282 	#define	kMFCTRInstruction	0x7c0903a6
283 
284 	long	originalInstruction = *originalFunctionPtr;
285 	if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
286 		err = err_cannot_override;
287 #elif defined(__i386__) || defined(__x86_64__)
288 	int eatenCount = 0;
289 	int originalInstructionCount = 0;
290 	char originalInstructions[kOriginalInstructionsSize];
291 	uint8_t originalInstructionSizes[kOriginalInstructionsSize];
292 	uint64_t jumpRelativeInstruction = 0; // JMP
293 
294 	Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
295 										&jumpRelativeInstruction, &eatenCount,
296 										originalInstructions, &originalInstructionCount,
297 										originalInstructionSizes );
298 #ifdef DEBUG_DISASM
299   if (!overridePossible) fprintf(stderr, "overridePossible = false @%d\n", __LINE__);
300 #endif
301 	if (eatenCount > kOriginalInstructionsSize) {
302 #ifdef DEBUG_DISASM
303 		fprintf(stderr, "Too many instructions eaten\n");
304 #endif
305 		overridePossible = false;
306 	}
307 	if (!overridePossible) err = err_cannot_override;
308 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
309 #endif
310 
311 	//	Make the original function implementation writable.
312 	if( !err ) {
313 		err = vm_protect( mach_task_self(),
314 				(vm_address_t) originalFunctionPtr, 8, false,
315 				(VM_PROT_ALL | VM_PROT_COPY) );
316 		if( err )
317 			err = vm_protect( mach_task_self(),
318 					(vm_address_t) originalFunctionPtr, 8, false,
319 					(VM_PROT_DEFAULT | VM_PROT_COPY) );
320 	}
321 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
322 
323 	//	Allocate and target the escape island to the overriding function.
324 	BranchIsland	*escapeIsland = NULL;
325 	if( !err )
326 		err = alloc( (void**)&escapeIsland, sizeof(BranchIsland), originalFunctionAddress );
327 	if ( err ) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
328 
329 #if defined(__ppc__) || defined(__POWERPC__)
330 	if( !err )
331 		err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
332 
333 	//	Build the branch absolute instruction to the escape island.
334 	long	branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
335 	if( !err ) {
336 		long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
337 		branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
338 	}
339 #elif defined(__i386__) || defined(__x86_64__)
340         if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
341 
342 	if( !err )
343 		err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
344 
345 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
346 	// Build the jump relative instruction to the escape island
347 #endif
348 
349 
350 #if defined(__i386__) || defined(__x86_64__)
351 	if (!err) {
352 		uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
353 		addressOffset = OSSwapInt32(addressOffset);
354 
355 		jumpRelativeInstruction |= 0xE900000000000000LL;
356 		jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
357 		jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
358 	}
359 #endif
360 
361 	//	Optionally allocate & return the reentry island. This may contain relocated
362 	//  jmp instructions and so has all the same addressing reachability requirements
363 	//  the escape island has to the original function, except the escape island is
364 	//  technically our original function.
365 	BranchIsland	*reentryIsland = NULL;
366 	if( !err && originalFunctionReentryIsland ) {
367 		err = alloc( (void**)&reentryIsland, sizeof(BranchIsland), escapeIsland);
368 		if( !err )
369 			*originalFunctionReentryIsland = reentryIsland;
370 	}
371 
372 #if defined(__ppc__) || defined(__POWERPC__)
373 	//	Atomically:
374 	//	o If the reentry island was allocated:
375 	//		o Insert the original instruction into the reentry island.
376 	//		o Target the reentry island at the 2nd instruction of the
377 	//		  original function.
378 	//	o Replace the original instruction with the branch absolute.
379 	if( !err ) {
380 		int escapeIslandEngaged = false;
381 		do {
382 			if( reentryIsland )
383 				err = setBranchIslandTarget( reentryIsland,
384 						(void*) (originalFunctionPtr+1), originalInstruction );
385 			if( !err ) {
386 				escapeIslandEngaged = CompareAndSwap( originalInstruction,
387 										branchAbsoluteInstruction,
388 										(UInt32*)originalFunctionPtr );
389 				if( !escapeIslandEngaged ) {
390 					//	Someone replaced the instruction out from under us,
391 					//	re-read the instruction, make sure it's still not
392 					//	'mfctr' and try again.
393 					originalInstruction = *originalFunctionPtr;
394 					if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
395 						err = err_cannot_override;
396 				}
397 			}
398 		} while( !err && !escapeIslandEngaged );
399 	}
400 #elif defined(__i386__) || defined(__x86_64__)
401 	// Atomically:
402 	//	o If the reentry island was allocated:
403 	//		o Insert the original instructions into the reentry island.
404 	//		o Target the reentry island at the first non-replaced
405 	//        instruction of the original function.
406 	//	o Replace the original first instructions with the jump relative.
407 	//
408 	// Note that on i386, we do not support someone else changing the code under our feet
409 	if ( !err ) {
410 		fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
411 					originalInstructionCount, originalInstructionSizes );
412 
413 		if( reentryIsland )
414 			err = setBranchIslandTarget_i386( reentryIsland,
415 										 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
416 		// try making islands executable before planting the jmp
417 #if defined(__x86_64__) || defined(__i386__)
418         if( !err )
419             err = makeIslandExecutable(escapeIsland);
420         if( !err && reentryIsland )
421             err = makeIslandExecutable(reentryIsland);
422 #endif
423 		if ( !err )
424 			atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
425 	}
426 #endif
427 
428 	//	Clean up on error.
429 	if( err ) {
430 		if( reentryIsland )
431 			dealloc( reentryIsland );
432 		if( escapeIsland )
433 			dealloc( escapeIsland );
434 	}
435 
436 #ifdef DEBUG_DISASM
437   {
438     fprintf(stderr, "First 16 bytes of the function after slicing: ");
439     unsigned char *orig = (unsigned char *)originalFunctionAddress;
440     int i;
441     for (i = 0; i < 16; i++) {
442        fprintf(stderr, "%x ", (unsigned int) orig[i]);
443     }
444     fprintf(stderr, "\n");
445   }
446 #endif
447 	return err;
448 }
449 
450 /*******************************************************************************
451 *
452 *	Implementation
453 *
454 *******************************************************************************/
455 #pragma mark	-
456 #pragma mark	(Implementation)
457 
458 /***************************************************************************//**
459 	Implementation: Allocates memory for a branch island.
460 
461 	@param	island			<-	The allocated island.
462 	@param	allocateHigh	->	Whether to allocate the island at the end of the
463 								address space (for use with the branch absolute
464 								instruction).
465 	@result					<-	mach_error_t
466 
467 	***************************************************************************/
468 
469 	static mach_error_t
allocateBranchIsland(BranchIsland ** island,int allocateHigh,void * originalFunctionAddress)470 allocateBranchIsland(
471 		BranchIsland	**island,
472 		int				allocateHigh,
473 		void *originalFunctionAddress)
474 {
475 	assert( island );
476 
477 	mach_error_t	err = err_none;
478 
479 	if( allocateHigh ) {
480 		vm_size_t pageSize;
481 		err = host_page_size( mach_host_self(), &pageSize );
482 		if( !err ) {
483 			assert( sizeof( BranchIsland ) <= pageSize );
484 #if defined(__ppc__) || defined(__POWERPC__)
485 			vm_address_t first = 0xfeffffff;
486 			vm_address_t last = 0xfe000000 + pageSize;
487 #elif defined(__x86_64__)
488 			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?
489 			vm_address_t last = 0x0;
490 #else
491 			vm_address_t first = 0xffc00000;
492 			vm_address_t last = 0xfffe0000;
493 #endif
494 
495 			vm_address_t page = first;
496 			int allocated = 0;
497 			vm_map_t task_self = mach_task_self();
498 
499 			while( !err && !allocated && page != last ) {
500 
501 				err = vm_allocate( task_self, &page, pageSize, 0 );
502 				if( err == err_none )
503 					allocated = 1;
504 				else if( err == KERN_NO_SPACE ) {
505 #if defined(__x86_64__)
506 					page -= pageSize;
507 #else
508 					page += pageSize;
509 #endif
510 					err = err_none;
511 				}
512 			}
513 			if( allocated )
514 				*island = (BranchIsland*) page;
515 			else if( !allocated && !err )
516 				err = KERN_NO_SPACE;
517 		}
518 	} else {
519 		void *block = malloc( sizeof( BranchIsland ) );
520 		if( block )
521 			*island = block;
522 		else
523 			err = KERN_NO_SPACE;
524 	}
525 	if( !err )
526 		(**island).allocatedHigh = allocateHigh;
527 
528 	return err;
529 }
530 
531 /***************************************************************************//**
532 	Implementation: Deallocates memory for a branch island.
533 
534 	@param	island	->	The island to deallocate.
535 	@result			<-	mach_error_t
536 
537 	***************************************************************************/
538 
539 	static mach_error_t
freeBranchIsland(BranchIsland * island)540 freeBranchIsland(
541 		BranchIsland	*island )
542 {
543 	assert( island );
544 	assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
545 	assert( island->allocatedHigh );
546 
547 	mach_error_t	err = err_none;
548 
549 	if( island->allocatedHigh ) {
550 		vm_size_t pageSize;
551 		err = host_page_size( mach_host_self(), &pageSize );
552 		if( !err ) {
553 			assert( sizeof( BranchIsland ) <= pageSize );
554 			err = vm_deallocate(
555 					mach_task_self(),
556 					(vm_address_t) island, pageSize );
557 		}
558 	} else {
559 		free( island );
560 	}
561 
562 	return err;
563 }
564 
565 /***************************************************************************//**
566 	Implementation: Sets the branch island's target, with an optional
567 	instruction.
568 
569 	@param	island		->	The branch island to insert target into.
570 	@param	branchTo	->	The address of the target.
571 	@param	instruction	->	Optional instruction to execute prior to branch. Set
572 							to zero for nop.
573 	@result				<-	mach_error_t
574 
575 	***************************************************************************/
576 #if defined(__ppc__) || defined(__POWERPC__)
577 	static mach_error_t
setBranchIslandTarget(BranchIsland * island,const void * branchTo,long instruction)578 setBranchIslandTarget(
579 		BranchIsland	*island,
580 		const void		*branchTo,
581 		long			instruction )
582 {
583 	//	Copy over the template code.
584     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
585 
586     //	Fill in the address.
587     ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
588     ((short*)island->instructions)[kAddressHi]
589     	= (((long) branchTo) >> 16) & 0x0000FFFF;
590 
591     //	Fill in the (optional) instuction.
592     if( instruction != 0 ) {
593         ((short*)island->instructions)[kInstructionLo]
594         	= instruction & 0x0000FFFF;
595         ((short*)island->instructions)[kInstructionHi]
596         	= (instruction >> 16) & 0x0000FFFF;
597     }
598 
599     //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
600 	msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
601 
602     return err_none;
603 }
604 #endif
605 
606 #if defined(__i386__)
607 	static mach_error_t
setBranchIslandTarget_i386(BranchIsland * island,const void * branchTo,char * instructions)608 setBranchIslandTarget_i386(
609 	BranchIsland	*island,
610 	const void		*branchTo,
611 	char*			instructions )
612 {
613 
614 	//	Copy over the template code.
615     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
616 
617 	// copy original instructions
618 	if (instructions) {
619 		bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
620 	}
621 
622     // Fill in the address.
623     int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
624     *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
625 
626     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
627     return err_none;
628 }
629 
630 #elif defined(__x86_64__)
631 static mach_error_t
setBranchIslandTarget_i386(BranchIsland * island,const void * branchTo,char * instructions)632 setBranchIslandTarget_i386(
633         BranchIsland	*island,
634         const void		*branchTo,
635         char*			instructions )
636 {
637     // Copy over the template code.
638     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
639 
640     // Copy original instructions.
641     if (instructions) {
642         bcopy (instructions, island->instructions, kOriginalInstructionsSize);
643     }
644 
645     //	Fill in the address.
646     *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
647     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
648 
649     return err_none;
650 }
651 #endif
652 
653 
654 #if defined(__i386__) || defined(__x86_64__)
655 // simplistic instruction matching
656 typedef struct {
657 	unsigned int length; // max 15
658 	unsigned char mask[15]; // sequence of bytes in memory order
659 	unsigned char constraint[15]; // sequence of bytes in memory order
660 }	AsmInstructionMatch;
661 
662 #if defined(__i386__)
663 static AsmInstructionMatch possibleInstructions[] = {
664 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },	// jmp 0x????????
665 	{ 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },	// push %esp; mov %esp,%ebp; leave; ret
666 	{ 0x1, {0xFF}, {0x90} },							// nop
667 	{ 0x1, {0xF8}, {0x50} },							// push %reg
668 	{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },				                // mov %esp,%ebp
669 	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x89, 0x1C, 0x24} },				                // mov %ebx,(%esp)
670 	{ 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },	                        // sub 0x??, %esp
671 	{ 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} },	// sub 0x??, %esp with 32bit immediate
672 	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
673 	{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} },  // mov $imm(%ebp), %reg
674 	{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} },  // mov $imm(%eax-%edx), %reg
675 	{ 0x3, {0xFF, 0xCF, 0x00}, {0x8B, 0x4D, 0x00} },  // mov $imm(%rpb), %reg
676 	{ 0x3, {0xFF, 0x4F, 0x00}, {0x8A, 0x4D, 0x00} },  // mov $imm(%ebp), %cl
677 	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} },  			// mov $imm(%esp), %ecx
678 	{ 0x4, {0xFF, 0x00, 0x00, 0x00}, {0x8B, 0x00, 0x00, 0x00} },  			// mov r16,r/m16 or r32,r/m32
679 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB9, 0x00, 0x00, 0x00, 0x00} }, 	// mov $imm, %ecx
680 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, 	// mov $imm, %eax
681 	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },             	// pxor xmm2/128, xmm1
682 	{ 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, 						// fninit
683 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE8, 0x00, 0x00, 0x00, 0x00} },	// call $imm
684 	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x0F, 0xBE, 0x55, 0x00} },                    // movsbl $imm(%ebp), %edx
685 	{ 0x0 }
686 };
687 #elif defined(__x86_64__)
688 // TODO(glider): disassembling the "0x48, 0x89" sequences is trickier than it's done below.
689 // If it stops working, refer to http://ref.x86asm.net/geek.html#modrm_byte_32_64 to do it
690 // more accurately.
691 // Note: 0x48 is in fact the REX.W prefix, but it might be wrong to treat it as a separate
692 // instruction.
693 static AsmInstructionMatch possibleInstructions[] = {
694 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },	// jmp 0x????????
695 	{ 0x1, {0xFF}, {0x90} },							// nop
696 	{ 0x1, {0xF8}, {0x50} },							// push %rX
697 	{ 0x1, {0xFF}, {0x65} },							// GS prefix
698 	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },				// mov %rsp,%rbp
699 	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },	                // sub 0x??, %rsp
700 	{ 0x4, {0xFB, 0xFF, 0x07, 0x00}, {0x48, 0x89, 0x05, 0x00} },	                // move onto rbp
701 	{ 0x3, {0xFB, 0xFF, 0x00}, {0x48, 0x89, 0x00} },	                            // mov %reg, %reg
702 	{ 0x3, {0xFB, 0xFF, 0x00}, {0x49, 0x89, 0x00} },	                            // mov %reg, %reg (REX.WB)
703 	{ 0x2, {0xFF, 0x00}, {0x41, 0x00} },						// push %rXX
704 	{ 0x2, {0xFF, 0x00}, {0x84, 0x00} },						// test %rX8,%rX8
705 	{ 0x2, {0xFF, 0x00}, {0x85, 0x00} },						// test %rX,%rX
706 	{ 0x2, {0xFF, 0x00}, {0x77, 0x00} },						// ja $i8
707 	{ 0x2, {0xFF, 0x00}, {0x74, 0x00} },						// je $i8
708 	{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },	// mov $imm, %reg
709 	{ 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },				// pushq $imm(%rdi)
710 	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
711 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0x25, 0x00, 0x00, 0x00, 0x00} },	// and $imm, %eax
712 	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x80, 0x3F, 0x00} },				// cmpb $imm, (%rdi)
713 
714   { 0x8, {0xFF, 0xFF, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x00},
715          {0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00}, },                     // mov $imm, %{rax,rdx,rsp,rsi}
716   { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xFA, 0x00}, },   // cmp $i8, %rdx
717 	{ 0x4, {0xFF, 0xFF, 0x00, 0x00}, {0x83, 0x7f, 0x00, 0x00}, },			// cmpl $imm, $imm(%rdi)
718 	{ 0xa, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
719                {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },    // mov $imm, %rax
720         { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
721                {0x81, 0xE6, 0x00, 0x00, 0x00, 0x00} },                            // and $imm, %esi
722         { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
723                {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00} },                            // jmpq *(%rip)
724         { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },              // pxor xmm2/128, xmm1
725         { 0x2, {0xFF, 0x00}, {0x89, 0x00} },                               // mov r/m32,r32 or r/m16,r16
726         { 0x3, {0xFF, 0xFF, 0xFF}, {0x49, 0x89, 0xF8} },                   // mov %rdi,%r8
727         { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0F, 0xBE, 0xCE} },       // movsbl %sil,%ecx
728         { 0x3, {0xFF, 0xFF, 0xFF}, {0x0F, 0xBE, 0xCE} },  // movsbl, %dh, %ecx
729         { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },  // pushq $imm(%rdi)
730         { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
731         { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x85, 0xD2} },  // test %rdx,%rdx
732 	{ 0x0 }
733 };
734 #endif
735 
codeMatchesInstruction(unsigned char * code,AsmInstructionMatch * instruction)736 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
737 {
738 	Boolean match = true;
739 
740 	size_t i;
741   assert(instruction);
742 #ifdef DEBUG_DISASM
743 	fprintf(stderr, "Matching: ");
744 #endif
745 	for (i=0; i<instruction->length; i++) {
746 		unsigned char mask = instruction->mask[i];
747 		unsigned char constraint = instruction->constraint[i];
748 		unsigned char codeValue = code[i];
749 #ifdef DEBUG_DISASM
750 		fprintf(stderr, "%x ", (unsigned)codeValue);
751 #endif
752 		match = ((codeValue & mask) == constraint);
753 		if (!match) break;
754 	}
755 #ifdef DEBUG_DISASM
756 	if (match) {
757 		fprintf(stderr, " OK\n");
758 	} else {
759 		fprintf(stderr, " FAIL\n");
760 	}
761 #endif
762 	return match;
763 }
764 
765 #if defined(__i386__) || defined(__x86_64__)
766 	static Boolean
eatKnownInstructions(unsigned char * code,uint64_t * newInstruction,int * howManyEaten,char * originalInstructions,int * originalInstructionCount,uint8_t * originalInstructionSizes)767 eatKnownInstructions(
768 	unsigned char	*code,
769 	uint64_t		*newInstruction,
770 	int				*howManyEaten,
771 	char			*originalInstructions,
772 	int				*originalInstructionCount,
773 	uint8_t			*originalInstructionSizes )
774 {
775 	Boolean allInstructionsKnown = true;
776 	int totalEaten = 0;
777 	unsigned char* ptr = code;
778 	int remainsToEat = 5; // a JMP instruction takes 5 bytes
779 	int instructionIndex = 0;
780 
781 	if (howManyEaten) *howManyEaten = 0;
782 	if (originalInstructionCount) *originalInstructionCount = 0;
783 	while (remainsToEat > 0) {
784 		Boolean curInstructionKnown = false;
785 
786 		// See if instruction matches one  we know
787 		AsmInstructionMatch* curInstr = possibleInstructions;
788 		do {
789 			if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
790 			curInstr++;
791 		} while (curInstr->length > 0);
792 
793 		// if all instruction matches failed, we don't know current instruction then, stop here
794 		if (!curInstructionKnown) {
795 			allInstructionsKnown = false;
796 			fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
797 			break;
798 		}
799 
800 		// At this point, we've matched curInstr
801 		int eaten = curInstr->length;
802 		ptr += eaten;
803 		remainsToEat -= eaten;
804 		totalEaten += eaten;
805 
806 		if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
807 		instructionIndex += 1;
808 		if (originalInstructionCount) *originalInstructionCount = instructionIndex;
809 	}
810 
811 
812 	if (howManyEaten) *howManyEaten = totalEaten;
813 
814 	if (originalInstructions) {
815 		Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
816 
817 		if (enoughSpaceForOriginalInstructions) {
818 			memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
819 			bcopy(code, originalInstructions, totalEaten);
820 		} else {
821 #ifdef DEBUG_DISASM
822 			fprintf(stderr, "Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
823 #endif
824 			return false;
825 		}
826 	}
827 
828 	if (allInstructionsKnown) {
829 		// save last 3 bytes of first 64bits of codre we'll replace
830 		uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
831 		currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
832 		currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
833 
834 		// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
835 		*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
836 		*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
837 	}
838 
839 	return allInstructionsKnown;
840 }
841 
842 	static void
fixupInstructions(void * originalFunction,void * escapeIsland,void * instructionsToFix,int instructionCount,uint8_t * instructionSizes)843 fixupInstructions(
844     void		*originalFunction,
845     void		*escapeIsland,
846     void		*instructionsToFix,
847 	int			instructionCount,
848 	uint8_t		*instructionSizes )
849 {
850 	void *initialOriginalFunction = originalFunction;
851 	int	index, fixed_size, code_size = 0;
852 	for (index = 0;index < instructionCount;index += 1)
853 		code_size += instructionSizes[index];
854 
855 #ifdef DEBUG_DISASM
856 	void *initialInstructionsToFix = instructionsToFix;
857 	fprintf(stderr, "BEFORE FIXING:\n");
858 	dump16Bytes(initialOriginalFunction);
859 	dump16Bytes(initialInstructionsToFix);
860 #endif  // DEBUG_DISASM
861 
862 	for (index = 0;index < instructionCount;index += 1)
863 	{
864                 fixed_size = instructionSizes[index];
865 		if ((*(uint8_t*)instructionsToFix == 0xE9) || // 32-bit jump relative
866 		    (*(uint8_t*)instructionsToFix == 0xE8))   // 32-bit call relative
867 		{
868 			uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
869 			uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
870 			*jumpOffsetPtr += offset;
871 		}
872 		if ((*(uint8_t*)instructionsToFix == 0x74) ||  // Near jump if equal (je), 2 bytes.
873 		    (*(uint8_t*)instructionsToFix == 0x77))    // Near jump if above (ja), 2 bytes.
874 		{
875 			// We replace a near je/ja instruction, "7P JJ", with a 32-bit je/ja, "0F 8P WW XX YY ZZ".
876 			// This is critical, otherwise a near jump will likely fall outside the original function.
877 			uint32_t offset = (uintptr_t)initialOriginalFunction - (uintptr_t)escapeIsland;
878 			uint32_t jumpOffset = *(uint8_t*)((uintptr_t)instructionsToFix + 1);
879 			*(uint8_t*)(instructionsToFix + 1) = *(uint8_t*)instructionsToFix + 0x10;
880 			*(uint8_t*)instructionsToFix = 0x0F;
881 			uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 2 );
882 			*jumpOffsetPtr = offset + jumpOffset;
883 			fixed_size = 6;
884                 }
885 
886 		originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
887 		escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
888 		instructionsToFix = (void*)((uintptr_t)instructionsToFix + fixed_size);
889 
890 		// Expanding short instructions into longer ones may overwrite the next instructions,
891 		// so we must restore them.
892 		code_size -= fixed_size;
893 		if ((code_size > 0) && (fixed_size != instructionSizes[index])) {
894 			bcopy(originalFunction, instructionsToFix, code_size);
895 		}
896 	}
897 #ifdef DEBUG_DISASM
898 	fprintf(stderr, "AFTER_FIXING:\n");
899 	dump16Bytes(initialOriginalFunction);
900 	dump16Bytes(initialInstructionsToFix);
901 #endif  // DEBUG_DISASM
902 }
903 
904 #ifdef DEBUG_DISASM
905 #define HEX_DIGIT(x) ((((x) % 16) < 10) ? ('0' + ((x) % 16)) : ('A' + ((x) % 16 - 10)))
906 
907 	static void
dump16Bytes(void * ptr)908 dump16Bytes(
909 	void 	*ptr) {
910 	int i;
911 	char buf[3];
912 	uint8_t *bytes = (uint8_t*)ptr;
913 	for (i = 0; i < 16; i++) {
914 		buf[0] = HEX_DIGIT(bytes[i] / 16);
915 		buf[1] = HEX_DIGIT(bytes[i] % 16);
916 		buf[2] = ' ';
917 		write(2, buf, 3);
918 	}
919 	write(2, "\n", 1);
920 }
921 #endif  // DEBUG_DISASM
922 #endif
923 
924 #if defined(__i386__)
925 __asm(
926 			".text;"
927 			".align 2, 0x90;"
928 			"_atomic_mov64:;"
929 			"	pushl %ebp;"
930 			"	movl %esp, %ebp;"
931 			"	pushl %esi;"
932 			"	pushl %ebx;"
933 			"	pushl %ecx;"
934 			"	pushl %eax;"
935 			"	pushl %edx;"
936 
937 			// atomic push of value to an address
938 			// we use cmpxchg8b, which compares content of an address with
939 			// edx:eax. If they are equal, it atomically puts 64bit value
940 			// ecx:ebx in address.
941 			// We thus put contents of address in edx:eax to force ecx:ebx
942 			// in address
943 			"	mov		8(%ebp), %esi;"  // esi contains target address
944 			"	mov		12(%ebp), %ebx;"
945 			"	mov		16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
946 			"	mov		(%esi), %eax;"
947 			"	mov		4(%esi), %edx;"  // edx:eax now contains value currently contained in target address
948 			"	lock; cmpxchg8b	(%esi);" // atomic move.
949 
950 			// restore registers
951 			"	popl %edx;"
952 			"	popl %eax;"
953 			"	popl %ecx;"
954 			"	popl %ebx;"
955 			"	popl %esi;"
956 			"	popl %ebp;"
957 			"	ret"
958 );
959 #elif defined(__x86_64__)
atomic_mov64(uint64_t * targetAddress,uint64_t value)960 void atomic_mov64(
961 		uint64_t *targetAddress,
962 		uint64_t value )
963 {
964     *targetAddress = value;
965 }
966 #endif
967 #endif
968 #endif  // __APPLE__
969