summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
}