summaryrefslogtreecommitdiffstats
path: root/sandbox/linux
diff options
context:
space:
mode:
authormarkus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-21 23:04:11 +0000
committermarkus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-21 23:04:11 +0000
commit6b603d9092891f9b3e2e7b54a7000e3595252f84 (patch)
tree5e5bfc3831a959964e5585ec3a32816a5d64243d /sandbox/linux
parentebc3c8bdb77ce5926e0bb6961851d9e3546f7274 (diff)
downloadchromium_src-6b603d9092891f9b3e2e7b54a7000e3595252f84.zip
chromium_src-6b603d9092891f9b3e2e7b54a7000e3595252f84.tar.gz
chromium_src-6b603d9092891f9b3e2e7b54a7000e3595252f84.tar.bz2
- found all symbols that we directly access from assembly and marked them as internal. This ensures
that the linker won't complain about IP relative addressing for symbols that could be overridden at run-time. - avoided using "g" register constraints, as there has been a report of some versions of GCC erroneously generating code that is no longer position independant when this constraint is used. - removed the old code that fork()'s a child to try to extend mappings of libraries at run-time. This code always was somewhat fragile and caused a measurable performance penalty when the sandbox was started. Replaced with code that remapped just the very first page. This can actually be done in a running process without disrupting the use of the libraries. - added a special case for the instrumentation code allowing it to deal with jumps between the VDSO and VSyscalls even if the instructions would normally not be eligible for interception as they are IP relative. After making this change, we can again find sufficiently large code snippets to rewrite them successfully. This is only a concern on x86_64. - fixed a bug that would erroneously look for IP relative addressing on x86_32. It doesn't exist for that architecture. TEST=none BUG=http://code.google.com/p/chromium/issues/detail?id=18337 Review URL: http://codereview.chromium.org/306036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29726 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/linux')
-rw-r--r--sandbox/linux/seccomp/debug.cc2
-rw-r--r--sandbox/linux/seccomp/debug.h6
-rw-r--r--sandbox/linux/seccomp/library.cc440
-rw-r--r--sandbox/linux/seccomp/library.h32
-rw-r--r--sandbox/linux/seccomp/linux_syscall_support.h6
-rw-r--r--sandbox/linux/seccomp/maps.cc124
-rw-r--r--sandbox/linux/seccomp/maps.h29
-rw-r--r--sandbox/linux/seccomp/sandbox.cc12
-rw-r--r--sandbox/linux/seccomp/sandbox_impl.h19
-rw-r--r--sandbox/linux/seccomp/syscall.cc1
-rw-r--r--sandbox/linux/seccomp/syscall.h6
-rw-r--r--sandbox/linux/seccomp/syscall_table.c6
-rw-r--r--sandbox/linux/seccomp/syscall_table.h13
13 files changed, 210 insertions, 486 deletions
diff --git a/sandbox/linux/seccomp/debug.cc b/sandbox/linux/seccomp/debug.cc
index 467b460..35d3c82 100644
--- a/sandbox/linux/seccomp/debug.cc
+++ b/sandbox/linux/seccomp/debug.cc
@@ -148,7 +148,7 @@ void Debug::syscall(int sysnum, const char* msg, int call) {
}
char unnamed[40] = "Unnamed syscall #";
if (!sysname) {
- itoa(const_cast<char*>(strrchr(sysname = unnamed, '\000')), sysnum);
+ itoa(const_cast<char *>(strrchr(sysname = unnamed, '\000')), sysnum);
}
#if defined(__NR_socketcall) || defined(__NR_ipc)
char extra[40];
diff --git a/sandbox/linux/seccomp/debug.h b/sandbox/linux/seccomp/debug.h
index 728c55c..4b94f8f 100644
--- a/sandbox/linux/seccomp/debug.h
+++ b/sandbox/linux/seccomp/debug.h
@@ -16,7 +16,11 @@ class Debug {
// If debugging is enabled, write a message to stderr.
static void message(const char* msg)
#ifndef NDEBUG
- asm("playground$debugMessage");
+ asm("playground$debugMessage")
+ #if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+ #endif
+ ;
#else
{ }
#endif
diff --git a/sandbox/linux/seccomp/library.cc b/sandbox/linux/seccomp/library.cc
index a6c406e..cf7477b 100644
--- a/sandbox/linux/seccomp/library.cc
+++ b/sandbox/linux/seccomp/library.cc
@@ -77,6 +77,20 @@ char* Library::__kernel_vsyscall;
char* Library::__kernel_sigreturn;
char* Library::__kernel_rt_sigreturn;
+Library::~Library() {
+ if (image_size_) {
+ // We no longer need access to a full mapping of the underlying library
+ // file. Move the temporarily extended mapping back to where we originally
+ // found. Make sure to preserve any changes that we might have made since.
+ Sandbox::SysCalls sys;
+ sys.mprotect(image_, 4096, PROT_READ | PROT_WRITE);
+ memcpy(image_, memory_ranges_.rbegin()->second.start, 4096);
+ sys.mprotect(image_, 4096, PROT_READ | PROT_EXEC);
+ sys.mremap(image_, image_size_, 4096, MREMAP_MAYMOVE | MREMAP_FIXED,
+ memory_ranges_.rbegin()->second.start);
+ }
+}
+
char* Library::getBytes(char* dst, const char* src, ssize_t len) {
// Some kernels don't allow accessing the VDSO from write()
if (isVDSO_ &&
@@ -148,30 +162,9 @@ char *Library::get(Elf_Addr offset, char *buf, size_t len) {
long size = reinterpret_cast<char *>(iter->second.stop) -
reinterpret_cast<char *>(iter->second.start);
if (offset > size - len) {
- if (!maps_ && memory_ranges_.size() == 1 &&
- !memory_ranges_.begin()->first && !isVDSO_) {
- // We are in the child and have exactly one mapping covering the whole
- // library. We are trying to read data past the end of what is currently
- // mapped. Check if we can expand the memory mapping to recover the
- // needed data
- Sandbox::SysCalls sys;
- long new_size = (offset + len + 4095) & ~4095;
- void *new_start = sys.mremap(iter->second.start, size, new_size,
- MREMAP_MAYMOVE);
- if (new_start != MAP_FAILED) {
- memory_ranges_.clear();
- memory_ranges_.insert(std::make_pair(0,
- Range(new_start, reinterpret_cast<void *>(
- reinterpret_cast<char *>(new_start) + new_size),
- PROT_READ)));
- iter = memory_ranges_.begin();
- goto ok;
- }
- }
memset(buf, 0, len);
return NULL;
}
-ok:
char *src = reinterpret_cast<char *>(iter->second.start) + offset;
memset(buf, 0, len);
if (!getBytes(buf, src, len)) {
@@ -189,31 +182,6 @@ std::string Library::get(Elf_Addr offset) {
return "";
}
offset -= iter->first;
- size_t size = reinterpret_cast<char *>(iter->second.stop) -
- reinterpret_cast<char *>(iter->second.start);
- if (offset > size - 4096) {
- if (!maps_ && memory_ranges_.size() == 1 &&
- !memory_ranges_.begin()->first && !isVDSO_) {
- // We are in the child and have exactly one mapping covering the whole
- // library. We are trying to read data past the end of what is currently
- // mapped. Check if we can expand the memory mapping to recover the
- // needed data. We assume that strings are never longer than 4kB.
- Sandbox::SysCalls sys;
- long new_size = (offset + 4096 + 4095) & ~4095;
- void *new_start = sys.mremap(iter->second.start, size, new_size,
- MREMAP_MAYMOVE);
- if (new_start != MAP_FAILED) {
- memory_ranges_.clear();
- memory_ranges_.insert(std::make_pair(0,
- Range(new_start, reinterpret_cast<void *>(
- reinterpret_cast<char *>(new_start) + new_size),
- PROT_READ)));
- iter = memory_ranges_.begin();
- goto ok;
- }
- }
- }
-ok:
const char *start = reinterpret_cast<char *>(iter->second.start) + offset;
const char *stop = reinterpret_cast<char *>(iter->second.stop) + offset;
char buf[4096] = { 0 };
@@ -233,18 +201,79 @@ char *Library::getOriginal(Elf_Addr offset, char *buf, size_t len) {
memset(buf, 0, len);
return NULL;
}
- if (maps_) {
- return maps_->forwardGetRequest(this, offset, buf, len);
+ Sandbox::SysCalls sys;
+ if (!image_ && !isVDSO_ && !memory_ranges_.empty() &&
+ memory_ranges_.rbegin()->first == 0) {
+ // Extend the mapping of the very first page of the underlying library
+ // file. This way, we can read the original file contents of the entire
+ // library.
+ // We have to be careful, because doing so temporarily removes the first
+ // 4096 bytes of the library from memory. And we don't want to accidentally
+ // unmap code that we are executing. So, only use functions that can be
+ // inlined.
+ void* start = memory_ranges_.rbegin()->second.start;
+ image_size_ = memory_ranges_.begin()->first +
+ (reinterpret_cast<char *>(memory_ranges_.begin()->second.stop) -
+ reinterpret_cast<char *>(memory_ranges_.begin()->second.start));
+ image_ = reinterpret_cast<char *>(sys.mremap(start, 4096, image_size_,
+ MREMAP_MAYMOVE));
+ if (image_ == MAP_FAILED) {
+ image_ = NULL;
+ } else {
+ sys.MMAP(start, 4096, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ for (int i = 4096 / sizeof(long); --i;
+ reinterpret_cast<long *>(start)[i] =
+ reinterpret_cast<long *>(image_)[i]);
+ }
+ }
+
+ if (image_) {
+ if (offset + len > image_size_) {
+ // It is quite likely that we initially did not map the entire file as
+ // we did not know how large it is. So, if necessary, try to extend the
+ // mapping.
+ size_t new_size = (offset + len + 4095) & ~4095;
+ char* tmp =
+ reinterpret_cast<char *>(sys.mremap(image_, image_size_, new_size,
+ MREMAP_MAYMOVE));
+ if (tmp != MAP_FAILED) {
+ image_ = tmp;
+ image_size_ = new_size;
+ }
+ }
+ if (buf && offset + len <= image_size_) {
+ return reinterpret_cast<char *>(memcpy(buf, image_ + offset, len));
+ }
+ return NULL;
}
- return get(offset, buf, len);
+ return buf ? get(offset, buf, len) : NULL;
}
std::string Library::getOriginal(Elf_Addr offset) {
if (!valid_) {
return "";
}
- if (maps_) {
- return maps_->forwardGetRequest(this, offset);
+ // Make sure we actually have a mapping that we can access. If the string
+ // is located at the end of the image, we might not yet have extended the
+ // mapping sufficiently.
+ if (!image_ || image_size_ <= offset) {
+ getOriginal(offset, NULL, 1);
+ }
+
+ if (image_) {
+ if (offset < image_size_) {
+ char* start = image_ + offset;
+ char* stop = start;
+ while (stop < image_ + image_size_ && *stop) {
+ ++stop;
+ if (stop >= image_ + image_size_) {
+ getOriginal(stop - image_, NULL, 1);
+ }
+ }
+ return std::string(start, stop - start);
+ }
+ return "";
}
return get(offset);
}
@@ -381,7 +410,12 @@ void Library::patchSystemCallsInFunction(const Maps* maps, char *start,
code[codeIdx].insn = next_inst((const char **)&ptr, __WORDSIZE == 64,
0, 0, &mod_rm, 0, 0);
code[codeIdx].len = ptr - code[codeIdx].addr;
- code[codeIdx].is_ip_relative = mod_rm && (*mod_rm & 0xC7) == 0x5;
+ code[codeIdx].is_ip_relative =
+ #if defined(__x86_64__)
+ mod_rm && (*mod_rm & 0xC7) == 0x5;
+ #else
+ false;
+ #endif
// Whenever we find a system call, we patch it with a jump to out-of-line
// code that redirects to our system call wrapper.
@@ -458,6 +492,7 @@ void Library::patchSystemCallsInFunction(const Maps* maps, char *start,
#endif
char *next = ptr;
for (int i = codeIdx;
+ next < end &&
(i = (i + 1) % (sizeof(code) / sizeof(struct Code))) != startIdx;
) {
std::set<char *>::const_iterator iter =
@@ -567,6 +602,8 @@ void Library::patchSystemCallsInFunction(const Maps* maps, char *start,
*reinterpret_cast<unsigned short *>(code[codeIdx].addr + 2) = 0x9090;
goto findEndIdx;
}
+ #elif defined(__x86_64__)
+ std::set<char *>::const_iterator iter;
#endif
// If we cannot figure out any other way to intercept this system call,
// we replace it with a call to INT0. This causes a SEGV which we then
@@ -578,7 +615,36 @@ void Library::patchSystemCallsInFunction(const Maps* maps, char *start,
memset(code[codeIdx].addr + 2, 0x90, code[codeIdx].len - 2);
}
goto replaced;
- } else {
+ }
+ #if defined(__x86_64__)
+ // On x86-64, we occasionally see code like this in the VDSO:
+ // 48 8B 05 CF FE FF FF MOV -0x131(%rip),%rax
+ // FF 50 20 CALLQ *0x20(%rax)
+ // By default, we would not replace the MOV instruction, as it is
+ // IP relative. But if the following instruction is also IP relative,
+ // we are left with only three bytes which is not enough to insert a
+ // jump.
+ // We recognize this particular situation, and as long as the CALLQ
+ // is not a branch target, we decide to still relocate the entire
+ // sequence. We just have to make sure that we then patch up the
+ // IP relative addressing.
+ else if (is_indirect_call && startIdx == codeIdx &&
+ code[startIdx = (startIdx + (sizeof(code) /
+ sizeof(struct Code)) - 1) %
+ (sizeof(code) / sizeof(struct Code))].addr &&
+ ptr - code[startIdx].addr >= 5 &&
+ code[startIdx].is_ip_relative &&
+ isSafeInsn(code[startIdx].insn) &&
+ ((iter = std::upper_bound(branch_targets.begin(),
+ branch_targets.end(),
+ code[startIdx].addr)) ==
+ branch_targets.end() || *iter >= ptr)) {
+ // We changed startIdx to include the IP relative instruction.
+ // When copying this preamble, we make sure to patch up the
+ // offset.
+ }
+ #endif
+ else {
Sandbox::die("Cannot intercept system call");
}
}
@@ -618,6 +684,14 @@ void Library::patchSystemCallsInFunction(const Maps* maps, char *start,
extraSpace, extraLength);
memcpy(dest, code[first].addr, preamble);
+ // For jumps from the VDSO to the VSyscalls we sometimes allow exactly
+ // one IP relative instruction in the preamble.
+ if (code[first].is_ip_relative) {
+ *reinterpret_cast<int *>(dest + (code[codeIdx].addr -
+ code[first].addr) - 4)
+ -= dest - code[first].addr;
+ }
+
// For indirect calls, we need to copy the actual CALL instruction and
// turn it into a PUSH instruction.
#if defined(__x86_64__)
@@ -1097,264 +1171,4 @@ bool Library::parseSymbols() {
return true;
}
-void Library::recoverOriginalDataParent(Maps* maps) {
- maps_ = maps;
-}
-
-void Library::recoverOriginalDataChild(const std::string& filename) {
- if (isVDSO_) {
- valid_ = true;
- return;
- }
- if (memory_ranges_.empty() || memory_ranges_.rbegin()->first) {
- failed:
- memory_ranges_.clear();
- } else {
- const Range& range = memory_ranges_.rbegin()->second;
- struct Args {
- void* old_addr;
- long old_length;
- void* new_addr;
- long new_length;
- long prot;
- } args = {
- range.start,
- (reinterpret_cast<long>(range.stop) -
- reinterpret_cast<long>(range.start) + 4095) & ~4095,
- 0,
- (memory_ranges_.begin()->first +
- (reinterpret_cast<long>(memory_ranges_.begin()->second.stop) -
- reinterpret_cast<long>(memory_ranges_.begin()->second.start)) +
- 4095) & ~4095,
- range.prot
- };
- // We find the memory mapping that starts at file offset zero and
- // extend it to cover the entire file. This is a little difficult to
- // do, as the mapping needs to be moved to a different address. But
- // we are potentially running code that is inside of this mapping at the
- // time when it gets moved.
- //
- // We have to write the code in assembly. We allocate temporary
- // storage and copy the critical code into this page. We then execute
- // from this page, while we relocate the mapping. Finally, we allocate
- // memory at the original location and copy the original data into it.
- // The program can now resume execution.
- #if defined(__x86_64__)
- asm volatile(
- // new_addr = 4096 + mmap(0, new_length + 4096,
- // PROT_READ|PROT_WRITE|PROT_EXEC,
- // MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- "mov $0, %%r9\n"
- "mov $-1, %%r8\n"
- "mov $0x22, %%r10\n"
- "mov $7, %%rdx\n"
- "mov 0x18(%0), %%rsi\n"
- "add $4096, %%rsi\n"
- "mov $0, %%rdi\n"
- "mov $9, %%rax\n"
- "syscall\n"
- "cmp $-4096, %%rax\n"
- "ja 6f\n"
- "mov %%rax, %%r12\n"
- "add $4096, %%r12\n"
-
- // memcpy(new_addr - 4096, &&asm, asm_length)
- "lea 2f(%%rip), %%rsi\n"
- "lea 6f(%%rip), %%rdi\n"
- "sub %%rsi, %%rdi\n"
- "0:sub $1, %%rdi\n"
- "test %%rdi, %%rdi\n"
- "js 1f\n"
- "movzbl (%%rsi, %%rdi, 1), %%ebx\n"
- "mov %%bl, (%%rax, %%rdi, 1)\n"
- "jmp 0b\n"
- "1:\n"
-
- // ((void (*)())new_addr - 4096)()
- "lea 6f(%%rip), %%rbx\n"
- "push %%rbx\n"
- "jmp *%%rax\n"
-
- // mremap(old_addr, old_length, new_length,
- // MREMAP_MAYMOVE|MREMAP_FIXED, new_addr)
- "2:mov %%r12, %%r8\n"
- "mov $3, %%r10\n"
- "mov 0x18(%0), %%rdx\n"
- "mov 0x8(%0), %%rsi\n"
- "mov 0(%0), %%rdi\n"
- "mov $25, %%rax\n"
- "syscall\n"
- "cmp $-4096, %%rax\n"
- "ja 5f\n"
-
- // mmap(old_addr, old_length, PROT_WRITE,
- // MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)
- "mov $0, %%r9\n"
- "mov $-1, %%r8\n"
- "mov $0x32, %%r10\n"
- "mov $2, %%rdx\n"
- "mov 0x8(%0), %%rsi\n"
- "mov 0(%0), %%rdi\n"
- "mov $9, %%rax\n"
- "syscall\n"
- "cmp $-12, %%eax\n"
- "jz 4f\n"
- "cmp $-4096, %%rax\n"
- "ja 5f\n"
-
- // memcpy(old_addr, new_addr, old_length)
- "mov 0x8(%0), %%rdi\n"
- "3:sub $1, %%rdi\n"
- "test %%rdi, %%rdi\n"
- "js 4f\n"
- "movzbl (%%r12, %%rdi, 1), %%ebx\n"
- "mov %%bl, (%%rax, %%rdi, 1)\n"
- "jmp 3b\n"
- "4:\n"
-
- // mprotect(old_addr, old_length, prot)
- "mov 0x20(%0), %%rdx\n"
- "mov 0x8(%0), %%rsi\n"
- "mov %%rax, %%rdi\n"
- "mov $10, %%rax\n"
- "syscall\n"
-
- // args.new_addr = new_addr
- "mov %%r12, 0x10(%0)\n"
- "5:retq\n"
-
- // munmap(new_addr - 4096, 4096)
- "6:mov $4096, %%rsi\n"
- "mov %%r12, %%rdi\n"
- "sub %%rsi, %%rdi\n"
- "mov $11, %%rax\n"
- "syscall\n"
- :
- : "q"(&args)
- : "rax", "rbx", "rcx", "rdx", "rsi", "rdi",
- "r8", "r9", "r10", "r11", "r12", "memory");
- #elif defined(__i386__)
- asm volatile(
- "push %%ebp\n"
- "push %%ebx\n"
- "push %%edi\n"
-
- // new_addr = 4096 + mmap(0, new_length + 4096,
- // PROT_READ|PROT_WRITE|PROT_EXEC,
- // MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- "mov $0, %%ebp\n"
- "mov $0x22, %%esi\n"
- "mov $7, %%edx\n"
- "mov 12(%%edi), %%ecx\n"
- "add $4096, %%ecx\n"
- "mov $-1, %%edi\n"
- "mov $0, %%ebx\n"
- "mov $192, %%eax\n"
- "int $0x80\n"
- "cmp $-4096, %%eax\n"
- "ja 6f\n"
- "mov %%eax, %%ebp\n"
- "add $4096, %%ebp\n"
-
- // memcpy(new_addr - 4096, &&asm, asm_length)
- "lea 2f, %%ecx\n"
- "lea 6f, %%ebx\n"
- "sub %%ecx, %%ebx\n"
- "0:dec %%ebx\n"
- "test %%ebx, %%ebx\n"
- "js 1f\n"
- "movzbl (%%ecx, %%ebx, 1), %%edx\n"
- "mov %%dl, (%%eax, %%ebx, 1)\n"
- "jmp 0b\n"
- "1:\n"
-
- // ((void (*)())new_addr - 4096)()
- "lea 6f, %%ebx\n"
- "push %%ebx\n"
- "jmp *%%eax\n"
-
- // mremap(old_addr, old_length, new_length,
- // MREMAP_MAYMOVE|MREMAP_FIXED, new_addr)
- "2:push %%ebp\n"
- "mov $3, %%esi\n"
- "mov 8(%%esp), %%edi\n"
- "mov 12(%%edi), %%edx\n"
- "mov 4(%%edi), %%ecx\n"
- "mov 0(%%edi), %%ebx\n"
- "mov %%ebp, %%edi\n"
- "mov $163, %%eax\n"
- "int $0x80\n"
- "cmp $-4096, %%eax\n"
- "ja 5f\n"
-
- // mmap(old_addr, old_length, PROT_WRITE,
- // MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)
- "mov $0, %%ebp\n"
- "mov $0x32, %%esi\n"
- "mov $2, %%edx\n"
- "mov 8(%%esp), %%edi\n"
- "mov 4(%%edi), %%ecx\n"
- "mov 0(%%edi), %%ebx\n"
- "mov $-1, %%edi\n"
- "mov $192, %%eax\n"
- "int $0x80\n"
- "cmp $-12, %%eax\n"
- "jz 4f\n"
- "cmp $-4096, %%eax\n"
- "ja 5f\n"
-
- // memcpy(old_addr, new_addr, old_length)
- "mov 0(%%esp), %%ecx\n"
- "mov 8(%%esp), %%edi\n"
- "mov 4(%%edi), %%ebx\n"
- "3:dec %%ebx\n"
- "test %%ebx, %%ebx\n"
- "js 4f\n"
- "movzbl (%%ecx, %%ebx, 1), %%edx\n"
- "mov %%dl, (%%eax, %%ebx, 1)\n"
- "jmp 3b\n"
- "4:\n"
-
- // mprotect(old_addr, old_length, prot)
- "mov 8(%%esp), %%edi\n"
- "mov 16(%%edi), %%edx\n"
- "mov 4(%%edi), %%ecx\n"
- "mov %%eax, %%ebx\n"
- "mov $125, %%eax\n"
- "int $0x80\n"
-
- // args.new_addr = new_addr
- "mov 8(%%esp), %%edi\n"
- "mov 0(%%esp), %%ebp\n"
- "mov %%ebp, 0x8(%%edi)\n"
-
- "5:pop %%ebx\n"
- "ret\n"
-
- // munmap(new_addr - 4096, 4096)
- "6:mov $4096, %%ecx\n"
- "sub %%ecx, %%ebx\n"
- "mov $91, %%eax\n"
- "int $0x80\n"
- "pop %%edi\n"
- "pop %%ebx\n"
- "pop %%ebp\n"
- :
- : "D"(&args)
- : "eax", "ecx", "edx", "esi", "memory");
- #else
- #error Unsupported target platform
- #endif
- if (!args.new_addr) {
- goto failed;
- }
-
- memory_ranges_.clear();
- memory_ranges_.insert(std::make_pair(0, Range(args.new_addr,
- reinterpret_cast<char *>(args.new_addr) + args.new_length,
- PROT_READ)));
- valid_ = true;
- }
-}
-
} // namespace
diff --git a/sandbox/linux/seccomp/library.h b/sandbox/linux/seccomp/library.h
index 002992b..523652c 100644
--- a/sandbox/linux/seccomp/library.h
+++ b/sandbox/linux/seccomp/library.h
@@ -35,11 +35,21 @@ class Library {
isVDSO_(false),
asr_offset_(0),
vsys_offset_(0),
- maps_(0) {
+ maps_(0),
+ image_(0),
+ image_size_(0) {
}
- void addMemoryRange(void* start, void* stop, Elf_Addr offset, int prot,
- int isVDSO) {
+ ~Library();
+
+ void setLibraryInfo(Maps* maps) {
+ if (!maps_) {
+ maps_ = maps;
+ }
+ }
+
+ void addMemoryRange(void* start, void* stop, Elf_Addr offset,
+ int prot, int isVDSO) {
memory_ranges_.insert(std::make_pair(offset, Range(start, stop, prot)));
isVDSO_ = isVDSO;
}
@@ -61,13 +71,11 @@ class Library {
template<class T>T* getOriginal(Elf_Addr offset, T* t) {
if (!valid_) {
memset(t, 0, sizeof(T));
- return false;
- }
- if (maps_) {
- return reinterpret_cast<T *>(maps_->forwardGetRequest(
- this, offset, reinterpret_cast<char *>(t), sizeof(T)));
+ return NULL;
}
- return get(offset, t);
+ return reinterpret_cast<T *>(getOriginal(offset,
+ reinterpret_cast<char *>(t),
+ sizeof(T)));
}
template<class T>bool set(void *addr, T* value) {
@@ -98,6 +106,7 @@ class Library {
return true;
}
+ bool parseElf();
const Elf_Ehdr* getEhdr();
const Elf_Shdr* getSection(const std::string& section);
const int getSectionIndex(const std::string& section);
@@ -108,10 +117,7 @@ class Library {
bool isVDSO() const { return isVDSO_; }
protected:
- bool parseElf();
bool parseSymbols();
- void recoverOriginalDataParent(Maps* maps);
- void recoverOriginalDataChild(const std::string& child);
private:
class GreaterThan : public std::binary_function<Elf_Addr, Elf_Addr, bool> {
@@ -154,6 +160,8 @@ class Library {
SectionTable section_table_;
SymbolTable symbols_;
PltTable plt_entries_;
+ char* image_;
+ size_t image_size_;
static char* __kernel_vsyscall;
static char* __kernel_sigreturn;
static char* __kernel_rt_sigreturn;
diff --git a/sandbox/linux/seccomp/linux_syscall_support.h b/sandbox/linux/seccomp/linux_syscall_support.h
index b3ab59c..0d2e529 100644
--- a/sandbox/linux/seccomp/linux_syscall_support.h
+++ b/sandbox/linux/seccomp/linux_syscall_support.h
@@ -1722,7 +1722,7 @@ struct kernel_statfs {
__asm__ __volatile__("movq %5,%%r10; syscall" : \
"=a" (__res) : "0" (__NR_##name), \
"D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \
- "g" ((long)(arg4)) : "r10", "r11", "rcx", "memory"); \
+ "r" ((long)(arg4)) : "r10", "r11", "rcx", "memory"); \
LSS_RETURN(type, __res); \
}
#undef _syscall5
@@ -1734,7 +1734,7 @@ struct kernel_statfs {
__asm__ __volatile__("movq %5,%%r10; movq %6,%%r8; syscall" : \
"=a" (__res) : "0" (__NR_##name), \
"D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \
- "g" ((long)(arg4)), "g" ((long)(arg5)) : \
+ "r" ((long)(arg4)), "r" ((long)(arg5)) : \
"r8", "r10", "r11", "rcx", "memory"); \
LSS_RETURN(type, __res); \
}
@@ -1748,7 +1748,7 @@ struct kernel_statfs {
"syscall" : \
"=a" (__res) : "0" (__NR_##name), \
"D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \
- "g" ((long)(arg4)), "g" ((long)(arg5)), "g" ((long)(arg6)) : \
+ "r" ((long)(arg4)), "r" ((long)(arg5)), "r" ((long)(arg6)) : \
"r8", "r9", "r10", "r11", "rcx", "memory"); \
LSS_RETURN(type, __res); \
}
diff --git a/sandbox/linux/seccomp/maps.cc b/sandbox/linux/seccomp/maps.cc
index 68bea96..0bf9c8a 100644
--- a/sandbox/linux/seccomp/maps.cc
+++ b/sandbox/linux/seccomp/maps.cc
@@ -19,9 +19,7 @@ Maps::Maps(const std::string& maps_file) :
maps_file_(maps_file),
begin_iter_(this, true, false),
end_iter_(this, false, true),
- pid_(-1),
vsyscall_(0) {
- memset(fds_, -1, sizeof(fds_));
int fd = open(maps_file.c_str(), O_RDONLY);
Sandbox::SysCalls sys;
if (fd >= 0) {
@@ -79,11 +77,12 @@ Maps::Maps(const std::string& maps_file) :
if ((prot & (PROT_EXEC | PROT_READ)) == 0) {
goto skip_entry;
}
- libs_[id + ' ' + library].addMemoryRange(
- reinterpret_cast<void *>(start),
- reinterpret_cast<void *>(stop),
- Elf_Addr(offset),
- prot, isVDSO);
+ Library* lib = &libs_[id + ' ' + library];
+ lib->setLibraryInfo(this);
+ lib->addMemoryRange(reinterpret_cast<void *>(start),
+ reinterpret_cast<void *>(stop),
+ Elf_Addr(offset),
+ prot, isVDSO);
}
skip_entry:
for (;;) {
@@ -97,118 +96,7 @@ Maps::Maps(const std::string& maps_file) :
}
} while (len || long_line);
NOINTR_SYS(close(fd));
-
- // The runtime loader clobbers some of the data that we want to read,
- // when it relocates objects. As we cannot trust the filename that we
- // obtained from /proc/self/maps, we instead fork() a child process and
- // use mremap() to uncover the obscured data.
- int tmp_fds[4];
- if (pipe(tmp_fds))
- abort();
- if (pipe(tmp_fds + 2))
- abort();
- pid_ = fork();
- if (pid_ >= 0) {
- // Set up read and write file descriptors for exchanging data
- // between parent and child.
- fds_[ !pid_] = tmp_fds[ !pid_];
- fds_[!!pid_] = tmp_fds[2 + !!pid_];
- NOINTR_SYS(close( tmp_fds[ !!pid_]));
- NOINTR_SYS(close( tmp_fds[2 + !pid_]));
-
- for (LibraryMap::iterator iter = libs_.begin(); iter != libs_.end(); ){
- Library* lib = &iter->second;
- if (pid_) {
- lib->recoverOriginalDataParent(this);
- } else {
- lib->recoverOriginalDataChild(strrchr(iter->first.c_str(), ' ') + 1);
- }
- if (pid_ && !lib->parseElf()) {
- libs_.erase(iter++);
- } else {
- ++iter;
- }
- }
-
- // Handle requests sent from the parent to the child
- if (!pid_) {
- Request req;
- for (;;) {
- if (Sandbox::read(sys, fds_[0], &req, sizeof(Request)) !=
- sizeof(Request)) {
- _exit(0);
- }
- switch (req.type) {
- case Request::REQ_GET:
- {
- char *buf = new char[req.length];
- if (!req.library->get(req.offset, buf, req.length)) {
- req.length = -1;
- Sandbox::write(sys, fds_[1], &req.length,sizeof(req.length));
- } else {
- Sandbox::write(sys, fds_[1], &req.length,sizeof(req.length));
- Sandbox::write(sys, fds_[1], buf, req.length);
- }
- delete[] buf;
- }
- break;
- case Request::REQ_GET_STR:
- {
- std::string s = req.library->get(req.offset);
- req.length = s.length();
- Sandbox::write(sys, fds_[1], &req.length, sizeof(req.length));
- Sandbox::write(sys, fds_[1], s.c_str(), req.length);
- }
- break;
- }
- }
- }
- } else {
- for (int i = 0; i < 4; i++) {
- NOINTR_SYS(close(tmp_fds[i]));
- }
- }
- }
-}
-
-Maps::~Maps() {
- Sandbox::SysCalls sys;
- sys.kill(pid_, SIGKILL);
- sys.waitpid(pid_, NULL, 0);
-}
-
-char *Maps::forwardGetRequest(Library *library, Elf_Addr offset,
- char *buf, size_t length) const {
- Request req(Request::REQ_GET, library, offset, length);
- Sandbox::SysCalls sys;
- if (Sandbox::write(sys, fds_[1], &req, sizeof(Request)) != sizeof(Request) ||
- Sandbox::read(sys, fds_[0], &req.length, sizeof(req.length)) !=
- sizeof(req.length) ||
- req.length == -1 ||
- Sandbox::read(sys, fds_[0], buf, length) != (ssize_t)length) {
- memset(buf, 0, length);
- return NULL;
- }
- return buf;
-}
-
-std::string Maps::forwardGetRequest(Library *library,
- Elf_Addr offset) const {
- Request req(Request::REQ_GET_STR, library, offset, -1);
- Sandbox::SysCalls sys;
- if (Sandbox::write(sys, fds_[1], &req, sizeof(Request)) != sizeof(Request) ||
- Sandbox::read(sys, fds_[0], &req.length, sizeof(req.length)) !=
- sizeof(req.length)) {
- return "";
- }
- char *buf = new char[req.length];
- if (Sandbox::read(sys, fds_[0], buf, req.length) != (ssize_t)req.length) {
- delete[] buf;
- return "";
}
- std::string s(buf, req.length);
- delete[] buf;
- return s;
}
Maps::Iterator::Iterator(Maps* maps, bool at_beginning, bool at_end)
diff --git a/sandbox/linux/seccomp/maps.h b/sandbox/linux/seccomp/maps.h
index 6b86555..9ecd140 100644
--- a/sandbox/linux/seccomp/maps.h
+++ b/sandbox/linux/seccomp/maps.h
@@ -20,13 +20,9 @@ class Maps {
friend class Library;
public:
Maps(const std::string& maps_file);
- ~Maps();
+ ~Maps() { }
protected:
- char *forwardGetRequest(Library *library, Elf_Addr offset, char *buf,
- size_t length) const;
- std::string forwardGetRequest(Library *library, Elf_Addr offset) const;
-
// A map with all the libraries currently loaded into the application.
// The key is a unique combination of device number, inode number, and
// file name. It should be treated as opaque.
@@ -72,32 +68,13 @@ class Maps {
char* vsyscall() const { return vsyscall_; }
- private:
- struct Request {
- enum Type { REQ_GET, REQ_GET_STR };
-
- Request() { }
-
- Request(enum Type t, Library* i, Elf_Addr o, ssize_t l) :
- library(i), offset(o), length(l), type(t), padding(0) {
- }
-
- Library* library;
- Elf_Addr offset;
- ssize_t length;
- enum Type type;
- int padding; // for valgrind
- };
-
protected:
const std::string maps_file_;
const Iterator begin_iter_;
const Iterator end_iter_;
- LibraryMap libs_;
- pid_t pid_;
- int fds_[2];
- char* vsyscall_;
+ LibraryMap libs_;
+ char* vsyscall_;
};
} // namespace
diff --git a/sandbox/linux/seccomp/sandbox.cc b/sandbox/linux/seccomp/sandbox.cc
index ddbed3b..810f295 100644
--- a/sandbox/linux/seccomp/sandbox.cc
+++ b/sandbox/linux/seccomp/sandbox.cc
@@ -384,7 +384,7 @@ void Sandbox::startSandbox() {
// other libraries.
for (Maps::const_iterator iter = maps.begin(); iter != maps.end(); ++iter){
Library* library = *iter;
- if (library->isVDSO()) {
+ if (library->isVDSO() && library->parseElf()) {
library->makeWritable(true);
library->patchSystemCalls();
library->makeWritable(false);
@@ -400,10 +400,12 @@ void Sandbox::startSandbox() {
if (name) {
char ch = name[strlen(*ptr)];
if (ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z') {
- library->makeWritable(true);
- library->patchSystemCalls();
- library->makeWritable(false);
- break;
+ if (library->parseElf()) {
+ library->makeWritable(true);
+ library->patchSystemCalls();
+ library->makeWritable(false);
+ break;
+ }
}
}
}
diff --git a/sandbox/linux/seccomp/sandbox_impl.h b/sandbox/linux/seccomp/sandbox_impl.h
index e58f59c..634f301 100644
--- a/sandbox/linux/seccomp/sandbox_impl.h
+++ b/sandbox/linux/seccomp/sandbox_impl.h
@@ -64,7 +64,11 @@ class Sandbox {
// calls playground$sandbox__clone().
static int sandbox_clone(int flags, void* stack, int* pid, int* ctid,
void* tls, void* wrapper_sp)
- asm("playground$sandbox__clone");
+ asm("playground$sandbox__clone")
+ #if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+#endif
+ ;
#else
#define STATIC
#define bool int
@@ -263,7 +267,12 @@ class Sandbox {
// Sends a file handle to another process.
static bool sendFd(int transport, int fd0, int fd1, const void* buf,
- size_t len) asm("playground$sendFd");
+ size_t len)
+ asm("playground$sendFd")
+ #if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+ #endif
+ ;
// If getFd() fails, it will set the first valid fd slot (e.g. fd0) to
// -errno.
@@ -559,7 +568,11 @@ class Sandbox {
static void* defaultSystemCallHandler(int syscallNum, void* arg0,
void* arg1, void* arg2, void* arg3,
void* arg4, void* arg5)
- asm("playground$defaultSystemCallHandler");
+ asm("playground$defaultSystemCallHandler")
+ #if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+ #endif
+ ;
// Return a secure memory structure that can be used by a newly created
// thread.
diff --git a/sandbox/linux/seccomp/syscall.cc b/sandbox/linux/seccomp/syscall.cc
index 8b14b30..e1e2547 100644
--- a/sandbox/linux/seccomp/syscall.cc
+++ b/sandbox/linux/seccomp/syscall.cc
@@ -38,6 +38,7 @@ asm(
// This is the wrapper which is called by the untrusted code, trying to
// make a system call.
"playground$syscallWrapper:"
+ ".internal playground$syscallWrapper\n"
".globl playground$syscallWrapper\n"
".type playground$syscallWrapper, @function\n"
#if defined(__x86_64__)
diff --git a/sandbox/linux/seccomp/syscall.h b/sandbox/linux/seccomp/syscall.h
index e4390c2..4859ca2 100644
--- a/sandbox/linux/seccomp/syscall.h
+++ b/sandbox/linux/seccomp/syscall.h
@@ -5,7 +5,11 @@
extern "C" {
#endif
-void syscallWrapper() asm("playground$syscallWrapper");
+void syscallWrapper() asm("playground$syscallWrapper")
+#if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+#endif
+;
#ifdef __cplusplus
}
diff --git a/sandbox/linux/seccomp/syscall_table.c b/sandbox/linux/seccomp/syscall_table.c
index 79b281e..588a1b5 100644
--- a/sandbox/linux/seccomp/syscall_table.c
+++ b/sandbox/linux/seccomp/syscall_table.c
@@ -115,4 +115,8 @@ const unsigned maxSyscall __attribute__((section(".rodata"))) =
sizeof(syscallTable)/sizeof(struct SyscallTable);
const int syscall_mutex_[4096/sizeof(int)] asm("playground$syscall_mutex")
- __attribute__((section(".rodata"),aligned(4096))) = { 0x80000000 };
+ __attribute__((section(".rodata"),aligned(4096)
+#if defined(__x86_64__)
+ ,visibility("internal")
+#endif
+ )) = { 0x80000000 };
diff --git a/sandbox/linux/seccomp/syscall_table.h b/sandbox/linux/seccomp/syscall_table.h
index d678c0b..49c2880 100644
--- a/sandbox/linux/seccomp/syscall_table.h
+++ b/sandbox/linux/seccomp/syscall_table.h
@@ -20,8 +20,17 @@ namespace playground {
int threadFd, SecureMemArgs* mem);
};
extern const struct SyscallTable syscallTable[]
- asm("playground$syscallTable");
- extern const unsigned maxSyscall asm("playground$maxSyscall");
+ asm("playground$syscallTable")
+#if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+#endif
+ ;
+ extern const unsigned maxSyscall
+ asm("playground$maxSyscall")
+#if defined(__x86_64__)
+ __attribute__((visibility("internal")))
+#endif
+ ;
#ifdef __cplusplus
} // namespace
}