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

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: Fixed spacing issues in build/common.gypi 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
Roland McGrath 2014/02/03 21:25:14 This is unused since you switched to stdio. Drop
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 UNREFERENCED_PARAMETER(data);
76 if (insn_begin[0] == 0x65) { /* GS prefix */
77 if (insn_end - insn_begin < 6) {
78 ReportError(insn_begin, "Unexpected GS prefix");
79 } else if (insn_end[-1] == 0 && insn_end[-2] == 0 &&
80 insn_end[-3] == 0 && insn_end[-4] == 0) {
81 /*
82 * This is 'something %gs:0'.
83 * Turn it into 'something %gs:4'.
84 */
85 ((uint8_t *) insn_end)[-4] = 4;
86 ++g_changes;
87 } else if (insn_end[-1] == 0 && insn_end[-2] == 0 &&
88 insn_end[-3] == 0 && insn_end[-4] == 4) {
89 /*
90 * The Instruction is already offset to the right location.
91 * TODO: This case should be removed eventually once the IRT
92 * is being properly compiled without any special TLS flags.
93 */
94 uint32_t insn_addr = GetInsnAddr(insn_begin);
95 printf("%#x: %%gs address already pointing to correct offset (4)\n",
96 insn_addr);
97 } else {
98 ReportError(insn_begin, "Unexpected %gs address");
99 }
100 }
101 return (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) == 0;
102 }
103
104 static void EditX86_32Code(void *code, size_t code_length) {
105 const NaClCPUFeaturesX86 *cpu_features = &kFullCPUIDFeatures;
106 if (!ValidateChunkIA32(code, code_length,
107 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION,
108 cpu_features, &ConsiderOneInsn, NULL))
109 ReportError(code, "Validation failed");
110 }
111
112 static void ReadInput(const char *filename) {
113 struct stat st;
114 FILE *fp = fopen(filename, "rb");
115 if (fp == NULL) {
116 fprintf(stderr, "fopen: %s: %s\n",
117 filename, strerror(errno));
118 exit(1);
119 }
120
121 if (fstat(fileno(fp), &st) < 0) {
122 fprintf(stderr, "fstat: %s: %s\n",
123 filename, strerror(errno));
124 exit(1);
125 }
126
127 g_contents_size = st.st_size;
128 g_contents = malloc(g_contents_size);
129 if (g_contents == NULL) {
130 fprintf(stderr, "Cannot allocate %u bytes: %s\n",
131 (unsigned int) st.st_size, strerror(errno));
132 exit(1);
133 }
134
135 {
136 size_t read_bytes = fread(g_contents, 1, g_contents_size, fp);
137 if (read_bytes != g_contents_size) {
138 if (ferror(fp)) {
139 fprintf(stderr, "fread: %s: %s\n",
140 filename, strerror(errno));
141 } else if (feof(fp)) {
142 fprintf(stderr, "fread: %s: premature EOF\n",
143 filename);
144 } else {
145 fprintf(stderr, "fread: %s: unexpected read count - %u != %u\n",
146 filename, (unsigned int) read_bytes,
147 (unsigned int) g_contents_size);
148 }
149 exit(1);
150 }
151 }
152
153 fclose(fp);
154 }
155
156 static void WriteOutput(const char *filename) {
157 FILE *fp = fopen(filename, "wb+");
158 if (fp == NULL) {
159 fprintf(stderr, "fopen: %s: %s\n", filename, strerror(errno));
160 exit(1);
161 }
162
163 {
164 size_t nwrote = fwrite(g_contents, 1, g_contents_size, fp);
165 if (nwrote != g_contents_size) {
166 fprintf(stderr, "fwrite: %s: %s\n", filename, strerror(errno));
167 exit(1);
168 }
169 }
170
171 fclose(fp);
172 }
173
174 static Bool EditTLSCode(const char *infile, uint32_t code_addr,
175 uint8_t *code_start, size_t code_length,
176 uint16_t e_machine) {
177 g_code_addr = code_addr;
178 g_code_start = code_start;
179
180 switch (e_machine) {
181 case EM_ARM:
182 EditArmCode(g_code_start, code_length);
183 break;
184 case EM_386:
185 EditX86_32Code(g_code_start, code_length);
186 break;
187 case EM_X86_64:
188 printf("%s: x86-64 ELF detected, no instructions changed\n",
189 infile);
190 return TRUE;
191 default:
Mark Seaborn 2014/02/03 22:31:47 Can you make tls_edit a no-op on MIPS so that this
192 fprintf(stderr, "%s: Unsupported e_machine %d\n",
193 infile, e_machine);
194 return FALSE;
195 }
196
197 /*
198 * TODO: Until we dep roll native_client changes, no instructions
Mark Seaborn 2014/02/03 22:31:47 Nit: TODOs should have a name, i.e. "TODO(dyen):".
199 * should be changed. No changes to make should return FALSE eventually.
Mark Seaborn 2014/02/03 22:31:47 FWIW, that's not necessarily true if you happen to
200 */
201 if (g_changes == 0) {
202 fprintf(stderr, "%s: Found no changes to make\n",
203 infile);
204 return TRUE;
205 } else {
206 printf("%s: %d instructions changed\n",
207 infile, g_changes);
208 }
209
210 return TRUE;
211 }
212
213 static Bool Process32BitFile(const char *infile) {
214 const Elf32_Ehdr *ehdr;
215 const Elf32_Phdr *phdr;
216 int i;
217
218 ehdr = g_contents;
219 if (ehdr->e_phoff > g_contents_size) {
220 fprintf(stderr, "%s: bogus e_phoff\n",
221 infile);
222 return FALSE;
223 }
224 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
225 fprintf(stderr, "%s: not an ELFCLASS32 file\n",
226 infile);
227 return FALSE;
228 }
229 if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
230 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
231 infile, ehdr->e_phentsize);
232 return FALSE;
233 }
234 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf32_Phdr)) {
235 fprintf(stderr, "%s: bogus elf32 e_phnum\n",
236 infile);
237 return FALSE;
238 }
239
240 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
241 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
242 infile);
243 return FALSE;
244 }
245
246 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
247 for (i = 0; i < ehdr->e_phnum; ++i) {
248 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
249 break;
250 }
251 if (i == ehdr->e_phnum) {
252 fprintf(stderr, "%s: Could not find executable load segment!\n",
253 infile);
254 return FALSE;
255 }
256
257 if (phdr[i].p_offset > g_contents_size ||
258 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
259 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
260 infile, i);
261 return FALSE;
262 }
263
264 return EditTLSCode(infile, phdr[i].p_vaddr,
265 (uint8_t *) g_contents + phdr[i].p_offset,
266 phdr[i].p_filesz, ehdr->e_machine);
267 }
268
269 static Bool Process64BitFile(const char *infile) {
270 const Elf64_Ehdr *ehdr;
271 const Elf64_Phdr *phdr;
272 int i;
273
274 ehdr = g_contents;
275 if (ehdr->e_phoff > g_contents_size) {
276 fprintf(stderr, "%s: bogus e_phoff\n",
277 infile);
278 return FALSE;
279 }
280 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
281 fprintf(stderr, "%s: not an ELFCLASS64 file\n",
282 infile);
283 return FALSE;
284 }
285 if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
286 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
287 infile, ehdr->e_phentsize);
288 return FALSE;
289 }
290 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf64_Phdr)) {
291 fprintf(stderr, "%s: bogus elf64 e_phnum\n",
292 infile);
293 return FALSE;
294 }
295
296 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
297 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
298 infile);
299 return FALSE;
300 }
301
302 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
303 for (i = 0; i < ehdr->e_phnum; ++i) {
304 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
305 break;
306 }
307 if (i == ehdr->e_phnum) {
308 fprintf(stderr, "%s: Could not find executable load segment!\n",
309 infile);
310 return FALSE;
311 }
312
313 if (phdr[i].p_offset > g_contents_size ||
314 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
315 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
316 infile, i);
317 return FALSE;
318 }
319
320 return EditTLSCode(infile, (uint32_t) phdr[i].p_vaddr,
321 (uint8_t *) g_contents + phdr[i].p_offset,
322 (size_t) phdr[i].p_filesz, ehdr->e_machine);
323 }
324
325 int main(int argc, char **argv) {
326 const char *infile;
327 const char *outfile;
328
329 if (argc != 3) {
330 fprintf(stderr, "Usage: %s INFILE OUTFILE\n", argv[0]);
331 return 1;
332 }
333
334 infile = argv[1];
335 outfile = argv[2];
336
337 ReadInput(infile);
338
339 if (g_contents_size < SELFMAG) {
340 fprintf(stderr, "%s: too short to be an ELF file\n",
341 infile);
342 return 1;
343 }
344 if (memcmp(g_contents, ELFMAG, SELFMAG) != 0) {
345 fprintf(stderr, "%s: not an ELF file\n",
346 infile);
347 return 1;
348 }
349
350 /*
351 * We will examine the header to figure out whether we are dealing
352 * with a 32 bit or 64 bit executable file.
353 */
354 if (g_contents_size >= sizeof(Elf32_Ehdr) &&
355 ((Elf32_Ehdr*) g_contents)->e_ident[EI_CLASS] == ELFCLASS32) {
356 if (!Process32BitFile(infile)) {
357 fprintf(stderr, "%s: Could not process 32 bit ELF file\n",
358 infile);
359 return 1;
360 }
361 } else if (g_contents_size >= sizeof(Elf64_Ehdr) &&
362 ((Elf64_Ehdr*) g_contents)->e_ident[EI_CLASS] == ELFCLASS64) {
363 if (!Process64BitFile(infile)) {
364 fprintf(stderr, "%s: Could not process 64 bit ELF file\n",
365 infile);
366 return 1;
367 }
368 } else {
369 fprintf(stderr, "%s: Invalid ELF file!\n",
370 infile);
371 return 1;
372 }
373
374 if (g_errors != 0)
375 return 1;
376
377 WriteOutput(outfile);
378 return 0;
379 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698