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 |