Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 | |
| 5 #include <assert.h> | |
| 6 #include <elf.h> | |
| 7 #include <stdio.h> | |
| 8 #include <stdlib.h> | |
| 9 #include <string.h> | |
| 10 | |
| 11 #include "x86_decode.h" | |
| 12 | |
| 13 // This tool patches ELF libraries and executables so that they can be | |
| 14 // used with elf_loader.cc. It rewrites system call instructions so | |
| 15 // that they will work inside the sandbox. | |
|
Markus (顧孟勤)
2011/11/17 22:15:19
I suspect, in the long run, you probably want a to
| |
| 16 | |
| 17 | |
| 18 static void CheckBounds(char *data, size_t data_size, | |
| 19 void *ptr, size_t inside_size) { | |
| 20 assert(data <= (char *) ptr); | |
| 21 assert((char *) ptr + inside_size <= data + data_size); | |
| 22 } | |
| 23 | |
| 24 static int FixUpSection(bool is64bit, char *code, size_t code_size) { | |
| 25 int patch_count = 0; | |
| 26 char *pos = code; | |
| 27 char *end = code + code_size; | |
| 28 while (pos < end) { | |
| 29 const char *ip = pos; | |
| 30 playground::next_inst(&ip, is64bit); | |
| 31 if (is64bit | |
| 32 ? (pos[0] == '\x0f' && pos[1] == '\x05') /* syscall */ | |
| 33 : (pos[0] == '\xcd' && pos[1] == '\x80') /* int $0x80 */) { | |
| 34 // Replace the instruction with "int $0". This is the simplest | |
| 35 // thing to do since it does not involve moving any instructions | |
| 36 // around or extending the code segment. However, executing | |
| 37 // system calls via "int $0" is not very fast at run time. | |
| 38 pos[0] = '\xcd'; | |
| 39 pos[1] = '\x00'; | |
| 40 patch_count++; | |
| 41 } | |
| 42 pos = (char *) ip; | |
| 43 } | |
| 44 return patch_count; | |
| 45 } | |
| 46 | |
| 47 struct Elf32 { | |
| 48 typedef Elf32_Ehdr Ehdr; | |
| 49 typedef Elf32_Shdr Shdr; | |
| 50 }; | |
| 51 | |
| 52 struct Elf64 { | |
| 53 typedef Elf64_Ehdr Ehdr; | |
| 54 typedef Elf64_Shdr Shdr; | |
| 55 }; | |
| 56 | |
| 57 template <class Elf> | |
| 58 static void FixUpElf(char *data, size_t data_size) { | |
| 59 typename Elf::Ehdr *header = (typename Elf::Ehdr *) data; | |
| 60 CheckBounds(data, data_size, header, sizeof(*header)); | |
| 61 assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
| 62 | |
| 63 int patch_count = 0; | |
| 64 for (int index = 0; index < header->e_shnum; index++) { | |
| 65 typename Elf::Shdr *section = | |
| 66 (typename Elf::Shdr *) (data + header->e_shoff + | |
| 67 header->e_shentsize * index); | |
| 68 CheckBounds(data, data_size, section, sizeof(*section)); | |
| 69 | |
| 70 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
| 71 CheckBounds(data, data_size, | |
| 72 data + section->sh_offset, section->sh_size); | |
| 73 patch_count += FixUpSection(header->e_machine == EM_X86_64, | |
| 74 data + section->sh_offset, section->sh_size); | |
| 75 } | |
| 76 } | |
| 77 printf("patched %i syscall instructions\n", patch_count); | |
| 78 } | |
| 79 | |
| 80 static void FixUpElfFile(const char *input_file, const char *output_file) { | |
| 81 FILE *fp; | |
| 82 size_t file_size; | |
| 83 char *data; | |
| 84 size_t got; | |
| 85 size_t written; | |
| 86 | |
| 87 // Read whole ELF file and write it back with modifications. | |
| 88 fp = fopen(input_file, "rb"); | |
| 89 if (fp == NULL) { | |
| 90 fprintf(stderr, "Failed to open input file: %s\n", input_file); | |
| 91 exit(1); | |
| 92 } | |
| 93 // Find the file size. | |
| 94 fseek(fp, 0, SEEK_END); | |
| 95 file_size = ftell(fp); | |
| 96 data = (char *) malloc(file_size); | |
| 97 assert(data != NULL); | |
| 98 fseek(fp, 0, SEEK_SET); | |
| 99 got = fread(data, 1, file_size, fp); | |
| 100 assert(got == file_size); | |
| 101 fclose(fp); | |
| 102 | |
| 103 switch (data[EI_CLASS]) { | |
| 104 case ELFCLASS64: | |
| 105 FixUpElf<Elf64>(data, file_size); | |
| 106 break; | |
| 107 case ELFCLASS32: | |
| 108 FixUpElf<Elf32>(data, file_size); | |
| 109 break; | |
| 110 default: | |
| 111 fprintf(stderr, "Unknown ELF class\n"); | |
| 112 exit(1); | |
| 113 } | |
| 114 | |
| 115 fp = fopen(output_file, "wb"); | |
| 116 if (fp == NULL) { | |
| 117 fprintf(stderr, "Failed to open output file: %s\n", output_file); | |
| 118 exit(1); | |
| 119 } | |
| 120 written = fwrite(data, 1, file_size, fp); | |
| 121 assert(written == file_size); | |
| 122 fclose(fp); | |
| 123 free(data); | |
| 124 } | |
| 125 | |
| 126 int main(int argc, char **argv) { | |
| 127 if (argc != 4 || strcmp(argv[2], "-o") != 0) { | |
| 128 fprintf(stderr, "Usage: %s <input-file> -o <output-file>\n\n", argv[0]); | |
| 129 fprintf(stderr, | |
| 130 "This tool rewrites ELF objects to patch system call instructions\n" | |
| 131 "to be redirected via the seccomp-sandbox's handler.\n"); | |
| 132 return 1; | |
| 133 } | |
| 134 FixUpElfFile(argv[1], argv[3]); | |
| 135 return 0; | |
| 136 } | |
| OLD | NEW |