Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(795)

Side by Side Diff: library.cc

Issue 8605003: Add logic for patching calls to the x86-64 vsyscall page (Closed) Base URL: https://seccompsandbox.googlecode.com/svn/trunk
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/test_patching.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | tests/test_patching.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698