diff options
-rw-r--r-- | sandbox/linux/seccomp/debug.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/debug.h | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/library.cc | 440 | ||||
-rw-r--r-- | sandbox/linux/seccomp/library.h | 32 | ||||
-rw-r--r-- | sandbox/linux/seccomp/linux_syscall_support.h | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/maps.cc | 124 | ||||
-rw-r--r-- | sandbox/linux/seccomp/maps.h | 29 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sandbox.cc | 12 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sandbox_impl.h | 19 | ||||
-rw-r--r-- | sandbox/linux/seccomp/syscall.cc | 1 | ||||
-rw-r--r-- | sandbox/linux/seccomp/syscall.h | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/syscall_table.c | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/syscall_table.h | 13 |
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 } |