| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #define XOPEN_SOURCE 500 | 5 #define XOPEN_SOURCE 500 |
| 6 | 6 |
| 7 #include "library.h" | 7 #include "library.h" |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <elf.h> | 10 #include <elf.h> |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 *extraSpace = maps->allocNearAddr(near, *extraLength, | 357 *extraSpace = maps->allocNearAddr(near, *extraLength, |
| 358 PROT_READ|PROT_WRITE|PROT_EXEC); | 358 PROT_READ|PROT_WRITE|PROT_EXEC); |
| 359 } | 359 } |
| 360 if (*extraSpace) { | 360 if (*extraSpace) { |
| 361 *extraLength -= needed; | 361 *extraLength -= needed; |
| 362 return *extraSpace + *extraLength; | 362 return *extraSpace + *extraLength; |
| 363 } | 363 } |
| 364 Sandbox::die("Insufficient space to intercept system call"); | 364 Sandbox::die("Insufficient space to intercept system call"); |
| 365 } | 365 } |
| 366 | 366 |
| 367 #if defined(__x86_64__) |
| 368 static bool isCallToVsyscallPage(char* code) { |
| 369 // Look for these instructions, which are a call to the x86-64 |
| 370 // vsyscall page, which the kernel puts at a fixed address: |
| 371 // |
| 372 // 48 c7 c0 00 XX 60 ff mov $0xffffffffff60XX00,%rax |
| 373 // ff d0 callq *%rax |
| 374 // |
| 375 // This will not catch all calls to the vsyscall page, but it |
| 376 // handles the important cases that glibc contains. The vsyscall |
| 377 // page is deprecated, so it is unlikely that new instruction |
| 378 // sequences for calling it will be introduced. |
| 379 return (code[0] == '\x48' && |
| 380 code[1] == '\xc7' && |
| 381 code[2] == '\xc0' && |
| 382 code[3] == '\x00' && |
| 383 (code[4] == '\x00' || code[4] == '\x04' || code[4] == '\x08') && |
| 384 code[5] == '\x60' && |
| 385 code[6] == '\xff' && |
| 386 code[7] == '\xff' && |
| 387 code[8] == '\xd0'); |
| 388 } |
| 389 |
| 390 static void patchCallToVsyscallPage(char* code) { |
| 391 // We replace the mov+callq with these instructions: |
| 392 // |
| 393 // b8 XX XX XX XX mov $X, %eax // where X is the syscall number |
| 394 // 0f 05 syscall |
| 395 // 90 nop |
| 396 // 90 nop |
| 397 // |
| 398 // The syscall instruction will later be patched by the general case. |
| 399 if (code[4] == '\x00') { |
| 400 // Use __NR_gettimeofday == 96 == 0x60. |
| 401 const char replacement[] = "\xb8\x60\x00\x00\x00\x0f\x05\x90\x90"; |
| 402 memcpy(code, replacement, sizeof(replacement) - 1); |
| 403 } else if (code[4] == '\x04') { |
| 404 // Use __NR_time == 201 == 0xc9. |
| 405 const char replacement[] = "\xb8\xc9\x00\x00\x00\x0f\x05\x90\x90"; |
| 406 memcpy(code, replacement, sizeof(replacement) - 1); |
| 407 } else if (code[4] == '\x08') { |
| 408 // Use __NR_getcpu == 309 == 0x135. |
| 409 const char replacement[] = "\xb8\x35\x01\x00\x00\x0f\x05\x90\x90"; |
| 410 memcpy(code, replacement, sizeof(replacement) - 1); |
| 411 } |
| 412 } |
| 413 #endif |
| 414 |
| 367 void Library::patchSystemCallsInFunction(const Maps* maps, int vsys_offset, | 415 void Library::patchSystemCallsInFunction(const Maps* maps, int vsys_offset, |
| 368 char* start, char* end, | 416 char* start, char* end, |
| 369 char** extraSpace, int* extraLength) { | 417 char** extraSpace, int* extraLength) { |
| 370 typedef std::set<char *, std::less<char *>, SystemAllocator<char *> > | 418 typedef std::set<char *, std::less<char *>, SystemAllocator<char *> > |
| 371 BranchTargets; | 419 BranchTargets; |
| 372 BranchTargets branch_targets; | 420 BranchTargets branch_targets; |
| 373 for (char *ptr = start; ptr < end; ) { | 421 for (char *ptr = start; ptr < end; ) { |
| 374 unsigned short insn = next_inst((const char **)&ptr, __WORDSIZE == 64); | 422 unsigned short insn = next_inst((const char **)&ptr, __WORDSIZE == 64); |
| 375 char *target; | 423 char *target; |
| 376 if ((insn >= 0x70 && insn <= 0x7F) /* Jcc */ || insn == 0xEB /* JMP */) { | 424 if ((insn >= 0x70 && insn <= 0x7F) /* Jcc */ || insn == 0xEB /* JMP */) { |
| 377 target = ptr + (reinterpret_cast<signed char *>(ptr))[-1]; | 425 target = ptr + (reinterpret_cast<signed char *>(ptr))[-1]; |
| 378 } else if (insn == 0xE8 /* CALL */ || insn == 0xE9 /* JMP */ || | 426 } else if (insn == 0xE8 /* CALL */ || insn == 0xE9 /* JMP */ || |
| 379 (insn >= 0x0F80 && insn <= 0x0F8F) /* Jcc */) { | 427 (insn >= 0x0F80 && insn <= 0x0F8F) /* Jcc */) { |
| 380 target = ptr + (reinterpret_cast<int *>(ptr))[-1]; | 428 target = ptr + (reinterpret_cast<int *>(ptr))[-1]; |
| 381 } else { | 429 } else { |
| 382 continue; | 430 continue; |
| 383 } | 431 } |
| 384 branch_targets.insert(target); | 432 branch_targets.insert(target); |
| 385 } | 433 } |
| 386 struct Code { | 434 struct Code { |
| 387 char* addr; | 435 char* addr; |
| 388 int len; | 436 int len; |
| 389 unsigned short insn; | 437 unsigned short insn; |
| 390 bool is_ip_relative; | 438 bool is_ip_relative; |
| 391 } code[5] = { { 0 } }; | 439 } code[5] = { { 0 } }; |
| 392 int codeIdx = 0; | 440 int codeIdx = 0; |
| 393 char* ptr = start; | 441 char* ptr = start; |
| 394 while (ptr < end) { | 442 while (ptr < end) { |
| 443 #if defined(__x86_64__) |
| 444 if (isCallToVsyscallPage(ptr)) { |
| 445 patchCallToVsyscallPage(ptr); |
| 446 } |
| 447 #endif |
| 395 // Keep a ring-buffer of the last few instruction in order to find the | 448 // Keep a ring-buffer of the last few instruction in order to find the |
| 396 // correct place to patch the code. | 449 // correct place to patch the code. |
| 397 char *mod_rm; | 450 char *mod_rm; |
| 398 code[codeIdx].addr = ptr; | 451 code[codeIdx].addr = ptr; |
| 399 code[codeIdx].insn = next_inst((const char **)&ptr, __WORDSIZE == 64, | 452 code[codeIdx].insn = next_inst((const char **)&ptr, __WORDSIZE == 64, |
| 400 0, 0, &mod_rm, 0, 0); | 453 0, 0, &mod_rm, 0, 0); |
| 401 code[codeIdx].len = ptr - code[codeIdx].addr; | 454 code[codeIdx].len = ptr - code[codeIdx].addr; |
| 402 code[codeIdx].is_ip_relative = | 455 code[codeIdx].is_ip_relative = |
| 403 #if defined(__x86_64__) | 456 #if defined(__x86_64__) |
| 404 mod_rm && (*mod_rm & 0xC7) == 0x5; | 457 mod_rm && (*mod_rm & 0xC7) == 0x5; |
| (...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 } | 1077 } |
| 1025 | 1078 |
| 1026 void Library::patchSystemCallsInRange(char* start, char* stop, | 1079 void Library::patchSystemCallsInRange(char* start, char* stop, |
| 1027 char** extraSpace, int* extraLength) { | 1080 char** extraSpace, int* extraLength) { |
| 1028 char* func = start; | 1081 char* func = start; |
| 1029 int nopcount = 0; | 1082 int nopcount = 0; |
| 1030 bool has_syscall = false; | 1083 bool has_syscall = false; |
| 1031 for (char *ptr = start; ptr < stop; ptr++) { | 1084 for (char *ptr = start; ptr < stop; ptr++) { |
| 1032 #if defined(__x86_64__) | 1085 #if defined(__x86_64__) |
| 1033 if ((*ptr == '\x0F' && ptr[1] == '\x05' /* SYSCALL */) || | 1086 if ((*ptr == '\x0F' && ptr[1] == '\x05' /* SYSCALL */) || |
| 1034 (isVDSO_ && *ptr == '\xFF')) { | 1087 (isVDSO_ && *ptr == '\xFF') || |
| 1088 isCallToVsyscallPage(ptr)) { |
| 1035 #elif defined(__i386__) | 1089 #elif defined(__i386__) |
| 1036 if ((*ptr == '\xCD' && ptr[1] == '\x80' /* INT $0x80 */) || | 1090 if ((*ptr == '\xCD' && ptr[1] == '\x80' /* INT $0x80 */) || |
| 1037 (*ptr == '\x65' && ptr[1] == '\xFF' && | 1091 (*ptr == '\x65' && ptr[1] == '\xFF' && |
| 1038 ptr[2] == '\x15' /* CALL %gs:.. */)) { | 1092 ptr[2] == '\x15' /* CALL %gs:.. */)) { |
| 1039 #else | 1093 #else |
| 1040 #error Unsupported target platform | 1094 #error Unsupported target platform |
| 1041 #endif | 1095 #endif |
| 1042 ptr++; | 1096 ptr++; |
| 1043 has_syscall = true; | 1097 has_syscall = true; |
| 1044 nopcount = 0; | 1098 nopcount = 0; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1187 } | 1241 } |
| 1188 iter = symbols_.find("__kernel_rt_sigreturn"); | 1242 iter = symbols_.find("__kernel_rt_sigreturn"); |
| 1189 if (iter != symbols_.end() && iter->second.st_value) { | 1243 if (iter != symbols_.end() && iter->second.st_value) { |
| 1190 __kernel_rt_sigreturn = asr_offset_ + iter->second.st_value; | 1244 __kernel_rt_sigreturn = asr_offset_ + iter->second.st_value; |
| 1191 } | 1245 } |
| 1192 | 1246 |
| 1193 return true; | 1247 return true; |
| 1194 } | 1248 } |
| 1195 | 1249 |
| 1196 } // namespace | 1250 } // namespace |
| OLD | NEW |