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

Side by Side Diff: src/trusted/service_runtime/elf_util.c

Issue 389022: first step in factoring out code dealing with elf into a separate library.... (Closed) Base URL: http://nativeclient.googlecode.com/svn/trunk/src/native_client/
Patch Set: '' Created 11 years, 1 month 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 | « src/trusted/service_runtime/elf_util.h ('k') | src/trusted/service_runtime/mmap_test.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2009 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can
4 * be found in the LICENSE file.
5 */
6
7 /*
8 * NaCl helper functions to deal with elf images
9 */
10
11 #include "native_client/src/include/portability.h"
12
13 #include <stdio.h>
14
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "native_client/src/include/elf_constants.h"
19 #include "native_client/src/include/nacl_elf.h"
20 #include "native_client/src/include/nacl_macros.h"
21
22 #include "native_client/src/shared/platform/nacl_log.h"
23
24 #include "native_client/src/trusted/service_runtime/elf_util.h"
25 #include "native_client/src/trusted/service_runtime/nacl_config.h"
26
27 /* private */
28 struct NaClElfImage {
29 Elf32_Ehdr ehdr;
30 Elf32_Phdr phdrs[NACL_MAX_PROGRAM_HEADERS];
31 int loadable[NACL_MAX_PROGRAM_HEADERS];
32 };
33
34
35 enum NaClPhdrCheckAction {
36 PCA_NONE,
37 PCA_TEXT_CHECK,
38 PCA_IGNORE /* ignore this segment. currently used only for PT_PHDR. */
39 };
40
41
42 struct NaClPhdrChecks {
43 Elf32_Word p_type;
44 Elf32_Word p_flags; /* rwx */
45 enum NaClPhdrCheckAction action;
46 int required; /* only for text for now */
47 Elf32_Word p_vaddr; /* if non-zero, vaddr must be this */
48 };
49
50 /*
51 * Other than empty segments, these are the only ones that are allowed.
52 */
53 static const struct NaClPhdrChecks nacl_phdr_check_data[] = {
54 /* phdr */
55 { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, },
56 /* text */
57 { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_END, },
58 /* rodata */
59 { PT_LOAD, PF_R, PCA_NONE, 0, 0, },
60 /* data/bss */
61 { PT_LOAD, PF_R|PF_W, PCA_NONE, 0, 0, },
62 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
63 /* arm exception handling unwind info (for c++)*/
64 /* TODO(robertm): for some reason this does NOT end up in ro maybe because
65 * it is relocatable. Try hacking the linker script to move it.
66 */
67 { PT_ARM_EXIDX, PF_R, PCA_IGNORE, 0, 0, },
68 #endif
69 /*
70 * allow optional GNU stack permission marker, but require that the
71 * stack is non-executable.
72 */
73 { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, },
74 };
75
76
77
78 static void NaClDumpElfHeader(Elf32_Ehdr *elf_hdr) {
79 #define DUMP(m,f) do { NaClLog(2, \
80 #m " = %" f "\n", \
81 elf_hdr->m); } while (0)
82 DUMP(e_ident+1, ".3s");
83 DUMP(e_type, "#x");
84 DUMP(e_machine, "#x");
85 DUMP(e_version, "#x");
86 DUMP(e_entry, "#x");
87 DUMP(e_phoff, "#x");
88 DUMP(e_shoff, "#x");
89 DUMP(e_flags, "#x");
90 DUMP(e_ehsize, "#x");
91 DUMP(e_phentsize, "#x");
92 DUMP(e_phnum, "#x");
93 DUMP(e_shentsize, "#x");
94 DUMP(e_shnum, "#x");
95 DUMP(e_shstrndx, "#x");
96 #undef DUMP
97 NaClLog(2, "sizeof(Elf32_Ehdr) = %x\n", (int) sizeof *elf_hdr);
98 }
99
100
101 static void NaClDumpElfProgramHeader(Elf32_Phdr *phdr) {
102 #define DUMP(mem) do { \
103 NaClLog(2, "%s: %x\n", #mem, phdr->mem); \
104 } while (0)
105
106 DUMP(p_type);
107 DUMP(p_offset);
108 DUMP(p_vaddr);
109 DUMP(p_paddr);
110 DUMP(p_filesz);
111 DUMP(p_memsz);
112 DUMP(p_flags);
113 NaClLog(2, " (%s %s %s)\n",
114 (phdr->p_flags & PF_R) ? "PF_R" : "",
115 (phdr->p_flags & PF_W) ? "PF_W" : "",
116 (phdr->p_flags & PF_X) ? "PF_X" : "");
117 DUMP(p_align);
118 #undef DUMP
119 NaClLog(2, "\n");
120 }
121
122
123 NaClErrorCode NaClElfImageValidateAbi(struct NaClElfImage *image) {
124 const Elf32_Ehdr *hdr = &image->ehdr;
125
126 if (ELFOSABI_NACL != hdr->e_ident[EI_OSABI]) {
127 NaClLog(LOG_ERROR, "Expected OSABI %d, got %d\n",
128 ELFOSABI_NACL,
129 hdr->e_ident[EI_OSABI]);
130 return LOAD_BAD_ABI;
131 }
132
133 if (EF_NACL_ABIVERSION != hdr->e_ident[EI_ABIVERSION]) {
134 NaClLog(LOG_ERROR, "Expected ABIVERSION %d, got %d\n",
135 EF_NACL_ABIVERSION,
136 hdr->e_ident[EI_ABIVERSION]);
137 return LOAD_BAD_ABI;
138 }
139
140 return LOAD_OK;
141 }
142
143
144 NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) {
145 const Elf32_Ehdr *hdr = &image->ehdr;
146
147 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) {
148 NaClLog(LOG_ERROR, "bad elf magic\n");
149 return LOAD_BAD_ELF_MAGIC;
150 }
151
152 if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) {
153 NaClLog(LOG_ERROR, "bad elf class\n");
154 return LOAD_NOT_32_BIT;
155 }
156
157 if (ET_EXEC != hdr->e_type) {
158 NaClLog(LOG_ERROR, "non executable\n");
159 return LOAD_NOT_EXEC;
160 }
161
162 if (EM_EXPECTED_BY_NACL != hdr->e_machine) {
163 NaClLog(LOG_ERROR, "bad machine\n");
164 return LOAD_BAD_MACHINE;
165 }
166
167 if (EV_CURRENT != hdr->e_version) {
168 NaClLog(LOG_ERROR, "bad elf version\n");
169 return LOAD_BAD_ELF_VERS;
170 }
171
172 return LOAD_OK;
173 }
174
175 /* TODO(robertm): decouple validation from computation of
176 text_region_bytes and max_vaddr */
177 NaClErrorCode NaClElfImageValidateProgramHeaders(
178 struct NaClElfImage *image,
179 uint32_t addr_bits,
180 uint32_t *text_region_bytes,
181 uintptr_t *max_vaddr) {
182 /*
183 * Scan phdrs and do sanity checks in-line. Verify that the load
184 * address is NACL_TRAMPOLINE_END, that we have a single text
185 * segment. Data and TLS segments are not required, though it is
186 * hard to avoid with standard tools, but in any case there should
187 * be at most one each. Ensure that no segment's vaddr is outside
188 * of the address space. Ensure that PT_GNU_STACK is present, and
189 * that x is off.
190 */
191 const Elf32_Ehdr *hdr = &image->ehdr;
192 int seen_seg[NACL_ARRAY_SIZE(nacl_phdr_check_data)];
193
194 int segnum;
195 const Elf32_Phdr *php;
196 size_t j;
197
198 *max_vaddr = NACL_TRAMPOLINE_END;
199
200 /*
201 * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum)
202 * is okay.
203 */
204 memset(seen_seg, 0, sizeof seen_seg);
205 for (segnum = 0; segnum < hdr->e_phnum; ++segnum) {
206 php = &image->phdrs[segnum];
207 NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n",
208 segnum, php->p_type, php->p_flags);
209 for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
210 if (php->p_type == nacl_phdr_check_data[j].p_type
211 && php->p_flags == nacl_phdr_check_data[j].p_flags) {
212 NaClLog(2, "Matched nacl_phdr_check_data[%"PRIdS"]\n", j);
213 if (seen_seg[j] > 0) {
214 NaClLog(2, "Segment %d is a type that has been seen\n", segnum);
215 return LOAD_DUP_SEGMENT;
216 }
217 ++seen_seg[j];
218
219 if (PCA_IGNORE == nacl_phdr_check_data[j].action) {
220 NaClLog(3, "Ignoring\n");
221 goto next_seg;
222 }
223
224 if (0 != php->p_memsz) {
225 /*
226 * We will load this segment later. Do the sanity checks.
227 */
228 if (0 != nacl_phdr_check_data[j].p_vaddr
229 && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) {
230 NaClLog(2,
231 ("Segment %d: bad virtual address: 0x%08x,"
232 " expected 0x%08x\n"),
233 segnum,
234 php->p_vaddr,
235 nacl_phdr_check_data[j].p_vaddr);
236 return LOAD_SEGMENT_BAD_LOC;
237 }
238 if (php->p_vaddr < NACL_TRAMPOLINE_END) {
239 NaClLog(2, "Segment %d: virtual address (0x%08x) too low\n",
240 segnum,
241 php->p_vaddr);
242 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
243 }
244 /*
245 * integer overflow? Elf32_Addr and Elf32_Word are uint32_t,
246 * so the addition/comparison is well defined.
247 */
248 if (php->p_vaddr + php->p_memsz < php->p_vaddr) {
249 NaClLog(2,
250 "Segment %d: p_memsz caused integer overflow\n",
251 segnum);
252 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
253 }
254 if (php->p_vaddr + php->p_memsz >= (1U << addr_bits)) {
255 NaClLog(2,
256 "Segment %d: too large, ends at 0x%08x\n",
257 segnum,
258 php->p_vaddr + php->p_memsz);
259 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
260 }
261 if (php->p_filesz > php->p_memsz) {
262 NaClLog(2,
263 ("Segment %d: file size 0x%08x larger"
264 " than memory size 0x%08x\n"),
265 segnum,
266 php->p_filesz,
267 php->p_memsz);
268 return LOAD_SEGMENT_BAD_PARAM;
269 }
270
271 image->loadable[segnum] = 1;
272 /* record our decision that we will load this segment */
273
274 /*
275 * NACL_TRAMPOLINE_END <= p_vaddr
276 * <= p_vaddr + p_memsz
277 * < (1U << nap->addr_bits)
278 */
279 if (*max_vaddr < php->p_vaddr + php->p_memsz) {
280 *max_vaddr = php->p_vaddr + php->p_memsz;
281 }
282 }
283
284 switch (nacl_phdr_check_data[j].action) {
285 case PCA_NONE:
286 break;
287 case PCA_TEXT_CHECK:
288 if (0 == php->p_memsz) {
289 return LOAD_BAD_ELF_TEXT;
290 }
291 *text_region_bytes = php->p_filesz;
292 break;
293 case PCA_IGNORE:
294 break;
295 }
296 goto next_seg;
297 }
298 }
299 /* segment not in nacl_phdr_check_data */
300 if (0 == php->p_memsz) {
301 NaClLog(3, "Segment %d zero size: ignored\n", segnum);
302 continue;
303 }
304 NaClLog(2,
305 "Segment %d is of unexpected type 0x%x, flag 0x%x\n",
306 segnum,
307 php->p_type,
308 php->p_flags);
309 return LOAD_BAD_SEGMENT;
310 next_seg:
311 {}
312 }
313 for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
314 if (nacl_phdr_check_data[j].required && !seen_seg[j]) {
315 return LOAD_REQUIRED_SEG_MISSING;
316 }
317 }
318
319 /*
320 * Memory allocation will use NaClRoundPage(nap->break_addr), but
321 * the system notion of break is always an exact address. Even
322 * though we must allocate and make accessible multiples of pages,
323 * the linux-style brk system call (which returns current break on
324 * failure) permits an arbitrarily aligned address as argument.
325 */
326
327 return LOAD_OK;
328 }
329
330
331 struct NaClElfImage *NaClElfImageNew(struct Gio *gp) {
332 struct NaClElfImage *result;
333 struct NaClElfImage image;
334 int cur_ph;
335
336 memset(image.loadable, 0, sizeof image.loadable);
337 if ((*gp->vtbl->Read)(gp,
338 &image.ehdr,
339 sizeof image.ehdr)
340 != sizeof image.ehdr) {
341 /* Consider making this fatal */
342 NaClLog(2, "could not load elf headers\n");
343 return 0;
344 }
345
346 NaClDumpElfHeader(&image.ehdr);
347
348 /* read program headers */
349 if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) {
350 /* Consider making this fatal */
351 NaClLog(2, "too many prog headers\n");
352 return 0;
353 }
354
355 if (image.ehdr.e_phentsize < sizeof image.phdrs[0]) {
356 NaClLog(2, "bad prog headers size\n");
357 return 0;
358 }
359
360 if ((*gp->vtbl->Seek)(gp,
361 image.ehdr.e_phoff,
362 SEEK_SET) == -1) {
363 NaClLog(2, "cannot seek tp prog headers\n");
364 return 0;
365 }
366
367 if ((*gp->vtbl->Read)(gp,
368 &image.phdrs[0],
369 image.ehdr.e_phnum * sizeof image.phdrs[0])
370 != (int32_t) (image.ehdr.e_phnum * sizeof image.phdrs[0])) {
371 NaClLog(2, "cannot load tp prog headers\n");
372 return 0;
373 }
374
375 for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
376 NaClDumpElfProgramHeader(&image.phdrs[cur_ph]);
377 }
378
379 /* we delay allocating till the end to avoid cleanup code */
380 result = malloc(sizeof image);
381 if (result == 0) {
382 NaClLog(LOG_FATAL, "no enough memory for image meta data\n");
383 return 0;
384 }
385 memcpy(result, &image, sizeof image);
386 return result;
387 }
388
389
390 NaClErrorCode NaClElfImageLoad(struct NaClElfImage *image,
391 struct Gio *gp,
392 uint32_t addr_bits,
393 uintptr_t mem_start) {
394 int segnum;
395 uintptr_t paddr;
396 uintptr_t end_vaddr;
397
398 for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
399 const Elf32_Phdr *php = &image->phdrs[segnum];
400
401 /* did we decide that we will load this segment earlier? */
402 if (!image->loadable[segnum]) {
403 continue;
404 }
405
406 NaClLog(2, "loading segment %d", segnum);
407 end_vaddr = php->p_vaddr + php->p_filesz;
408 /* integer overflow? */
409 if (end_vaddr < php->p_vaddr) {
410 NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
411 }
412 /*
413 * is the end virtual address within the NaCl application's
414 * address space? if it is, it implies that the start virtual
415 * address is also.
416 */
417 if (end_vaddr >= (1U << addr_bits)) {
418 NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
419 }
420
421 paddr = mem_start + php->p_vaddr;
422
423 if ((*gp->vtbl->Seek)(gp, php->p_offset, SEEK_SET) == -1) {
424 NaClLog(LOG_ERROR, "seek failure segment %d", segnum);
425 return LOAD_SEGMENT_BAD_PARAM;
426 }
427 if ((Elf32_Word) (*gp->vtbl->Read)(gp, (void *) paddr, php->p_filesz)
428 != php->p_filesz) {
429 NaClLog(LOG_ERROR, "load failure segment %d", segnum);
430 return LOAD_SEGMENT_BAD_PARAM;
431 }
432 /* region from p_filesz to p_memsz should already be zero filled */
433 }
434
435 return LOAD_OK;
436 }
437
438
439 void NaClElfImageDelete(struct NaClElfImage *image) {
440 free(image);
441 }
442
443
444 uint32_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) {
445 return image->ehdr.e_entry;
446 }
447
448
449 /* TODO(robertm): this code should enforce that either 16 or 32 bit alignment is
450 is set - there are currently some problems with ARM, though
451 */
452 int NaClElfImageGetAlignBoundary(struct NaClElfImage *image) {
453 unsigned long eflags = image->ehdr.e_flags & EF_NACL_ALIGN_MASK;
454 if (eflags) {
455 if (eflags == EF_NACL_ALIGN_16) {
456 return 16;
457 } else if (eflags == EF_NACL_ALIGN_32) {
458 return 32;
459 } else {
460 NaClLog(LOG_ERROR, "strange alignment");
461 return 0;
462 }
463 } else {
464 return 32;
465 }
466 }
OLDNEW
« no previous file with comments | « src/trusted/service_runtime/elf_util.h ('k') | src/trusted/service_runtime/mmap_test.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698