| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 1 #define XOPEN_SOURCE 500 | 5 #define XOPEN_SOURCE 500 |
| 2 #include <algorithm> | 6 #include <algorithm> |
| 3 #include <elf.h> | 7 #include <elf.h> |
| 4 #include <errno.h> | 8 #include <errno.h> |
| 5 #include <errno.h> | 9 #include <errno.h> |
| 6 #include <fcntl.h> | 10 #include <fcntl.h> |
| 7 #include <iostream> | 11 #include <iostream> |
| 8 #include <linux/unistd.h> | 12 #include <linux/unistd.h> |
| 9 #include <set> | 13 #include <set> |
| 10 #include <signal.h> | 14 #include <signal.h> |
| 11 #include <stdarg.h> | 15 #include <stdarg.h> |
| 12 #include <stdio.h> | 16 #include <stdio.h> |
| 13 #include <stdlib.h> | 17 #include <stdlib.h> |
| 14 #include <sys/ptrace.h> | 18 #include <sys/ptrace.h> |
| 15 #include <sys/resource.h> | 19 #include <sys/resource.h> |
| 16 #include <sys/stat.h> | 20 #include <sys/stat.h> |
| 17 #include <sys/types.h> | 21 #include <sys/types.h> |
| 18 | 22 |
| 23 #include "allocator.h" |
| 19 #include "debug.h" | 24 #include "debug.h" |
| 20 #include "library.h" | 25 #include "library.h" |
| 21 #include "sandbox_impl.h" | 26 #include "sandbox_impl.h" |
| 22 #include "syscall.h" | 27 #include "syscall.h" |
| 23 #include "syscall_table.h" | 28 #include "syscall_table.h" |
| 24 #include "x86_decode.h" | 29 #include "x86_decode.h" |
| 25 | 30 |
| 26 #if defined(__x86_64__) | 31 #if defined(__x86_64__) |
| 27 typedef Elf64_Phdr Elf_Phdr; | 32 typedef Elf64_Phdr Elf_Phdr; |
| 28 typedef Elf64_Rela Elf_Rel; | 33 typedef Elf64_Rela Elf_Rel; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 char* Library::__kernel_sigreturn; | 82 char* Library::__kernel_sigreturn; |
| 78 char* Library::__kernel_rt_sigreturn; | 83 char* Library::__kernel_rt_sigreturn; |
| 79 | 84 |
| 80 Library::~Library() { | 85 Library::~Library() { |
| 81 if (image_size_) { | 86 if (image_size_) { |
| 82 // We no longer need access to a full mapping of the underlying library | 87 // We no longer need access to a full mapping of the underlying library |
| 83 // file. Move the temporarily extended mapping back to where we originally | 88 // file. Move the temporarily extended mapping back to where we originally |
| 84 // found. Make sure to preserve any changes that we might have made since. | 89 // found. Make sure to preserve any changes that we might have made since. |
| 85 Sandbox::SysCalls sys; | 90 Sandbox::SysCalls sys; |
| 86 sys.mprotect(image_, 4096, PROT_READ | PROT_WRITE); | 91 sys.mprotect(image_, 4096, PROT_READ | PROT_WRITE); |
| 87 memcpy(image_, memory_ranges_.rbegin()->second.start, 4096); | 92 if (memcmp(image_, memory_ranges_.rbegin()->second.start, 4096)) { |
| 93 // Only copy data, if we made any changes in this data. Otherwise there |
| 94 // is no need to create another modified COW mapping. |
| 95 memcpy(image_, memory_ranges_.rbegin()->second.start, 4096); |
| 96 } |
| 88 sys.mprotect(image_, 4096, PROT_READ | PROT_EXEC); | 97 sys.mprotect(image_, 4096, PROT_READ | PROT_EXEC); |
| 89 sys.mremap(image_, image_size_, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, | 98 sys.mremap(image_, image_size_, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, |
| 90 memory_ranges_.rbegin()->second.start); | 99 memory_ranges_.rbegin()->second.start); |
| 91 } | 100 } |
| 92 } | 101 } |
| 93 | 102 |
| 94 char* Library::getBytes(char* dst, const char* src, ssize_t len) { | 103 char* Library::getBytes(char* dst, const char* src, ssize_t len) { |
| 95 // Some kernels don't allow accessing the VDSO from write() | 104 // Some kernels don't allow accessing the VDSO from write() |
| 96 if (isVDSO_ && | 105 if (isVDSO_ && |
| 97 src >= memory_ranges_.begin()->second.start && | 106 src >= memory_ranges_.begin()->second.start && |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 return NULL; | 175 return NULL; |
| 167 } | 176 } |
| 168 char *src = reinterpret_cast<char *>(iter->second.start) + offset; | 177 char *src = reinterpret_cast<char *>(iter->second.start) + offset; |
| 169 memset(buf, 0, len); | 178 memset(buf, 0, len); |
| 170 if (!getBytes(buf, src, len)) { | 179 if (!getBytes(buf, src, len)) { |
| 171 return NULL; | 180 return NULL; |
| 172 } | 181 } |
| 173 return buf; | 182 return buf; |
| 174 } | 183 } |
| 175 | 184 |
| 176 std::string Library::get(Elf_Addr offset) { | 185 Library::string Library::get(Elf_Addr offset) { |
| 177 if (!valid_) { | 186 if (!valid_) { |
| 178 return ""; | 187 return ""; |
| 179 } | 188 } |
| 180 RangeMap::const_iterator iter = memory_ranges_.lower_bound(offset); | 189 RangeMap::const_iterator iter = memory_ranges_.lower_bound(offset); |
| 181 if (iter == memory_ranges_.end()) { | 190 if (iter == memory_ranges_.end()) { |
| 182 return ""; | 191 return ""; |
| 183 } | 192 } |
| 184 offset -= iter->first; | 193 offset -= iter->first; |
| 185 const char *start = reinterpret_cast<char *>(iter->second.start) + offset; | 194 const char *start = reinterpret_cast<char *>(iter->second.start) + offset; |
| 186 const char *stop = reinterpret_cast<char *>(iter->second.stop) + offset; | 195 const char *stop = reinterpret_cast<char *>(iter->second.stop) + offset; |
| 187 char buf[4096] = { 0 }; | 196 char buf[4096] = { 0 }; |
| 188 getBytes(buf, start, stop - start >= (int)sizeof(buf) ? | 197 getBytes(buf, start, stop - start >= (int)sizeof(buf) ? |
| 189 sizeof(buf) - 1 : stop - start); | 198 sizeof(buf) - 1 : stop - start); |
| 190 start = buf; | 199 start = buf; |
| 191 stop = buf; | 200 stop = buf; |
| 192 while (*stop) { | 201 while (*stop) { |
| 193 ++stop; | 202 ++stop; |
| 194 } | 203 } |
| 195 std::string s = stop > start ? std::string(start, stop - start) : ""; | 204 string s = stop > start ? string(start, stop - start) : ""; |
| 196 return s; | 205 return s; |
| 197 } | 206 } |
| 198 | 207 |
| 199 char *Library::getOriginal(Elf_Addr offset, char *buf, size_t len) { | 208 char *Library::getOriginal(Elf_Addr offset, char *buf, size_t len) { |
| 200 if (!valid_) { | 209 if (!valid_) { |
| 201 memset(buf, 0, len); | 210 memset(buf, 0, len); |
| 202 return NULL; | 211 return NULL; |
| 203 } | 212 } |
| 204 Sandbox::SysCalls sys; | 213 Sandbox::SysCalls sys; |
| 205 if (!image_ && !isVDSO_ && !memory_ranges_.empty() && | 214 if (!image_ && !isVDSO_ && !memory_ranges_.empty() && |
| 206 memory_ranges_.rbegin()->first == 0) { | 215 memory_ranges_.rbegin()->first == 0) { |
| 207 // Extend the mapping of the very first page of the underlying library | 216 // Extend the mapping of the very first page of the underlying library |
| 208 // file. This way, we can read the original file contents of the entire | 217 // file. This way, we can read the original file contents of the entire |
| 209 // library. | 218 // library. |
| 210 // We have to be careful, because doing so temporarily removes the first | 219 // We have to be careful, because doing so temporarily removes the first |
| 211 // 4096 bytes of the library from memory. And we don't want to accidentally | 220 // 4096 bytes of the library from memory. And we don't want to accidentally |
| 212 // unmap code that we are executing. So, only use functions that can be | 221 // unmap code that we are executing. So, only use functions that can be |
| 213 // inlined. | 222 // inlined. |
| 214 void* start = memory_ranges_.rbegin()->second.start; | 223 void* start = memory_ranges_.rbegin()->second.start; |
| 215 image_size_ = memory_ranges_.begin()->first + | 224 image_size_ = memory_ranges_.begin()->first + |
| 216 (reinterpret_cast<char *>(memory_ranges_.begin()->second.stop) - | 225 (reinterpret_cast<char *>(memory_ranges_.begin()->second.stop) - |
| 217 reinterpret_cast<char *>(memory_ranges_.begin()->second.start)); | 226 reinterpret_cast<char *>(memory_ranges_.begin()->second.start)); |
| 227 if (image_size_ < 8192) { |
| 228 // It is possible to create a library that is only a single page in |
| 229 // size. In that case, we have to make sure that we artificially map |
| 230 // one extra page past the end of it, as our code relies on mremap() |
| 231 // actually moving the mapping. |
| 232 image_size_ = 8192; |
| 233 } |
| 218 image_ = reinterpret_cast<char *>(sys.mremap(start, 4096, image_size_, | 234 image_ = reinterpret_cast<char *>(sys.mremap(start, 4096, image_size_, |
| 219 MREMAP_MAYMOVE)); | 235 MREMAP_MAYMOVE)); |
| 236 if (image_size_ == 8192 && image_ == start) { |
| 237 // We really mean it, when we say we want the memory to be moved. |
| 238 image_ = reinterpret_cast<char *>(sys.mremap(start, 4096, image_size_, |
| 239 MREMAP_MAYMOVE)); |
| 240 sys.munmap(reinterpret_cast<char *>(start) + 4096, 4096); |
| 241 } |
| 220 if (image_ == MAP_FAILED) { | 242 if (image_ == MAP_FAILED) { |
| 221 image_ = NULL; | 243 image_ = NULL; |
| 222 } else { | 244 } else { |
| 223 sys.MMAP(start, 4096, PROT_READ | PROT_WRITE, | 245 sys.MMAP(start, 4096, PROT_READ | PROT_WRITE, |
| 224 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); | 246 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); |
| 225 for (int i = 4096 / sizeof(long); --i; | 247 for (int i = 4096 / sizeof(long); --i; |
| 226 reinterpret_cast<long *>(start)[i] = | 248 reinterpret_cast<long *>(start)[i] = |
| 227 reinterpret_cast<long *>(image_)[i]); | 249 reinterpret_cast<long *>(image_)[i]); |
| 228 } | 250 } |
| 229 } | 251 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 243 } | 265 } |
| 244 } | 266 } |
| 245 if (buf && offset + len <= image_size_) { | 267 if (buf && offset + len <= image_size_) { |
| 246 return reinterpret_cast<char *>(memcpy(buf, image_ + offset, len)); | 268 return reinterpret_cast<char *>(memcpy(buf, image_ + offset, len)); |
| 247 } | 269 } |
| 248 return NULL; | 270 return NULL; |
| 249 } | 271 } |
| 250 return buf ? get(offset, buf, len) : NULL; | 272 return buf ? get(offset, buf, len) : NULL; |
| 251 } | 273 } |
| 252 | 274 |
| 253 std::string Library::getOriginal(Elf_Addr offset) { | 275 Library::string Library::getOriginal(Elf_Addr offset) { |
| 254 if (!valid_) { | 276 if (!valid_) { |
| 255 return ""; | 277 return ""; |
| 256 } | 278 } |
| 257 // Make sure we actually have a mapping that we can access. If the string | 279 // Make sure we actually have a mapping that we can access. If the string |
| 258 // is located at the end of the image, we might not yet have extended the | 280 // is located at the end of the image, we might not yet have extended the |
| 259 // mapping sufficiently. | 281 // mapping sufficiently. |
| 260 if (!image_ || image_size_ <= offset) { | 282 if (!image_ || image_size_ <= offset) { |
| 261 getOriginal(offset, NULL, 1); | 283 getOriginal(offset, NULL, 1); |
| 262 } | 284 } |
| 263 | 285 |
| 264 if (image_) { | 286 if (image_) { |
| 265 if (offset < image_size_) { | 287 if (offset < image_size_) { |
| 266 char* start = image_ + offset; | 288 char* start = image_ + offset; |
| 267 char* stop = start; | 289 char* stop = start; |
| 268 while (stop < image_ + image_size_ && *stop) { | 290 while (stop < image_ + image_size_ && *stop) { |
| 269 ++stop; | 291 ++stop; |
| 270 if (stop >= image_ + image_size_) { | 292 if (stop >= image_ + image_size_) { |
| 271 getOriginal(stop - image_, NULL, 1); | 293 getOriginal(stop - image_, NULL, 1); |
| 272 } | 294 } |
| 273 } | 295 } |
| 274 return std::string(start, stop - start); | 296 return string(start, stop - start); |
| 275 } | 297 } |
| 276 return ""; | 298 return ""; |
| 277 } | 299 } |
| 278 return get(offset); | 300 return get(offset); |
| 279 } | 301 } |
| 280 | 302 |
| 281 const Elf_Ehdr* Library::getEhdr() { | 303 const Elf_Ehdr* Library::getEhdr() { |
| 282 if (!valid_) { | 304 if (!valid_) { |
| 283 return NULL; | 305 return NULL; |
| 284 } | 306 } |
| 285 return &ehdr_; | 307 return &ehdr_; |
| 286 } | 308 } |
| 287 | 309 |
| 288 const Elf_Shdr* Library::getSection(const std::string& section) { | 310 const Elf_Shdr* Library::getSection(const string& section) { |
| 289 if (!valid_) { | 311 if (!valid_) { |
| 290 return NULL; | 312 return NULL; |
| 291 } | 313 } |
| 292 SectionTable::const_iterator iter = section_table_.find(section); | 314 SectionTable::const_iterator iter = section_table_.find(section); |
| 293 if (iter == section_table_.end()) { | 315 if (iter == section_table_.end()) { |
| 294 return NULL; | 316 return NULL; |
| 295 } | 317 } |
| 296 return &iter->second.second; | 318 return &iter->second.second; |
| 297 } | 319 } |
| 298 | 320 |
| 299 const int Library::getSectionIndex(const std::string& section) { | 321 const int Library::getSectionIndex(const string& section) { |
| 300 if (!valid_) { | 322 if (!valid_) { |
| 301 return -1; | 323 return -1; |
| 302 } | 324 } |
| 303 SectionTable::const_iterator iter = section_table_.find(section); | 325 SectionTable::const_iterator iter = section_table_.find(section); |
| 304 if (iter == section_table_.end()) { | 326 if (iter == section_table_.end()) { |
| 305 return -1; | 327 return -1; |
| 306 } | 328 } |
| 307 return iter->second.first; | 329 return iter->second.first; |
| 308 } | 330 } |
| 309 | 331 |
| 310 void **Library::getRelocation(const std::string& symbol) { | |
| 311 PltTable::const_iterator iter = plt_entries_.find(symbol); | |
| 312 if (iter == plt_entries_.end()) { | |
| 313 return NULL; | |
| 314 } | |
| 315 return reinterpret_cast<void **>(asr_offset_ + iter->second); | |
| 316 } | |
| 317 | |
| 318 void *Library::getSymbol(const std::string& symbol) { | |
| 319 SymbolTable::const_iterator iter = symbols_.find(symbol); | |
| 320 if (iter == symbols_.end() || !iter->second.st_value) { | |
| 321 return NULL; | |
| 322 } | |
| 323 return asr_offset_ + iter->second.st_value; | |
| 324 } | |
| 325 | |
| 326 void Library::makeWritable(bool state) const { | 332 void Library::makeWritable(bool state) const { |
| 327 for (RangeMap::const_iterator iter = memory_ranges_.begin(); | 333 for (RangeMap::const_iterator iter = memory_ranges_.begin(); |
| 328 iter != memory_ranges_.end(); ++iter) { | 334 iter != memory_ranges_.end(); ++iter) { |
| 329 const Range& range = iter->second; | 335 const Range& range = iter->second; |
| 330 long length = reinterpret_cast<char *>(range.stop) - | 336 long length = reinterpret_cast<char *>(range.stop) - |
| 331 reinterpret_cast<char *>(range.start); | 337 reinterpret_cast<char *>(range.start); |
| 332 Sandbox::SysCalls sys; | 338 Sandbox::SysCalls sys; |
| 333 sys.mprotect(range.start, length, | 339 sys.mprotect(range.start, length, |
| 334 range.prot | (state ? PROT_WRITE : 0)); | 340 range.prot | (state ? PROT_WRITE : 0)); |
| 335 } | 341 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 if (*extraSpace) { | 379 if (*extraSpace) { |
| 374 *extraLength -= needed; | 380 *extraLength -= needed; |
| 375 return *extraSpace + *extraLength; | 381 return *extraSpace + *extraLength; |
| 376 } | 382 } |
| 377 Sandbox::die("Insufficient space to intercept system call"); | 383 Sandbox::die("Insufficient space to intercept system call"); |
| 378 } | 384 } |
| 379 | 385 |
| 380 void Library::patchSystemCallsInFunction(const Maps* maps, char *start, | 386 void Library::patchSystemCallsInFunction(const Maps* maps, char *start, |
| 381 char *end, char** extraSpace, | 387 char *end, char** extraSpace, |
| 382 int* extraLength) { | 388 int* extraLength) { |
| 383 std::set<char *> branch_targets; | 389 std::set<char *, std::less<char *>, SystemAllocator<char *> > branch_targets; |
| 384 for (char *ptr = start; ptr < end; ) { | 390 for (char *ptr = start; ptr < end; ) { |
| 385 unsigned short insn = next_inst((const char **)&ptr, __WORDSIZE == 64); | 391 unsigned short insn = next_inst((const char **)&ptr, __WORDSIZE == 64); |
| 386 char *target; | 392 char *target; |
| 387 if ((insn >= 0x70 && insn <= 0x7F) /* Jcc */ || insn == 0xEB /* JMP */) { | 393 if ((insn >= 0x70 && insn <= 0x7F) /* Jcc */ || insn == 0xEB /* JMP */) { |
| 388 target = ptr + (reinterpret_cast<signed char *>(ptr))[-1]; | 394 target = ptr + (reinterpret_cast<signed char *>(ptr))[-1]; |
| 389 } else if (insn == 0xE8 /* CALL */ || insn == 0xE9 /* JMP */ || | 395 } else if (insn == 0xE8 /* CALL */ || insn == 0xE9 /* JMP */ || |
| 390 (insn >= 0x0F80 && insn <= 0x0F8F) /* Jcc */) { | 396 (insn >= 0x0F80 && insn <= 0x0F8F) /* Jcc */) { |
| 391 target = ptr + (reinterpret_cast<int *>(ptr))[-1]; | 397 target = ptr + (reinterpret_cast<int *>(ptr))[-1]; |
| 392 } else { | 398 } else { |
| 393 continue; | 399 continue; |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 code[i].len = next - code[i].addr; | 515 code[i].len = next - code[i].addr; |
| 510 code[i].is_ip_relative = tmp_rm && (*tmp_rm & 0xC7) == 0x5; | 516 code[i].is_ip_relative = tmp_rm && (*tmp_rm & 0xC7) == 0x5; |
| 511 if (!code[i].is_ip_relative && isSafeInsn(code[i].insn)) { | 517 if (!code[i].is_ip_relative && isSafeInsn(code[i].insn)) { |
| 512 endIdx = i; | 518 endIdx = i; |
| 513 length = next - code[startIdx].addr; | 519 length = next - code[startIdx].addr; |
| 514 } else { | 520 } else { |
| 515 break; | 521 break; |
| 516 } | 522 } |
| 517 } | 523 } |
| 518 // We now know, how many instructions neighboring the system call we | 524 // We now know, how many instructions neighboring the system call we |
| 519 // can safely overwrite. We need five bytes to insert a JMP/CALL and a | 525 // can safely overwrite. On x86-32 we need six bytes, and on x86-64 |
| 520 // 32bit address. We then jump to a code fragment that safely forwards | 526 // We need five bytes to insert a JMPQ and a 32bit address. We then |
| 521 // to our system call wrapper. On x86-64, this is complicated by | 527 // jump to a code fragment that safely forwards to our system call |
| 522 // the fact that the API allows up to 128 bytes of red-zones below the | 528 // wrapper. |
| 523 // current stack pointer. So, we cannot write to the stack until we | 529 // On x86-64, this is complicated by the fact that the API allows up |
| 524 // have adjusted the stack pointer. | 530 // to 128 bytes of red-zones below the current stack pointer. So, we |
| 531 // cannot write to the stack until we have adjusted the stack |
| 532 // pointer. |
| 533 // On both x86-32 and x86-64 we take care to leave the stack unchanged |
| 534 // while we are executing the preamble and postamble. This allows us |
| 535 // to treat instructions that reference %esp/%rsp as safe for |
| 536 // relocation. |
| 537 // In particular, this means that on x86-32 we cannot use CALL, but |
| 538 // have to use a PUSH/RET combination to change the instruction pointer. |
| 539 // On x86-64, we can instead use a 32bit JMPQ. |
| 525 // | 540 // |
| 526 // .. .. .. .. ; any leading instructions copied from original code | 541 // .. .. .. .. ; any leading instructions copied from original code |
| 527 // 48 81 EC 80 00 00 00 SUB $0x80, %rsp | 542 // 48 81 EC 80 00 00 00 SUB $0x80, %rsp |
| 528 // 50 PUSH %rax | 543 // 50 PUSH %rax |
| 529 // 48 8D 05 .. .. .. .. LEA ...(%rip), %rax | 544 // 48 8D 05 .. .. .. .. LEA ...(%rip), %rax |
| 530 // 50 PUSH %rax | 545 // 50 PUSH %rax |
| 531 // 48 B8 .. .. .. .. MOV $syscallWrapper, %rax | 546 // 48 B8 .. .. .. .. MOV $syscallWrapper, %rax |
| 532 // .. .. .. .. | 547 // .. .. .. .. |
| 533 // 50 PUSH %rax | 548 // 50 PUSH %rax |
| 534 // 48 8D 05 06 00 00 00 LEA 6(%rip), %rax | 549 // 48 8D 05 06 00 00 00 LEA 6(%rip), %rax |
| 535 // 48 87 44 24 10 XCHG %rax, 16(%rsp) | 550 // 48 87 44 24 10 XCHG %rax, 16(%rsp) |
| 536 // C3 RETQ | 551 // C3 RETQ |
| 537 // 48 81 C4 80 00 00 00 ADD $0x80, %rsp | 552 // 48 81 C4 80 00 00 00 ADD $0x80, %rsp |
| 538 // .. .. .. .. ; any trailing instructions copied from original code | 553 // .. .. .. .. ; any trailing instructions copied from original code |
| 539 // E9 .. .. .. .. JMPQ ... | 554 // E9 .. .. .. .. JMPQ ... |
| 540 // | 555 // |
| 541 // Total: 52 bytes + any bytes that were copied | 556 // Total: 52 bytes + any bytes that were copied |
| 542 // | 557 // |
| 543 // On x86-32, the stack is available and we can do: | 558 // On x86-32, the stack is available and we can do: |
| 544 // | 559 // |
| 545 // TODO(markus): Try to maintain frame pointers on x86-32 | 560 // TODO(markus): Try to maintain frame pointers on x86-32 |
| 546 // | 561 // |
| 547 // .. .. .. .. ; any leading instructions copied from original code | 562 // .. .. .. .. ; any leading instructions copied from original code |
| 548 // 68 .. .. .. .. PUSH return_addr | 563 // 68 .. .. .. .. PUSH return_addr |
| 549 // 68 .. .. .. .. PUSH $syscallWrapper | 564 // 68 .. .. .. .. PUSH $syscallWrapper |
| 550 // C3 RET | 565 // C3 RET |
| 551 // .. .. .. .. ; any trailing instructions copied from original code | 566 // .. .. .. .. ; any trailing instructions copied from original code |
| 567 // 68 .. .. .. .. PUSH return_addr |
| 552 // C3 RET | 568 // C3 RET |
| 553 // | 569 // |
| 554 // Total: 12 bytes + any bytes that were copied | 570 // Total: 17 bytes + any bytes that were copied |
| 555 // | 571 // |
| 556 // For indirect jumps from the VDSO to the VSyscall page, we instead | 572 // For indirect jumps from the VDSO to the VSyscall page, we instead |
| 557 // replace the following code (this is only necessary on x86-64). This | 573 // replace the following code (this is only necessary on x86-64). This |
| 558 // time, we don't have to worry about red zones: | 574 // time, we don't have to worry about red zones: |
| 559 // | 575 // |
| 560 // .. .. .. .. ; any leading instructions copied from original code | 576 // .. .. .. .. ; any leading instructions copied from original code |
| 561 // E8 00 00 00 00 CALL . | 577 // E8 00 00 00 00 CALL . |
| 562 // 48 83 04 24 .. ADDQ $.., (%rsp) | 578 // 48 83 04 24 .. ADDQ $.., (%rsp) |
| 563 // FF .. .. .. .. .. PUSH .. ; from original CALL instruction | 579 // FF .. .. .. .. .. PUSH .. ; from original CALL instruction |
| 564 // 48 81 3C 24 00 00 00 FF CMPQ $0xFFFFFFFFFF000000, 0(%rsp) | 580 // 48 81 3C 24 00 00 00 FF CMPQ $0xFFFFFFFFFF000000, 0(%rsp) |
| 565 // 72 10 JB . + 16 | 581 // 72 10 JB . + 16 |
| 566 // 81 2C 24 .. .. .. .. SUBL ..., 0(%rsp) | 582 // 81 2C 24 .. .. .. .. SUBL ..., 0(%rsp) |
| 567 // C7 44 24 04 00 00 00 00 MOVL $0, 4(%rsp) | 583 // C7 44 24 04 00 00 00 00 MOVL $0, 4(%rsp) |
| 568 // C3 RETQ | 584 // C3 RETQ |
| 569 // 48 87 04 24 XCHG %rax,(%rsp) | 585 // 48 87 04 24 XCHG %rax,(%rsp) |
| 570 // 48 89 44 24 08 MOV %rax,0x8(%rsp) | 586 // 48 89 44 24 08 MOV %rax,0x8(%rsp) |
| 571 // 58 POP %rax | 587 // 58 POP %rax |
| 572 // C3 RETQ | 588 // C3 RETQ |
| 573 // .. .. .. .. ; any trailing instructions copied from original code | 589 // .. .. .. .. ; any trailing instructions copied from original code |
| 574 // E9 .. .. .. .. JMPQ ... | 590 // E9 .. .. .. .. JMPQ ... |
| 575 // | 591 // |
| 576 // Total: 52 bytes + any bytes that were copied | 592 // Total: 52 bytes + any bytes that were copied |
| 577 | 593 |
| 578 if (length < 5) { | 594 if (length < (__WORDSIZE == 32 ? 6 : 5)) { |
| 579 // There are a very small number of instruction sequences that we | 595 // There are a very small number of instruction sequences that we |
| 580 // cannot easily intercept, and that have been observed in real world | 596 // cannot easily intercept, and that have been observed in real world |
| 581 // examples. Handle them here: | 597 // examples. Handle them here: |
| 582 #if defined(__i386__) | 598 #if defined(__i386__) |
| 583 int diff; | 599 int diff; |
| 584 if (!memcmp(code[codeIdx].addr, "\xCD\x80\xEB", 3) && | 600 if (!memcmp(code[codeIdx].addr, "\xCD\x80\xEB", 3) && |
| 585 (diff = *reinterpret_cast<signed char *>( | 601 (diff = *reinterpret_cast<signed char *>( |
| 586 code[codeIdx].addr + 3)) < 0 && diff >= -6) { | 602 code[codeIdx].addr + 3)) < 0 && diff >= -6) { |
| 587 // We have seen... | 603 // We have seen... |
| 588 // for (;;) { | 604 // for (;;) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 branch_targets.end() || *iter >= ptr)) { | 657 branch_targets.end() || *iter >= ptr)) { |
| 642 // We changed startIdx to include the IP relative instruction. | 658 // We changed startIdx to include the IP relative instruction. |
| 643 // When copying this preamble, we make sure to patch up the | 659 // When copying this preamble, we make sure to patch up the |
| 644 // offset. | 660 // offset. |
| 645 } | 661 } |
| 646 #endif | 662 #endif |
| 647 else { | 663 else { |
| 648 Sandbox::die("Cannot intercept system call"); | 664 Sandbox::die("Cannot intercept system call"); |
| 649 } | 665 } |
| 650 } | 666 } |
| 651 int needed = 5 - code[codeIdx].len; | 667 int needed = (__WORDSIZE == 32 ? 6 : 5) - code[codeIdx].len; |
| 652 int first = codeIdx; | 668 int first = codeIdx; |
| 653 while (needed > 0 && first != startIdx) { | 669 while (needed > 0 && first != startIdx) { |
| 654 first = (first + (sizeof(code) / sizeof(struct Code)) - 1) % | 670 first = (first + (sizeof(code) / sizeof(struct Code)) - 1) % |
| 655 (sizeof(code) / sizeof(struct Code)); | 671 (sizeof(code) / sizeof(struct Code)); |
| 656 needed -= code[first].len; | 672 needed -= code[first].len; |
| 657 } | 673 } |
| 658 int second = codeIdx; | 674 int second = codeIdx; |
| 659 while (needed > 0) { | 675 while (needed > 0) { |
| 660 second = (second + 1) % (sizeof(code) / sizeof(struct Code)); | 676 second = (second + 1) % (sizeof(code) / sizeof(struct Code)); |
| 661 needed -= code[second].len; | 677 needed -= code[second].len; |
| 662 } | 678 } |
| 663 int preamble = code[codeIdx].addr - code[first].addr; | 679 int preamble = code[codeIdx].addr - code[first].addr; |
| 664 int postamble = code[second].addr + code[second].len - | 680 int postamble = code[second].addr + code[second].len - |
| 665 code[codeIdx].addr - code[codeIdx].len; | 681 code[codeIdx].addr - code[codeIdx].len; |
| 666 | 682 |
| 667 // The following is all the code that construct the various bits of | 683 // The following is all the code that construct the various bits of |
| 668 // assembly code. | 684 // assembly code. |
| 669 #if defined(__x86_64__) | 685 #if defined(__x86_64__) |
| 670 if (is_indirect_call) { | 686 if (is_indirect_call) { |
| 671 needed = 52 + preamble + code[codeIdx].len + postamble; | 687 needed = 52 + preamble + code[codeIdx].len + postamble; |
| 672 } else { | 688 } else { |
| 673 needed = 52 + preamble + postamble; | 689 needed = 52 + preamble + postamble; |
| 674 } | 690 } |
| 675 #elif defined(__i386__) | 691 #elif defined(__i386__) |
| 676 needed = 12 + preamble + postamble; | 692 needed = 17 + preamble + postamble; |
| 677 #else | 693 #else |
| 678 #error Unsupported target platform | 694 #error Unsupported target platform |
| 679 #endif | 695 #endif |
| 680 | 696 |
| 681 // Allocate scratch space and copy the preamble of code that was moved | 697 // Allocate scratch space and copy the preamble of code that was moved |
| 682 // from the function that we are patching. | 698 // from the function that we are patching. |
| 683 char* dest = getScratchSpace(maps, code[first].addr, needed, | 699 char* dest = getScratchSpace(maps, code[first].addr, needed, |
| 684 extraSpace, extraLength); | 700 extraSpace, extraLength); |
| 685 memcpy(dest, code[first].addr, preamble); | 701 memcpy(dest, code[first].addr, preamble); |
| 686 | 702 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 (code[second].addr + code[second].len) - (dest + post + 5); | 761 (code[second].addr + code[second].len) - (dest + post + 5); |
| 746 if (is_indirect_call) { | 762 if (is_indirect_call) { |
| 747 *reinterpret_cast<int *>(dest + preamble + 13) = vsys_offset_; | 763 *reinterpret_cast<int *>(dest + preamble + 13) = vsys_offset_; |
| 748 } else { | 764 } else { |
| 749 *reinterpret_cast<int *>(dest + preamble + 11) = | 765 *reinterpret_cast<int *>(dest + preamble + 11) = |
| 750 (code[second].addr + code[second].len) - (dest + preamble + 15); | 766 (code[second].addr + code[second].len) - (dest + preamble + 15); |
| 751 *reinterpret_cast<void **>(dest + preamble + 18) = | 767 *reinterpret_cast<void **>(dest + preamble + 18) = |
| 752 reinterpret_cast<void *>(&syscallWrapper); | 768 reinterpret_cast<void *>(&syscallWrapper); |
| 753 } | 769 } |
| 754 #elif defined(__i386__) | 770 #elif defined(__i386__) |
| 755 *(dest + preamble + 11 + postamble) = '\xC3'; | 771 *(dest + preamble + 11 + postamble) = '\x68'; // PUSH |
| 772 *reinterpret_cast<char **>(dest + preamble + 12 + postamble) = |
| 773 code[second].addr + code[second].len; |
| 774 *(dest + preamble + 16 + postamble) = '\xC3'; // RET |
| 756 *reinterpret_cast<char **>(dest + preamble + 1) = | 775 *reinterpret_cast<char **>(dest + preamble + 1) = |
| 757 dest + preamble + 11; | 776 dest + preamble + 11; |
| 758 *reinterpret_cast<void (**)()>(dest + preamble + 6) = syscallWrapper; | 777 *reinterpret_cast<void (**)()>(dest + preamble + 6) = syscallWrapper; |
| 759 #else | 778 #else |
| 760 #error Unsupported target platform | 779 #error Unsupported target platform |
| 761 #endif | 780 #endif |
| 762 | 781 |
| 763 // Pad unused space in the original function with NOPs | 782 // Pad unused space in the original function with NOPs |
| 764 memset(code[first].addr, 0x90 /* NOP */, | 783 memset(code[first].addr, 0x90 /* NOP */, |
| 765 code[second].addr + code[second].len - code[first].addr); | 784 code[second].addr + code[second].len - code[first].addr); |
| 766 | 785 |
| 767 // Replace the system call with an unconditional jump to our new code. | 786 // Replace the system call with an unconditional jump to our new code. |
| 768 #if defined(__x86_64__) | 787 #if defined(__x86_64__) |
| 769 *code[first].addr = '\xE9'; // JMPQ | 788 *code[first].addr = '\xE9'; // JMPQ |
| 789 *reinterpret_cast<int *>(code[first].addr + 1) = |
| 790 dest - (code[first].addr + 5); |
| 770 #elif defined(__i386__) | 791 #elif defined(__i386__) |
| 771 *code[first].addr = '\xE8'; // CALL | 792 code[first].addr[0] = '\x68'; // PUSH |
| 793 *reinterpret_cast<char **>(code[first].addr + 1) = dest; |
| 794 code[first].addr[5] = '\xC3'; // RET |
| 772 #else | 795 #else |
| 773 #error Unsupported target platform | 796 #error Unsupported target platform |
| 774 #endif | 797 #endif |
| 775 *reinterpret_cast<int *>(code[first].addr + 1) = | |
| 776 dest - (code[first].addr + 5); | |
| 777 } | 798 } |
| 778 replaced: | 799 replaced: |
| 779 codeIdx = (codeIdx + 1) % (sizeof(code) / sizeof(struct Code)); | 800 codeIdx = (codeIdx + 1) % (sizeof(code) / sizeof(struct Code)); |
| 780 } | 801 } |
| 781 } | 802 } |
| 782 | 803 |
| 783 void Library::patchVDSO(char** extraSpace, int* extraLength){ | 804 void Library::patchVDSO(char** extraSpace, int* extraLength){ |
| 784 #if defined(__i386__) | 805 #if defined(__i386__) |
| 785 Sandbox::SysCalls sys; | 806 Sandbox::SysCalls sys; |
| 786 if (!__kernel_vsyscall || | 807 if (!__kernel_vsyscall || |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1042 // Verify ELF header | 1063 // Verify ELF header |
| 1043 Elf_Shdr str_shdr; | 1064 Elf_Shdr str_shdr; |
| 1044 if (!getOriginal(0, &ehdr_) || | 1065 if (!getOriginal(0, &ehdr_) || |
| 1045 ehdr_.e_ehsize < sizeof(Elf_Ehdr) || | 1066 ehdr_.e_ehsize < sizeof(Elf_Ehdr) || |
| 1046 ehdr_.e_phentsize < sizeof(Elf_Phdr) || | 1067 ehdr_.e_phentsize < sizeof(Elf_Phdr) || |
| 1047 ehdr_.e_shentsize < sizeof(Elf_Shdr) || | 1068 ehdr_.e_shentsize < sizeof(Elf_Shdr) || |
| 1048 !getOriginal(ehdr_.e_shoff + ehdr_.e_shstrndx * ehdr_.e_shentsize, | 1069 !getOriginal(ehdr_.e_shoff + ehdr_.e_shstrndx * ehdr_.e_shentsize, |
| 1049 &str_shdr)) { | 1070 &str_shdr)) { |
| 1050 // Not all memory mappings are necessarily ELF files. Skip memory | 1071 // Not all memory mappings are necessarily ELF files. Skip memory |
| 1051 // mappings that we cannot identify. | 1072 // mappings that we cannot identify. |
| 1073 error: |
| 1052 valid_ = false; | 1074 valid_ = false; |
| 1053 return false; | 1075 return false; |
| 1054 } | 1076 } |
| 1055 | 1077 |
| 1056 // Find PT_DYNAMIC segment. This is what our PLT entries and symbols will | |
| 1057 // point to. This information is probably incorrect in the child, as it | |
| 1058 // requires access to the original memory mappings. | |
| 1059 for (int i = 0; i < ehdr_.e_phnum; i++) { | |
| 1060 Elf_Phdr phdr; | |
| 1061 if (getOriginal(ehdr_.e_phoff + i*ehdr_.e_phentsize, &phdr) && | |
| 1062 phdr.p_type == PT_DYNAMIC) { | |
| 1063 RangeMap::const_iterator iter = | |
| 1064 memory_ranges_.lower_bound(phdr.p_offset); | |
| 1065 if (iter != memory_ranges_.end()) { | |
| 1066 asr_offset_ = reinterpret_cast<char *>(iter->second.start) - | |
| 1067 (phdr.p_vaddr - (phdr.p_offset - iter->first)); | |
| 1068 } | |
| 1069 break; | |
| 1070 } | |
| 1071 } | |
| 1072 | |
| 1073 // Parse section table and find all sections in this ELF file | 1078 // Parse section table and find all sections in this ELF file |
| 1074 for (int i = 0; i < ehdr_.e_shnum; i++) { | 1079 for (int i = 0; i < ehdr_.e_shnum; i++) { |
| 1075 Elf_Shdr shdr; | 1080 Elf_Shdr shdr; |
| 1076 if (!getOriginal(ehdr_.e_shoff + i*ehdr_.e_shentsize, &shdr)) { | 1081 if (!getOriginal(ehdr_.e_shoff + i*ehdr_.e_shentsize, &shdr)) { |
| 1077 continue; | 1082 continue; |
| 1078 } | 1083 } |
| 1079 section_table_.insert( | 1084 section_table_.insert( |
| 1080 std::make_pair(getOriginal(str_shdr.sh_offset + shdr.sh_name), | 1085 std::make_pair(getOriginal(str_shdr.sh_offset + shdr.sh_name), |
| 1081 std::make_pair(i, shdr))); | 1086 std::make_pair(i, shdr))); |
| 1082 } | 1087 } |
| 1083 | 1088 |
| 1089 // Compute the offset of entries in the .text segment |
| 1090 const Elf_Shdr* text = getSection(".text"); |
| 1091 if (text == NULL) { |
| 1092 // On x86-32, the VDSO is unusual in as much as it does not have a single |
| 1093 // ".text" section. Instead, it has one section per function. Each |
| 1094 // section name starts with ".text". We just need to pick an arbitrary |
| 1095 // one in order to find the asr_offset_ -- which would typically be zero |
| 1096 // for the VDSO. |
| 1097 for (SectionTable::const_iterator iter = section_table_.begin(); |
| 1098 iter != section_table_.end(); ++iter) { |
| 1099 if (!strncmp(iter->first.c_str(), ".text", 5)) { |
| 1100 text = &iter->second.second; |
| 1101 break; |
| 1102 } |
| 1103 } |
| 1104 } |
| 1105 |
| 1106 // Now that we know where the .text segment is located, we can compute the |
| 1107 // asr_offset_. |
| 1108 if (text) { |
| 1109 RangeMap::const_iterator iter = |
| 1110 memory_ranges_.lower_bound(text->sh_offset); |
| 1111 if (iter != memory_ranges_.end()) { |
| 1112 asr_offset_ = reinterpret_cast<char *>(iter->second.start) - |
| 1113 (text->sh_addr - (text->sh_offset - iter->first)); |
| 1114 } else { |
| 1115 goto error; |
| 1116 } |
| 1117 } else { |
| 1118 goto error; |
| 1119 } |
| 1120 |
| 1084 return !isVDSO_ || parseSymbols(); | 1121 return !isVDSO_ || parseSymbols(); |
| 1085 } | 1122 } |
| 1086 | 1123 |
| 1087 bool Library::parseSymbols() { | 1124 bool Library::parseSymbols() { |
| 1088 if (!valid_) { | 1125 if (!valid_) { |
| 1089 return false; | 1126 return false; |
| 1090 } | 1127 } |
| 1091 | 1128 |
| 1092 Elf_Shdr str_shdr; | 1129 Elf_Shdr str_shdr; |
| 1093 getOriginal(ehdr_.e_shoff + ehdr_.e_shstrndx * ehdr_.e_shentsize, &str_shdr); | 1130 getOriginal(ehdr_.e_shoff + ehdr_.e_shstrndx * ehdr_.e_shentsize, &str_shdr); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1121 continue; | 1158 continue; |
| 1122 } | 1159 } |
| 1123 Elf_Sym sym; | 1160 Elf_Sym sym; |
| 1124 if (!getOriginal(symtab->sh_offset + | 1161 if (!getOriginal(symtab->sh_offset + |
| 1125 ELF_R_SYM(rel.r_info)*sizeof(Elf_Sym), &sym) || | 1162 ELF_R_SYM(rel.r_info)*sizeof(Elf_Sym), &sym) || |
| 1126 sym.st_shndx >= ehdr_.e_shnum) { | 1163 sym.st_shndx >= ehdr_.e_shnum) { |
| 1127 Debug::message("Encountered invalid symbol for plt entry\n"); | 1164 Debug::message("Encountered invalid symbol for plt entry\n"); |
| 1128 valid_ = false; | 1165 valid_ = false; |
| 1129 return false; | 1166 return false; |
| 1130 } | 1167 } |
| 1131 std::string name = getOriginal(strtab.sh_offset + sym.st_name); | 1168 string name = getOriginal(strtab.sh_offset + sym.st_name); |
| 1132 if (name.empty()) { | 1169 if (name.empty()) { |
| 1133 continue; | 1170 continue; |
| 1134 } | 1171 } |
| 1135 plt_entries_.insert(std::make_pair(name, rel.r_offset)); | 1172 plt_entries_.insert(std::make_pair(name, rel.r_offset)); |
| 1136 } | 1173 } |
| 1137 } | 1174 } |
| 1138 | 1175 |
| 1139 if (symtab) { | 1176 if (symtab) { |
| 1140 // Parse symbol table and add its entries | 1177 // Parse symbol table and add its entries |
| 1141 for (Elf_Addr addr = 0; addr < symtab->sh_size; addr += sizeof(Elf_Sym)) { | 1178 for (Elf_Addr addr = 0; addr < symtab->sh_size; addr += sizeof(Elf_Sym)) { |
| 1142 Elf_Sym sym; | 1179 Elf_Sym sym; |
| 1143 if (!getOriginal(symtab->sh_offset + addr, &sym) || | 1180 if (!getOriginal(symtab->sh_offset + addr, &sym) || |
| 1144 (sym.st_shndx >= ehdr_.e_shnum && | 1181 (sym.st_shndx >= ehdr_.e_shnum && |
| 1145 sym.st_shndx < SHN_LORESERVE)) { | 1182 sym.st_shndx < SHN_LORESERVE)) { |
| 1146 Debug::message("Encountered invalid symbol\n"); | 1183 Debug::message("Encountered invalid symbol\n"); |
| 1147 valid_ = false; | 1184 valid_ = false; |
| 1148 return false; | 1185 return false; |
| 1149 } | 1186 } |
| 1150 std::string name = getOriginal(strtab.sh_offset + sym.st_name); | 1187 string name = getOriginal(strtab.sh_offset + sym.st_name); |
| 1151 if (name.empty()) { | 1188 if (name.empty()) { |
| 1152 continue; | 1189 continue; |
| 1153 } | 1190 } |
| 1154 symbols_.insert(std::make_pair(name, sym)); | 1191 symbols_.insert(std::make_pair(name, sym)); |
| 1155 } | 1192 } |
| 1156 } | 1193 } |
| 1157 | 1194 |
| 1158 SymbolTable::const_iterator iter = symbols_.find("__kernel_vsyscall"); | 1195 SymbolTable::const_iterator iter = symbols_.find("__kernel_vsyscall"); |
| 1159 if (iter != symbols_.end() && iter->second.st_value) { | 1196 if (iter != symbols_.end() && iter->second.st_value) { |
| 1160 __kernel_vsyscall = asr_offset_ + iter->second.st_value; | 1197 __kernel_vsyscall = asr_offset_ + iter->second.st_value; |
| 1161 } | 1198 } |
| 1162 iter = symbols_.find("__kernel_sigreturn"); | 1199 iter = symbols_.find("__kernel_sigreturn"); |
| 1163 if (iter != symbols_.end() && iter->second.st_value) { | 1200 if (iter != symbols_.end() && iter->second.st_value) { |
| 1164 __kernel_sigreturn = asr_offset_ + iter->second.st_value; | 1201 __kernel_sigreturn = asr_offset_ + iter->second.st_value; |
| 1165 } | 1202 } |
| 1166 iter = symbols_.find("__kernel_rt_sigreturn"); | 1203 iter = symbols_.find("__kernel_rt_sigreturn"); |
| 1167 if (iter != symbols_.end() && iter->second.st_value) { | 1204 if (iter != symbols_.end() && iter->second.st_value) { |
| 1168 __kernel_rt_sigreturn = asr_offset_ + iter->second.st_value; | 1205 __kernel_rt_sigreturn = asr_offset_ + iter->second.st_value; |
| 1169 } | 1206 } |
| 1170 | 1207 |
| 1171 return true; | 1208 return true; |
| 1172 } | 1209 } |
| 1173 | 1210 |
| 1174 } // namespace | 1211 } // namespace |
| OLD | NEW |