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