OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011 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 #include <assert.h> | |
8 #include <elf.h> | |
9 #include <inttypes.h> | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <string.h> | |
13 #include "validator.h" | |
14 | |
15 #undef TRUE | |
16 #define TRUE 1 | |
17 | |
18 #undef FALSE | |
19 #define FALSE 0 | |
20 | |
21 /* This may help with portability but makes code less readable. */ | |
22 #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" | |
23 | |
24 static void CheckBounds(unsigned char *data, size_t data_size, | |
25 void *ptr, size_t inside_size) { | |
26 assert(data <= (unsigned char *) ptr); | |
27 assert((unsigned char *) ptr + inside_size <= data + data_size); | |
28 } | |
29 | |
30 void ReadFile(const char *filename, uint8_t **result, size_t *result_size) { | |
31 FILE *fp; | |
32 uint8_t *data; | |
33 size_t file_size; | |
34 size_t got; | |
35 | |
36 fp = fopen(filename, "rb"); | |
37 if (fp == NULL) { | |
38 fprintf(stderr, "Failed to open input file: %s\n", filename); | |
39 exit(1); | |
40 } | |
41 /* Find the file size. */ | |
42 fseek(fp, 0, SEEK_END); | |
43 file_size = ftell(fp); | |
44 data = malloc(file_size); | |
45 if (data == NULL) { | |
46 fprintf(stderr, "Unable to create memory image of input file: %s\n", | |
47 filename); | |
48 exit(1); | |
49 } | |
50 fseek(fp, 0, SEEK_SET); | |
51 got = fread(data, 1, file_size, fp); | |
52 if (got != file_size) { | |
53 fprintf(stderr, "Unable to read data from input file: %s\n", | |
54 filename); | |
55 exit(1); | |
56 } | |
57 fclose(fp); | |
58 | |
59 *result = data; | |
60 *result_size = file_size; | |
61 } | |
62 | |
63 struct ValidateState { | |
64 uint8_t width; | |
65 const uint8_t *offset; | |
66 }; | |
67 | |
68 void ProcessError (const uint8_t *ptr, void *userdata) { | |
69 printf("rejected at %zx (byte 0x%02x)\n", | |
70 ptr - (((struct ValidateState *)userdata)->offset), *ptr); | |
71 } | |
72 | |
73 int ValidateFile(const char *filename, int repeat_count) { | |
74 size_t data_size; | |
75 uint8_t *data; | |
76 ReadFile(filename, &data, &data_size); | |
77 | |
78 int count; | |
79 if (data[4] == 1) { | |
80 for (count = 0; count < repeat_count; ++count) { | |
81 Elf32_Ehdr *header; | |
82 int index; | |
83 | |
84 header = (Elf32_Ehdr *) data; | |
85 CheckBounds(data, data_size, header, sizeof(*header)); | |
86 assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
87 | |
88 for (index = 0; index < header->e_shnum; ++index) { | |
89 Elf32_Shdr *section = (Elf32_Shdr *) (data + header->e_shoff + | |
90 header->e_shentsize * index); | |
91 CheckBounds(data, data_size, section, sizeof(*section)); | |
92 | |
93 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
94 struct ValidateState state; | |
95 state.offset = data + section->sh_offset - section->sh_addr; | |
96 if (section->sh_size <= 0xfff) { | |
97 state.width = 4; | |
98 } else if (section->sh_size <= 0xfffffff) { | |
99 state.width = 8; | |
100 } else { | |
101 state.width = 12; | |
102 } | |
103 CheckBounds(data, data_size, | |
104 data + section->sh_offset, section->sh_size); | |
105 int res = ValidateChunkIA32(data + section->sh_offset, | |
106 section->sh_size, ProcessError, &state); | |
107 if (res != 0) { | |
108 return res; | |
109 } | |
110 } | |
111 } | |
112 } | |
113 } else if (data[4] == 2) { | |
114 for (count = 0; count < repeat_count; ++count) { | |
115 Elf64_Ehdr *header; | |
116 int index; | |
117 | |
118 header = (Elf64_Ehdr *) data; | |
119 CheckBounds(data, data_size, header, sizeof(*header)); | |
120 assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
121 | |
122 for (index = 0; index < header->e_shnum; ++index) { | |
123 Elf64_Shdr *section = (Elf64_Shdr *) (data + header->e_shoff + | |
124 header->e_shentsize * index); | |
125 CheckBounds(data, data_size, section, sizeof(*section)); | |
126 | |
127 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
128 struct ValidateState state; | |
129 state.offset = data + section->sh_offset - section->sh_addr; | |
130 if (section->sh_size <= 0xfff) { | |
131 state.width = 4; | |
132 } else if (section->sh_size <= 0xfffffff) { | |
133 state.width = 8; | |
134 } else if (section->sh_size <= 0xfffffffffffLL) { | |
135 state.width = 12; | |
136 } else { | |
137 state.width = 16; | |
138 } | |
139 CheckBounds(data, data_size, | |
140 data + section->sh_offset, section->sh_size); | |
141 int res = ValidateChunkAMD64(data + section->sh_offset, | |
142 section->sh_size, ProcessError, &state); | |
143 if (res != 0) { | |
144 return res; | |
145 } | |
146 } | |
147 } | |
148 } | |
149 } else { | |
150 printf("Unknown ELF class: %s\n", filename); | |
151 exit(1); | |
152 } | |
153 return 0; | |
154 } | |
155 | |
156 int main(int argc, char **argv) { | |
157 int index, initial_index = 1, repeat_count = 1; | |
158 if (argc == 1) { | |
159 printf("%s: no input files\n", argv[0]); | |
160 } | |
161 if (!strcmp(argv[1],"--repeat")) | |
162 repeat_count = atoi(argv[2]), | |
163 initial_index += 2; | |
164 for (index = initial_index; index < argc; ++index) { | |
165 const char *filename = argv[index]; | |
166 int rc = ValidateFile(filename, repeat_count); | |
167 if (rc != 0) { | |
168 printf("file '%s' can not be fully validated\n", filename); | |
169 return 1; | |
170 } | |
171 } | |
172 return 0; | |
173 } | |
OLD | NEW |