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

Side by Side Diff: sandbox/linux/seccomp/library.cc

Issue 661438: Seccomp sandbox changes (performance and correctness fixes, primarily targetting x86-32) (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/linux/seccomp/library.h ('k') | sandbox/linux/seccomp/maps.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp/library.h ('k') | sandbox/linux/seccomp/maps.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698