OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 The Native Client Authors. All rights reserved. | 2 * Copyright 2010 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can | 3 * Use of this source code is governed by a BSD-style license that can |
4 * be found in the LICENSE file. | 4 * be found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <stdio.h> | 9 #include <stdio.h> |
| 10 #include <stdint.h> |
10 #include <stdlib.h> | 11 #include <stdlib.h> |
11 #include <string.h> | 12 #include <string.h> |
12 #include <sys/mman.h> | 13 #include <sys/mman.h> |
13 | 14 |
14 #include <sys/nacl_syscalls.h> | 15 #include <sys/nacl_syscalls.h> |
15 | 16 |
16 #include "native_client/tests/dynamic_code_loading/templates.h" | 17 #include "native_client/tests/dynamic_code_loading/templates.h" |
| 18 #include "native_client/tests/inbrowser_test_runner/test_runner.h" |
| 19 |
| 20 #if defined(__x86_64__) |
| 21 #define BUF_SIZE 64 |
| 22 #else |
| 23 #define BUF_SIZE 32 |
| 24 #endif |
17 | 25 |
18 #define NACL_BUNDLE_SIZE 32 | 26 #define NACL_BUNDLE_SIZE 32 |
19 /* | 27 /* |
20 * TODO(bsy): get this value from the toolchain. Get the toolchain | 28 * TODO(bsy): get this value from the toolchain. Get the toolchain |
21 * team to provide this value. | 29 * team to provide this value. |
22 */ | 30 */ |
23 #define NUM_BUNDLES_FOR_HLT 3 | 31 #define NUM_BUNDLES_FOR_HLT 3 |
24 | 32 |
25 /* TODO(mseaborn): Add a symbol to the linker script for finding the | 33 /* TODO(mseaborn): Add a symbol to the linker script for finding the |
26 end of the static code segment more accurately. The value below is | 34 end of the static code segment more accurately. The value below is |
27 an approximation. */ | 35 an approximation. */ |
28 #define DYNAMIC_CODE_SEGMENT_START 0x80000 | 36 #define DYNAMIC_CODE_SEGMENT_START 0x80000 |
29 /* TODO(mseaborn): Add a symbol to the linker script for finding the | 37 /* TODO(mseaborn): Add a symbol to the linker script for finding the |
30 end of the dynamic code region. The value below is duplicated in | 38 end of the dynamic code region. The value below is duplicated in |
31 nacl.scons, passed via --section-start. */ | 39 nacl.scons, passed via --section-start. */ |
32 #define DYNAMIC_CODE_SEGMENT_END 0x1000000 | 40 #define DYNAMIC_CODE_SEGMENT_END 0x1000000 |
33 | 41 |
| 42 struct code_section { |
| 43 char *name; |
| 44 char *start; |
| 45 char *end; |
| 46 }; |
34 | 47 |
35 char *next_addr = (char *) DYNAMIC_CODE_SEGMENT_START; | 48 struct code_section illegal_code_sections[] = { |
| 49 { "misaligned_replacement", |
| 50 &template_func_misaligned_replacement, |
| 51 &template_func_misaligned_replacement_end }, |
| 52 { "illegal_register_replacement", |
| 53 &template_func_illegal_register_replacement, |
| 54 &template_func_illegal_register_replacement_end }, |
| 55 { "illegal_guard_replacement", |
| 56 &template_func_illegal_guard_replacement, |
| 57 &template_func_illegal_guard_replacement_end }, |
| 58 { "illegal_call_target", |
| 59 &template_func_illegal_call_target, |
| 60 &template_func_illegal_call_target_end }, |
| 61 { "illegal_constant_replacement", |
| 62 &template_func_illegal_constant_replacement, |
| 63 &template_func_illegal_constant_replacement_end }, |
| 64 }; |
36 | 65 |
37 char *allocate_code_space(int pages) { | 66 uint8_t *next_addr = (uint8_t *) DYNAMIC_CODE_SEGMENT_START; |
38 char *addr = next_addr; | 67 |
| 68 uint8_t *allocate_code_space(int pages) { |
| 69 uint8_t *addr = next_addr; |
39 next_addr += 0x10000 * pages; | 70 next_addr += 0x10000 * pages; |
40 assert(next_addr < (char *) DYNAMIC_CODE_SEGMENT_END); | 71 assert(next_addr < (uint8_t *) DYNAMIC_CODE_SEGMENT_END); |
41 return addr; | 72 return addr; |
42 } | 73 } |
43 | 74 |
44 void fill_int32(uint8_t *data, size_t size, int32_t value) { | 75 void fill_int32(uint8_t *data, size_t size, int32_t value) { |
45 int i; | 76 int i; |
46 assert(size % 4 == 0); | 77 assert(size % 4 == 0); |
47 /* All the archs we target supported unaligned word read/write, but | 78 /* All the archs we target supported unaligned word read/write, but |
48 check that the pointer is aligned anyway. */ | 79 check that the pointer is aligned anyway. */ |
49 assert(((uintptr_t) data) % 4 == 0); | 80 assert(((uintptr_t) data) % 4 == 0); |
50 for (i = 0; i < size / 4; i++) | 81 for (i = 0; i < size / 4; i++) |
(...skipping 14 matching lines...) Expand all Loading... |
65 awkward because we have to output them in data mode, in which the | 96 awkward because we have to output them in data mode, in which the |
66 assembler wants to output zeroes instead of NOPs for padding. | 97 assembler wants to output zeroes instead of NOPs for padding. |
67 Also, the assembler won't put in a terminating HLT, which we need | 98 Also, the assembler won't put in a terminating HLT, which we need |
68 on x86-32. So we do the padding at run time. */ | 99 on x86-32. So we do the padding at run time. */ |
69 void copy_and_pad_fragment(void *dest, | 100 void copy_and_pad_fragment(void *dest, |
70 int dest_size, | 101 int dest_size, |
71 const char *fragment_start, | 102 const char *fragment_start, |
72 const char *fragment_end) { | 103 const char *fragment_end) { |
73 int fragment_size = fragment_end - fragment_start; | 104 int fragment_size = fragment_end - fragment_start; |
74 assert(dest_size % 32 == 0); | 105 assert(dest_size % 32 == 0); |
75 assert(fragment_size < dest_size); | 106 assert(fragment_size <= dest_size); |
76 fill_nops(dest, dest_size); | 107 fill_nops(dest, dest_size); |
77 memcpy(dest, fragment_start, fragment_size); | 108 memcpy(dest, fragment_start, fragment_size); |
78 } | 109 } |
79 | 110 |
80 /* Check that we can't dynamically rewrite code. */ | 111 /* Check that we can't dynamically rewrite code. */ |
81 void test_replacing_code() { | 112 void test_replacing_code() { |
82 uint8_t *load_area = allocate_code_space(1); | 113 uint8_t *load_area = allocate_code_space(1); |
83 uint8_t buf[32]; | 114 uint8_t buf[BUF_SIZE]; |
84 int rc; | 115 int rc; |
85 int (*func)(); | 116 int (*func)(); |
86 | 117 |
87 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 118 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
88 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); | 119 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
89 assert(rc == 0); | 120 assert(rc == 0); |
90 func = (int (*)()) (uintptr_t) load_area; | 121 func = (int (*)()) (uintptr_t) load_area; |
91 rc = func(); | 122 rc = func(); |
92 assert(rc == 1234); | 123 assert(rc == 1234); |
93 | 124 |
94 /* write replacement to the same location */ | 125 /* write replacement to the same location */ |
95 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, | 126 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, |
96 &template_func_replacement_end); | 127 &template_func_replacement_end); |
97 rc = nacl_dyncode_modify(load_area, buf, sizeof(buf)); | 128 rc = nacl_dyncode_modify(load_area, buf, sizeof(buf)); |
98 assert(rc == 0); | 129 assert(rc == 0); |
99 func = (int (*)()) (uintptr_t) load_area; | 130 func = (int (*)()) (uintptr_t) load_area; |
100 rc = func(); | 131 rc = func(); |
101 assert(rc == 4321); | 132 assert(rc == 4321); |
102 } | 133 } |
103 | 134 |
104 | 135 |
105 /* Check that we can dynamically rewrite code. */ | 136 /* Check that we can dynamically rewrite code. */ |
106 void test_replacing_code_unaligned() { | 137 void test_replacing_code_unaligned() { |
107 uint8_t *load_area = allocate_code_space(1); | 138 uint8_t *load_area = allocate_code_space(1); |
108 uint8_t buf[32]; | 139 uint8_t buf[BUF_SIZE]; |
109 int first_diff = 0; | 140 int first_diff = 0; |
110 int rc; | 141 int rc; |
111 int (*func)(); | 142 int (*func)(); |
112 | 143 |
113 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 144 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
114 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); | 145 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
115 assert(rc == 0); | 146 assert(rc == 0); |
116 func = (int (*)()) (uintptr_t) load_area; | 147 func = (int (*)()) (uintptr_t) load_area; |
117 rc = func(); | 148 rc = func(); |
118 assert(rc == 1234); | 149 assert(rc == 1234); |
119 | 150 |
120 | |
121 /* write replacement to the same location, unaligned */ | 151 /* write replacement to the same location, unaligned */ |
122 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, | 152 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, |
123 &template_func_replacement_end); | 153 &template_func_replacement_end); |
124 while (buf[first_diff] == load_area[first_diff] && first_diff < sizeof buf) { | 154 while (buf[first_diff] == load_area[first_diff] && first_diff < sizeof buf) { |
125 first_diff++; | 155 first_diff++; |
126 } | 156 } |
127 assert(first_diff>0); | 157 assert(first_diff > 0 && first_diff <= sizeof(buf)); |
128 rc = nacl_dyncode_modify(load_area+first_diff, buf+first_diff, | 158 rc = nacl_dyncode_modify(load_area+first_diff, buf+first_diff, |
129 sizeof(buf)-first_diff); | 159 sizeof(buf)-first_diff); |
130 assert(rc == 0); | 160 assert(rc == 0); |
131 func = (int (*)()) (uintptr_t) load_area; | 161 func = (int (*)()) (uintptr_t) load_area; |
132 rc = func(); | 162 rc = func(); |
133 assert(rc == 4321); | 163 assert(rc == 4321); |
134 } | 164 } |
135 | 165 |
136 /* Check that we can dynamically delete code. */ | 166 /* Check that we can dynamically delete code. */ |
137 void test_deleting_code() { | 167 void test_deleting_code() { |
138 uint8_t *load_area = allocate_code_space(1); | 168 uint8_t *load_area = allocate_code_space(1); |
139 uint8_t buf[32]; | 169 uint8_t buf[BUF_SIZE]; |
140 int first_diff = 0; | |
141 int rc; | 170 int rc; |
142 int (*func)(); | 171 int (*func)(); |
143 | 172 |
144 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 173 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
145 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); | 174 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
146 assert(rc == 0); | 175 assert(rc == 0); |
147 func = (int (*)()) (uintptr_t) load_area; | 176 func = (int (*)()) (uintptr_t) load_area; |
148 rc = func(); | 177 rc = func(); |
149 assert(rc == 1234); | 178 assert(rc == 1234); |
150 | 179 |
151 rc = nacl_dyncode_delete(load_area, sizeof buf); | 180 rc = nacl_dyncode_delete(load_area, sizeof buf); |
152 assert(rc == 0); | 181 assert(rc == 0); |
153 assert(load_area[0] != buf[0]); | 182 assert(load_area[0] != buf[0]); |
154 } | 183 } |
155 | 184 |
| 185 /* Check code replacement constraints */ |
| 186 void test_illegal_code_replacment() { |
| 187 uint8_t *load_area = allocate_code_space(1); |
| 188 uint8_t buf[BUF_SIZE]; |
| 189 int rc; |
| 190 int i; |
| 191 int (*func)(); |
| 192 |
| 193 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
| 194 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
| 195 assert(rc == 0); |
| 196 func = (int (*)()) (uintptr_t) load_area; |
| 197 rc = func(); |
| 198 assert(rc == 1234); |
| 199 |
| 200 for (i = 0; |
| 201 i < (sizeof(illegal_code_sections) / sizeof(struct code_section)); |
| 202 i++) { |
| 203 printf("\t%s\n", illegal_code_sections[i].name); |
| 204 |
| 205 /* write illegal replacement to the same location */ |
| 206 copy_and_pad_fragment(buf, sizeof(buf), illegal_code_sections[i].start, |
| 207 illegal_code_sections[i].end); |
| 208 rc = nacl_dyncode_modify(load_area, buf, sizeof(buf)); |
| 209 assert(rc != 0); |
| 210 func = (int (*)()) (uintptr_t) load_area; |
| 211 rc = func(); |
| 212 assert(rc == 1234); |
| 213 } |
| 214 } |
156 | 215 |
157 /* Check that we can't dynamically rewrite code. */ | 216 /* Check that we can't dynamically rewrite code. */ |
158 void test_replacing_code_disabled() { | 217 void test_replacing_code_disabled() { |
159 uint8_t *load_area = allocate_code_space(1); | 218 uint8_t *load_area = allocate_code_space(1); |
160 uint8_t buf[32]; | 219 uint8_t buf[BUF_SIZE]; |
161 int rc; | 220 int rc; |
162 int (*func)(); | 221 int (*func)(); |
163 | 222 |
164 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 223 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
165 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); | 224 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
166 assert(rc == 0); | 225 assert(rc == 0); |
167 func = (int (*)()) (uintptr_t) load_area; | 226 func = (int (*)()) (uintptr_t) load_area; |
168 rc = func(); | 227 rc = func(); |
169 assert(rc == 1234); | 228 assert(rc == 1234); |
170 | 229 |
171 /* write replacement to the same location */ | 230 /* write replacement to the same location */ |
172 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, | 231 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, |
173 &template_func_replacement_end); | 232 &template_func_replacement_end); |
174 rc = nacl_dyncode_modify(load_area, buf, sizeof(buf)); | 233 rc = nacl_dyncode_modify(load_area, buf, sizeof(buf)); |
175 assert(rc != 0); | 234 assert(rc != 0); |
176 func = (int (*)()) (uintptr_t) load_area; | 235 func = (int (*)()) (uintptr_t) load_area; |
177 rc = func(); | 236 rc = func(); |
178 assert(rc == 1234); | 237 assert(rc == 1234); |
179 } | 238 } |
180 | 239 |
181 /* Check that we can dynamically rewrite code. */ | 240 /* Check that we can dynamically rewrite code. */ |
182 void test_replacing_code_unaligned_disabled() { | 241 void test_replacing_code_unaligned_disabled() { |
183 uint8_t *load_area = allocate_code_space(1); | 242 uint8_t *load_area = allocate_code_space(1); |
184 uint8_t buf[32]; | 243 uint8_t buf[BUF_SIZE]; |
185 int first_diff = 0; | 244 int first_diff = 0; |
186 int rc; | 245 int rc; |
187 int (*func)(); | 246 int (*func)(); |
188 | 247 |
189 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 248 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
190 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); | 249 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
191 assert(rc == 0); | 250 assert(rc == 0); |
192 func = (int (*)()) (uintptr_t) load_area; | 251 func = (int (*)()) (uintptr_t) load_area; |
193 rc = func(); | 252 rc = func(); |
194 assert(rc == 1234); | 253 assert(rc == 1234); |
195 | 254 |
196 /* write replacement to the same location, unaligned */ | 255 /* write replacement to the same location, unaligned */ |
197 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, | 256 copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement, |
198 &template_func_replacement_end); | 257 &template_func_replacement_end); |
199 while (buf[first_diff] == load_area[first_diff] && first_diff < sizeof buf) { | 258 while (buf[first_diff] == load_area[first_diff] && first_diff < sizeof buf) { |
200 first_diff++; | 259 first_diff++; |
201 } | 260 } |
202 rc = nacl_dyncode_modify(load_area+first_diff, buf+first_diff, | 261 rc = nacl_dyncode_modify(load_area+first_diff, buf+first_diff, |
203 sizeof(buf)-first_diff); | 262 sizeof(buf)-first_diff); |
204 assert(rc != 0); | 263 assert(rc != 0); |
205 func = (int (*)()) (uintptr_t) load_area; | 264 func = (int (*)()) (uintptr_t) load_area; |
206 rc = func(); | 265 rc = func(); |
207 assert(rc == 1234); | 266 assert(rc == 1234); |
208 } | 267 } |
209 | 268 |
210 | 269 |
211 /* Check that we can't delete code */ | 270 /* Check that we can't delete code */ |
212 void test_deleting_code_disabled() { | 271 void test_deleting_code_disabled() { |
213 uint8_t *load_area = allocate_code_space(1); | 272 uint8_t *load_area = allocate_code_space(1); |
214 uint8_t buf[32]; | 273 uint8_t buf[BUF_SIZE]; |
215 int first_diff = 0; | |
216 int rc; | 274 int rc; |
217 int (*func)(); | 275 int (*func)(); |
218 | 276 |
219 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 277 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
220 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); | 278 rc = nacl_dyncode_create(load_area, buf, sizeof(buf)); |
221 assert(rc == 0); | 279 assert(rc == 0); |
222 func = (int (*)()) (uintptr_t) load_area; | 280 func = (int (*)()) (uintptr_t) load_area; |
223 rc = func(); | 281 rc = func(); |
224 assert(rc == 1234); | 282 assert(rc == 1234); |
225 | 283 |
226 rc = nacl_dyncode_delete(load_area, sizeof buf); | 284 rc = nacl_dyncode_delete(load_area, sizeof buf); |
227 assert(rc != 0); | 285 assert(rc != 0); |
228 assert(load_area[0] == buf[0]); | 286 assert(load_area[0] == buf[0]); |
229 } | 287 } |
230 | 288 |
231 void run_test(const char *test_name, void (*test_func)(void)) { | 289 void run_test(const char *test_name, void (*test_func)(void)) { |
232 printf("Running %s...\n", test_name); | 290 printf("Running %s...\n", test_name); |
233 test_func(); | 291 test_func(); |
234 } | 292 } |
235 | 293 |
236 int is_replacement_enabled() { | 294 int is_replacement_enabled() { |
237 char trash; | 295 char trash; |
238 return (0 == nacl_dyncode_modify(allocate_code_space(1), &trash, 0)); | 296 return (0 == nacl_dyncode_modify(allocate_code_space(1), &trash, 0)); |
239 } | 297 } |
240 | 298 |
241 #define RUN_TEST(test_func) (run_test(#test_func, test_func)) | 299 #define RUN_TEST(test_func) (run_test(#test_func, test_func)) |
242 | 300 |
243 int main() { | 301 int TestMain() { |
244 /* Turn off stdout buffering to aid debugging in case of a crash. */ | 302 /* Turn off stdout buffering to aid debugging in case of a crash. */ |
245 setvbuf(stdout, NULL, _IONBF, 0); | 303 setvbuf(stdout, NULL, _IONBF, 0); |
246 | 304 |
247 if (is_replacement_enabled()) { | 305 if (is_replacement_enabled()) { |
248 printf("Code replacement ENABLED\n"); | 306 printf("Code replacement ENABLED\n"); |
249 RUN_TEST(test_replacing_code); | 307 RUN_TEST(test_replacing_code); |
250 RUN_TEST(test_replacing_code_unaligned); | 308 RUN_TEST(test_replacing_code_unaligned); |
251 RUN_TEST(test_deleting_code); | 309 RUN_TEST(test_deleting_code); |
| 310 RUN_TEST(test_illegal_code_replacment); |
252 } else { | 311 } else { |
253 printf("Code replacement DISABLED\n"); | 312 printf("Code replacement DISABLED\n"); |
254 RUN_TEST(test_replacing_code_disabled); | 313 RUN_TEST(test_replacing_code_disabled); |
255 RUN_TEST(test_replacing_code_unaligned_disabled); | 314 RUN_TEST(test_replacing_code_unaligned_disabled); |
256 RUN_TEST(test_deleting_code_disabled); | 315 RUN_TEST(test_deleting_code_disabled); |
257 } | 316 } |
258 | 317 |
259 return 0; | 318 return 0; |
260 } | 319 } |
261 | 320 |
| 321 int main() { |
| 322 return RunTests(TestMain); |
| 323 } |
| 324 |
OLD | NEW |