1 /* 2 * Copyright (c) 1999 - 2006 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifdef HAVE_CONFIG_H 37 #include <config.h> 38 #endif 39 #ifdef HAVE_SYS_MMAN_H 40 #include <sys/mman.h> 41 #endif 42 #include <stdio.h> 43 #include <string.h> 44 #include <err.h> 45 #include <roken.h> 46 47 #include "asn1-common.h" 48 #include "check-common.h" 49 50 RCSID("$Id$"); 51 52 struct map_page { 53 void *start; 54 size_t size; 55 void *data_start; 56 size_t data_size; 57 enum map_type type; 58 }; 59 60 /* #undef HAVE_MMAP */ 61 62 void * 63 map_alloc(enum map_type type, const void *buf, 64 size_t size, struct map_page **map) 65 { 66 #ifndef HAVE_MMAP 67 unsigned char *p; 68 size_t len = size + sizeof(long) * 2; 69 int i; 70 71 *map = ecalloc(1, sizeof(**map)); 72 73 p = emalloc(len); 74 (*map)->type = type; 75 (*map)->start = p; 76 (*map)->size = len; 77 (*map)->data_start = p + sizeof(long); 78 for (i = sizeof(long); i > 0; i--) 79 p[sizeof(long) - i] = 0xff - i; 80 for (i = sizeof(long); i > 0; i--) 81 p[len - i] = 0xff - i; 82 #else 83 unsigned char *p; 84 int flags, ret, fd; 85 size_t pagesize = getpagesize(); 86 87 *map = ecalloc(1, sizeof(**map)); 88 89 (*map)->type = type; 90 91 #ifdef MAP_ANON 92 flags = MAP_ANON; 93 fd = -1; 94 #else 95 flags = 0; 96 fd = open ("/dev/zero", O_RDONLY); 97 if(fd < 0) 98 err (1, "open /dev/zero"); 99 #endif 100 flags |= MAP_PRIVATE; 101 102 (*map)->size = size + pagesize - (size % pagesize) + pagesize * 2; 103 104 p = (unsigned char *)mmap(0, (*map)->size, PROT_READ | PROT_WRITE, 105 flags, fd, 0); 106 if (p == (unsigned char *)MAP_FAILED) 107 err (1, "mmap"); 108 109 (*map)->start = p; 110 111 ret = mprotect (p, pagesize, 0); 112 if (ret < 0) 113 err (1, "mprotect"); 114 115 ret = mprotect (p + (*map)->size - pagesize, pagesize, 0); 116 if (ret < 0) 117 err (1, "mprotect"); 118 119 switch (type) { 120 case OVERRUN: 121 (*map)->data_start = p + (*map)->size - pagesize - size; 122 break; 123 case UNDERRUN: 124 (*map)->data_start = p + pagesize; 125 break; 126 default: 127 abort(); 128 } 129 #endif 130 (*map)->data_size = size; 131 if (buf) 132 memcpy((*map)->data_start, buf, size); 133 return (*map)->data_start; 134 } 135 136 void 137 map_free(struct map_page *map, const char *test_name, const char *map_name) 138 { 139 #ifndef HAVE_MMAP 140 unsigned char *p = map->start; 141 int i; 142 143 for (i = sizeof(long); i > 0; i--) 144 if (p[sizeof(long) - i] != 0xff - i) 145 errx(1, "%s: %s underrun %d\n", test_name, map_name, i); 146 for (i = sizeof(long); i > 0; i--) 147 if (p[map->size - i] != 0xff - i) 148 errx(1, "%s: %s overrun %lu\n", test_name, map_name, 149 (unsigned long)map->size - i); 150 free(map->start); 151 #else 152 int ret; 153 154 ret = munmap (map->start, map->size); 155 if (ret < 0) 156 err (1, "munmap"); 157 #endif 158 free(map); 159 } 160 161 static void 162 print_bytes (unsigned const char *buf, size_t len) 163 { 164 int i; 165 166 for (i = 0; i < len; ++i) 167 printf ("%02x ", buf[i]); 168 } 169 170 #ifndef MAP_FAILED 171 #define MAP_FAILED (-1) 172 #endif 173 174 static char *current_test = "<uninit>"; 175 static char *current_state = "<uninit>"; 176 177 static RETSIGTYPE 178 segv_handler(int sig) 179 { 180 int fd; 181 char msg[] = "SIGSEGV i current test: "; 182 183 fd = open("/dev/stdout", O_WRONLY, 0600); 184 if (fd >= 0) { 185 write(fd, msg, sizeof(msg)); 186 write(fd, current_test, strlen(current_test)); 187 write(fd, " ", 1); 188 write(fd, current_state, strlen(current_state)); 189 write(fd, "\n", 1); 190 close(fd); 191 } 192 _exit(1); 193 } 194 195 int 196 generic_test (const struct test_case *tests, 197 unsigned ntests, 198 size_t data_size, 199 int (ASN1CALL *encode)(unsigned char *, size_t, void *, size_t *), 200 int (ASN1CALL *length)(void *), 201 int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *), 202 int (ASN1CALL *free_data)(void *), 203 int (*cmp)(void *a, void *b), 204 int (ASN1CALL *copy)(const void *from, void *to)) 205 { 206 unsigned char *buf, *buf2; 207 int i; 208 int failures = 0; 209 void *data; 210 struct map_page *data_map, *buf_map, *buf2_map; 211 212 #ifdef HAVE_SIGACTION 213 struct sigaction sa, osa; 214 #endif 215 216 for (i = 0; i < ntests; ++i) { 217 int ret; 218 size_t sz, consumed_sz, length_sz, buf_sz; 219 void *to = NULL; 220 221 current_test = tests[i].name; 222 223 current_state = "init"; 224 225 #ifdef HAVE_SIGACTION 226 sigemptyset (&sa.sa_mask); 227 sa.sa_flags = 0; 228 #ifdef SA_RESETHAND 229 sa.sa_flags |= SA_RESETHAND; 230 #endif 231 sa.sa_handler = segv_handler; 232 sigaction (SIGSEGV, &sa, &osa); 233 #endif 234 235 data = map_alloc(OVERRUN, NULL, data_size, &data_map); 236 237 buf_sz = tests[i].byte_len; 238 buf = map_alloc(UNDERRUN, NULL, buf_sz, &buf_map); 239 240 current_state = "encode"; 241 ret = (*encode) (buf + buf_sz - 1, buf_sz, 242 tests[i].val, &sz); 243 if (ret != 0) { 244 printf ("encoding of %s failed %d\n", tests[i].name, ret); 245 ++failures; 246 continue; 247 } 248 if (sz != tests[i].byte_len) { 249 printf ("encoding of %s has wrong len (%lu != %lu)\n", 250 tests[i].name, 251 (unsigned long)sz, (unsigned long)tests[i].byte_len); 252 ++failures; 253 continue; 254 } 255 256 current_state = "length"; 257 length_sz = (*length) (tests[i].val); 258 if (sz != length_sz) { 259 printf ("length for %s is bad (%lu != %lu)\n", 260 tests[i].name, (unsigned long)length_sz, (unsigned long)sz); 261 ++failures; 262 continue; 263 } 264 265 current_state = "memcmp"; 266 if (memcmp (buf, tests[i].bytes, tests[i].byte_len) != 0) { 267 printf ("encoding of %s has bad bytes:\n" 268 "correct: ", tests[i].name); 269 print_bytes ((unsigned char *)tests[i].bytes, tests[i].byte_len); 270 printf ("\nactual: "); 271 print_bytes (buf, sz); 272 printf ("\n"); 273 #if 0 274 rk_dumpdata("correct", tests[i].bytes, tests[i].byte_len); 275 rk_dumpdata("actual", buf, sz); 276 exit (1); 277 #endif 278 ++failures; 279 continue; 280 } 281 282 buf2 = map_alloc(OVERRUN, buf, sz, &buf2_map); 283 284 current_state = "decode"; 285 ret = (*decode) (buf2, sz, data, &consumed_sz); 286 if (ret != 0) { 287 printf ("decoding of %s failed %d\n", tests[i].name, ret); 288 ++failures; 289 continue; 290 } 291 if (sz != consumed_sz) { 292 printf ("different length decoding %s (%ld != %ld)\n", 293 tests[i].name, 294 (unsigned long)sz, (unsigned long)consumed_sz); 295 ++failures; 296 continue; 297 } 298 current_state = "cmp"; 299 if ((*cmp)(data, tests[i].val) != 0) { 300 printf ("%s: comparison failed\n", tests[i].name); 301 ++failures; 302 continue; 303 } 304 305 current_state = "copy"; 306 if (copy) { 307 to = emalloc(data_size); 308 ret = (*copy)(data, to); 309 if (ret != 0) { 310 printf ("copy of %s failed %d\n", tests[i].name, ret); 311 ++failures; 312 continue; 313 } 314 315 current_state = "cmp-copy"; 316 if ((*cmp)(data, to) != 0) { 317 printf ("%s: copy comparison failed\n", tests[i].name); 318 ++failures; 319 continue; 320 } 321 } 322 323 current_state = "free"; 324 if (free_data) { 325 (*free_data)(data); 326 if (to) { 327 (*free_data)(to); 328 free(to); 329 } 330 } 331 332 current_state = "free"; 333 map_free(buf_map, tests[i].name, "encode"); 334 map_free(buf2_map, tests[i].name, "decode"); 335 map_free(data_map, tests[i].name, "data"); 336 337 #ifdef HAVE_SIGACTION 338 sigaction (SIGSEGV, &osa, NULL); 339 #endif 340 } 341 current_state = "done"; 342 return failures; 343 } 344 345 /* 346 * check for failures 347 * 348 * a test size (byte_len) of -1 means that the test tries to trigger a 349 * integer overflow (and later a malloc of to little memory), just 350 * allocate some memory and hope that is enough for that test. 351 */ 352 353 int 354 generic_decode_fail (const struct test_case *tests, 355 unsigned ntests, 356 size_t data_size, 357 int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)) 358 { 359 unsigned char *buf; 360 int i; 361 int failures = 0; 362 void *data; 363 struct map_page *data_map, *buf_map; 364 365 #ifdef HAVE_SIGACTION 366 struct sigaction sa, osa; 367 #endif 368 369 for (i = 0; i < ntests; ++i) { 370 int ret; 371 size_t sz; 372 const void *bytes; 373 374 current_test = tests[i].name; 375 376 current_state = "init"; 377 378 #ifdef HAVE_SIGACTION 379 sigemptyset (&sa.sa_mask); 380 sa.sa_flags = 0; 381 #ifdef SA_RESETHAND 382 sa.sa_flags |= SA_RESETHAND; 383 #endif 384 sa.sa_handler = segv_handler; 385 sigaction (SIGSEGV, &sa, &osa); 386 #endif 387 388 data = map_alloc(OVERRUN, NULL, data_size, &data_map); 389 390 if (tests[i].byte_len < 0xffffff && tests[i].byte_len >= 0) { 391 sz = tests[i].byte_len; 392 bytes = tests[i].bytes; 393 } else { 394 sz = 4096; 395 bytes = NULL; 396 } 397 398 buf = map_alloc(OVERRUN, bytes, sz, &buf_map); 399 400 if (tests[i].byte_len == -1) 401 memset(buf, 0, sz); 402 403 current_state = "decode"; 404 ret = (*decode) (buf, tests[i].byte_len, data, &sz); 405 if (ret == 0) { 406 printf ("sucessfully decoded %s\n", tests[i].name); 407 ++failures; 408 continue; 409 } 410 411 current_state = "free"; 412 if (buf) 413 map_free(buf_map, tests[i].name, "encode"); 414 map_free(data_map, tests[i].name, "data"); 415 416 #ifdef HAVE_SIGACTION 417 sigaction (SIGSEGV, &osa, NULL); 418 #endif 419 } 420 current_state = "done"; 421 return failures; 422 } 423