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

Side by Side Diff: src/untrusted/irt/tls_edit.c

Issue 140653005: Adds tls_edit utility which patches irt_core.nexe's TLS usage. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: This patch compiles in the tls offsets again instead of relying on tls_edit Created 6 years, 10 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
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2014 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 /*
8 * This alters instructions for the IRT so that access to the TLS
9 * point to the IRT's TLS.
10 */
11
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <sys/stat.h>
18
19 #include "native_client/src/include/elf32.h"
20 #include "native_client/src/include/elf64.h"
21 #include "native_client/src/include/arm_sandbox.h"
22 #include "native_client/src/include/portability.h"
23 #include "native_client/src/trusted/validator_ragel/validator.h"
24
25 #ifndef O_BINARY
26 # define O_BINARY 0
27 #endif
28
29 static void *g_contents;
30 static size_t g_contents_size;
31 static uint8_t *g_code_start;
32 static uint32_t g_code_addr;
33 static int g_errors;
34 static int g_changes;
35
36 static uint32_t GetInsnAddr(const void *insn) {
37 return (uint32_t) ((uint8_t *) insn - g_code_start) + g_code_addr;
38 }
39
40 static void ReportError(const void *insn, const char *message) {
41 uint32_t insn_addr = GetInsnAddr(insn);
42
43 fprintf(stderr, "%#x: %s\n", (unsigned int) insn_addr, message);
44 ++g_errors;
45 }
46
47 static void EditArmCode(void *code, size_t code_length) {
48 Elf32_Word *const words = code;
49 Elf32_Word *const end = (void *) ((uint8_t *) code + code_length);
50 Elf32_Word *insn;
51
52 for (insn = words; insn < end; ++insn) {
53 if (*insn == NACL_INSTR_ARM_LITERAL_POOL_HEAD) {
54 if ((insn - words) % 4 != 0) {
55 ReportError(insn, "Roadblock not at start of bundle");
56 } else {
57 /*
58 * Ignore the rest of this bundle.
59 */
60 insn += 3;
61 }
62 } else if ((*insn & 0x0FFF0FFF) == 0x05990000) {
63 /*
64 * This is 'ldr REG, [r9, #0]'.
65 * Turn it into 'ldr REG, [r9, #4]'.
66 */
67 *insn |= 4;
68 ++g_changes;
69 }
70 }
71 }
72
73 static Bool ConsiderOneInsn(const uint8_t *insn_begin, const uint8_t *insn_end,
74 uint32_t validation_info, void *data) {
75 const uint32_t *insn_offset = ((const uint32_t *) insn_end) - 1;
Roland McGrath 2014/01/31 21:02:01 You should not assume that the build machine is al
76 UNREFERENCED_PARAMETER(data);
77 if (insn_begin[0] == 0x65) { /* GS prefix */
78 if (insn_end - insn_begin < 6) {
79 ReportError(insn_begin, "Unexpected GS prefix");
80 } else if (*insn_offset == 4) {
81 /*
82 * Instruction already offset to the right location
Roland McGrath 2014/01/31 21:02:01 Punctuate the sentence. Line up the *s below the
83 */
84 uint32_t insn_addr = GetInsnAddr(insn_begin);
85 printf("%#x: %%gs address already pointing to correct offset (4)\n",
86 insn_addr);
87 } else if (*insn_offset != 0) {
88 ReportError(insn_begin, "Unexpected %gs address");
89 } else {
90 /*
91 * This is 'something %gs:0'.
92 * Turn it into 'something %gs:4'.
93 */
94 *((uint32_t *) insn_offset) = 4;
95 ++g_changes;
96 }
97 }
98 return (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) == 0;
99 }
100
101 static void EditX86_32Code(void *code, size_t code_length) {
102 const NaClCPUFeaturesX86* cpu_features = &kFullCPUIDFeatures;
Roland McGrath 2014/01/31 21:02:01 Space before * not after. This is not C++.
103 if (!ValidateChunkIA32(code, code_length,
104 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION,
105 cpu_features, &ConsiderOneInsn, NULL))
106 ReportError(code, "Validation failed");
107 }
108
109 static void ReadInput(const char *filename) {
110 struct stat st;
111 FILE *fp = fopen(filename, "rb");
112 if (fp == NULL) {
113 fprintf(stderr, "fopen: %s: %s\n",
114 filename, strerror(errno));
115 exit(1);
116 }
117
118 if (fstat(fileno(fp), &st) < 0) {
119 fprintf(stderr, "fstat: %s: %s\n",
120 filename, strerror(errno));
121 exit(1);
122 }
123
124 g_contents_size = st.st_size;
125 g_contents = malloc(g_contents_size);
126 if (g_contents == NULL) {
127 fprintf(stderr, "Cannot allocate %u bytes: %s\n",
128 (unsigned int) st.st_size, strerror(errno));
129 exit(1);
130 }
131
132 {
133 size_t read_bytes = fread(g_contents, 1, g_contents_size, fp);
134 if (read_bytes != g_contents_size) {
135 int error_num = ferror(fp);
Roland McGrath 2014/01/31 21:02:01 This is a bad name for this variable, and there is
136 int eof_error = feof(fp);
137 if (error_num) {
138 fprintf(stderr, "fread: %s: %s\n",
139 filename, strerror(errno));
140 } else if (eof_error) {
141 fprintf(stderr, "fread: %s: premature EOF\n",
142 filename);
143 } else {
144 fprintf(stderr, "fread: %s: unknown error\n",
Roland McGrath 2014/01/31 21:02:01 Make it say something like "short read count" and
145 filename);
146 }
147 exit(1);
148 }
149 }
150
151 fclose(fp);
152 }
153
154 static void WriteOutput(const char *filename) {
155 FILE *fp = fopen(filename, "wb+");
156 if (fp == NULL) {
157 fprintf(stderr, "fopen: %s: %s\n", filename, strerror(errno));
158 exit(1);
159 }
160
161 {
162 size_t nwrote = fwrite(g_contents, 1, g_contents_size, fp);
163 if (nwrote != g_contents_size) {
164 fprintf(stderr, "fwrite: %s: %s\n", filename, strerror(errno));
165 exit(1);
166 }
167 }
168
169 fclose(fp);
170 }
171
172 static Bool EditTLSCode(const char *infile, uint32_t code_addr,
173 uint8_t* code_start, size_t code_length,
Roland McGrath 2014/01/31 21:02:01 Space before * not after. This is not C++.
174 uint16_t e_machine) {
175 g_code_addr = code_addr;
176 g_code_start = code_start;
177
178 switch (e_machine) {
179 case EM_ARM:
180 EditArmCode(g_code_start, code_length);
181 break;
182 case EM_386:
183 EditX86_32Code(g_code_start, code_length);
184 break;
185 case EM_X86_64:
186 printf("%s: x86-64 ELF detected, no instructions changed\n",
187 infile);
188 return TRUE;
189 default:
190 fprintf(stderr, "%s: Unsupported e_machine %d\n",
191 infile, e_machine);
192 return FALSE;
193 }
194
195 /*
196 * TODO: Until we dep roll native_client changes, no instructions
Roland McGrath 2014/01/31 21:02:01 Convention is to write TODO(username). Line up th
197 * should be changed. No changes to make should return FALSE eventually.
198 */
199 if (g_changes == 0) {
200 fprintf(stderr, "%s: Found no changes to make\n",
201 infile);
202 return TRUE;
203 } else {
204 printf("%s: %d instructions changed\n",
205 infile, g_changes);
206 }
207
208 return TRUE;
209 }
210
211 static Bool Process32BitFile(const char *infile) {
212 const Elf32_Ehdr *ehdr;
213 const Elf32_Phdr *phdr;
214 int i;
215
216 ehdr = g_contents;
217 if (ehdr->e_phoff > g_contents_size) {
218 fprintf(stderr, "%s: bogus e_phoff\n",
219 infile);
220 return FALSE;
221 }
222 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
223 fprintf(stderr, "%s: not an ELFCLASS32 file\n",
224 infile);
225 return FALSE;
226 }
227 if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
228 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
229 infile, ehdr->e_phentsize);
230 return FALSE;
231 }
232 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf32_Phdr)) {
233 fprintf(stderr, "%s: bogus elf32 e_phnum\n",
234 infile);
235 return FALSE;
236 }
237
238 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
239 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
240 infile);
241 return FALSE;
242 }
243
244 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
245 for (i = 0; i < ehdr->e_phnum; ++i) {
246 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
247 break;
248 }
249 if (i == ehdr->e_phnum) {
250 fprintf(stderr, "%s: Could not find executable load segment!\n",
251 infile);
252 return FALSE;
253 }
254
255 if (phdr[i].p_offset > g_contents_size ||
256 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
257 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
258 infile, i);
259 return FALSE;
260 }
261
262 return EditTLSCode(infile, phdr[i].p_vaddr,
263 (uint8_t *) g_contents + phdr[i].p_offset,
264 phdr[i].p_filesz, ehdr->e_machine);
265 }
266
267 static Bool Process64BitFile(const char *infile) {
268 const Elf64_Ehdr *ehdr;
269 const Elf64_Phdr *phdr;
270 int i;
271
272 ehdr = g_contents;
273 if (ehdr->e_phoff > g_contents_size) {
274 fprintf(stderr, "%s: bogus e_phoff\n",
275 infile);
276 return FALSE;
277 }
278 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
279 fprintf(stderr, "%s: not an ELFCLASS64 file\n",
280 infile);
281 return FALSE;
282 }
283 if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
284 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
285 infile, ehdr->e_phentsize);
286 return FALSE;
287 }
288 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf64_Phdr)) {
289 fprintf(stderr, "%s: bogus elf64 e_phnum\n",
290 infile);
291 return FALSE;
292 }
293
294 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
295 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
296 infile);
297 return FALSE;
298 }
299
300 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
301 for (i = 0; i < ehdr->e_phnum; ++i) {
302 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
303 break;
304 }
305 if (i == ehdr->e_phnum) {
306 fprintf(stderr, "%s: Could not find executable load segment!\n",
307 infile);
308 return FALSE;
309 }
310
311 if (phdr[i].p_offset > g_contents_size ||
312 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
313 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
314 infile, i);
315 return FALSE;
316 }
317
318 return EditTLSCode(infile, (uint32_t) phdr[i].p_vaddr,
319 (uint8_t *) g_contents + phdr[i].p_offset,
320 (size_t) phdr[i].p_filesz, ehdr->e_machine);
321 }
322
323 int main(int argc, char **argv) {
324 const char *infile;
325 const char *outfile;
326
327 if (argc != 3) {
328 fprintf(stderr, "Usage: %s INFILE OUTFILE\n", argv[0]);
329 return 1;
330 }
331
332 infile = argv[1];
333 outfile = argv[2];
334
335 ReadInput(infile);
336
337 if (g_contents_size < SELFMAG) {
338 fprintf(stderr, "%s: too short to be an ELF file\n",
339 infile);
340 return 1;
341 }
342 if (memcmp(g_contents, ELFMAG, SELFMAG) != 0) {
343 fprintf(stderr, "%s: not an ELF file\n",
344 infile);
345 return 1;
346 }
347
348 /*
349 * We will examine the header to figure out whether or not we are dealing
Roland McGrath 2014/01/31 21:02:01 s/or not//
350 * with a 32 bit or 64 bit executable file.
351 */
352 if (g_contents_size >= sizeof(Elf32_Ehdr) &&
353 ((Elf32_Ehdr*)g_contents)->e_ident[EI_CLASS] == ELFCLASS32) {
Roland McGrath 2014/01/31 21:02:01 ((Elf32_Ehdr *) g_contents)
354 if (!Process32BitFile(infile)) {
355 fprintf(stderr, "%s: Could not process 32 bit ELF file\n",
356 infile);
357 return 1;
358 }
359 } else if (g_contents_size >= sizeof(Elf64_Ehdr) &&
360 ((Elf64_Ehdr*)g_contents)->e_ident[EI_CLASS] == ELFCLASS64) {
361 if (!Process64BitFile(infile)) {
362 fprintf(stderr, "%s: Could not process 64 bit ELF file\n",
363 infile);
364 return 1;
365 }
366 } else {
367 fprintf(stderr, "%s: Invalid ELF file!\n",
368 infile);
369 return 1;
370 }
371
372 if (g_errors != 0)
Roland McGrath 2014/01/31 21:02:01 Brace on end of 'if' line.
373 {
Roland McGrath 2014/01/31 21:02:01 Brace on end of 'if' line.
374 fprintf(stderr, "blahblah");
Roland McGrath 2014/01/31 21:02:01 Make it a useful message, and add a TODO comment a
375 return 1;
376 }
377 WriteOutput(outfile);
378 return 0;
379 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698