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#include <config.h> 37#ifdef HAVE_SYS_MMAN_H 38#include <sys/mman.h> 39#endif 40#include <stdio.h> 41#include <string.h> 42#include <err.h> 43#include <roken.h> 44 45#include "asn1-common.h" 46#include "check-common.h" 47 48struct map_page { 49 void *start; 50 size_t size; 51 void *data_start; 52 size_t data_size; 53 enum map_type type; 54}; 55 56/* #undef HAVE_MMAP */ 57 58void * 59map_alloc(enum map_type type, const void *buf, 60 size_t size, struct map_page **map) 61{ 62#ifndef HAVE_MMAP 63 unsigned char *p; 64 size_t len = size + sizeof(long) * 2; 65 int i; 66 67 *map = calloc(1, sizeof(**map)); 68 if (*map == NULL) 69 errx(1, "calloc"); 70 71 p = malloc(len); 72 if (p == NULL) 73 errx(1, "malloc"); 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 = calloc(1, sizeof(**map)); 88 if (*map == NULL) 89 errx(1, "calloc"); 90 91 (*map)->type = type; 92 93#ifdef MAP_ANON 94 flags = MAP_ANON; 95 fd = -1; 96#else 97 flags = 0; 98 fd = open ("/dev/zero", O_RDONLY); 99 if(fd < 0) 100 err (1, "open /dev/zero"); 101#endif 102 flags |= MAP_PRIVATE; 103 104 (*map)->size = size + pagesize - (size % pagesize) + pagesize * 2; 105 106 p = (unsigned char *)mmap(0, (*map)->size, PROT_READ | PROT_WRITE, 107 flags, fd, 0); 108 if (p == (unsigned char *)MAP_FAILED) 109 err (1, "mmap"); 110 111 (*map)->start = p; 112 113 ret = mprotect (p, pagesize, 0); 114 if (ret < 0) 115 err (1, "mprotect"); 116 117 ret = mprotect (p + (*map)->size - pagesize, pagesize, 0); 118 if (ret < 0) 119 err (1, "mprotect"); 120 121 switch (type) { 122 case OVERRUN: 123 (*map)->data_start = p + (*map)->size - pagesize - size; 124 break; 125 case UNDERRUN: 126 (*map)->data_start = p + pagesize; 127 break; 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 136void 137map_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 161static void 162print_bytes (unsigned const char *buf, size_t len) 163{ 164 size_t 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 174static char *current_test = "<uninit>"; 175static char *current_state = "<uninit>"; 176 177static RETSIGTYPE 178segv_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 195int 196generic_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 unsigned 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 != (size_t)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 = malloc(data_size); 308 if (to == NULL) 309 errx(1, "malloc"); 310 ret = (*copy)(data, to); 311 if (ret != 0) { 312 printf ("copy of %s failed %d\n", tests[i].name, ret); 313 ++failures; 314 continue; 315 } 316 317 current_state = "cmp-copy"; 318 if ((*cmp)(data, to) != 0) { 319 printf ("%s: copy comparison failed\n", tests[i].name); 320 ++failures; 321 continue; 322 } 323 } 324 325 current_state = "free"; 326 if (free_data) { 327 (*free_data)(data); 328 if (to) { 329 (*free_data)(to); 330 free(to); 331 } 332 } 333 334 current_state = "free"; 335 map_free(buf_map, tests[i].name, "encode"); 336 map_free(buf2_map, tests[i].name, "decode"); 337 map_free(data_map, tests[i].name, "data"); 338 339#ifdef HAVE_SIGACTION 340 sigaction (SIGSEGV, &osa, NULL); 341#endif 342 } 343 current_state = "done"; 344 return failures; 345} 346 347/* 348 * check for failures 349 * 350 * a test size (byte_len) of -1 means that the test tries to trigger a 351 * integer overflow (and later a malloc of to little memory), just 352 * allocate some memory and hope that is enough for that test. 353 */ 354 355int 356generic_decode_fail (const struct test_case *tests, 357 unsigned ntests, 358 size_t data_size, 359 int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)) 360{ 361 unsigned char *buf; 362 unsigned i; 363 int failures = 0; 364 void *data; 365 struct map_page *data_map, *buf_map; 366 367#ifdef HAVE_SIGACTION 368 struct sigaction sa, osa; 369#endif 370 371 for (i = 0; i < ntests; ++i) { 372 int ret; 373 size_t sz; 374 const void *bytes; 375 376 current_test = tests[i].name; 377 378 current_state = "init"; 379 380#ifdef HAVE_SIGACTION 381 sigemptyset (&sa.sa_mask); 382 sa.sa_flags = 0; 383#ifdef SA_RESETHAND 384 sa.sa_flags |= SA_RESETHAND; 385#endif 386 sa.sa_handler = segv_handler; 387 sigaction (SIGSEGV, &sa, &osa); 388#endif 389 390 data = map_alloc(OVERRUN, NULL, data_size, &data_map); 391 392 if (tests[i].byte_len < 0xffffff && tests[i].byte_len >= 0) { 393 sz = tests[i].byte_len; 394 bytes = tests[i].bytes; 395 } else { 396 sz = 4096; 397 bytes = NULL; 398 } 399 400 buf = map_alloc(OVERRUN, bytes, sz, &buf_map); 401 402 if (tests[i].byte_len == -1) 403 memset(buf, 0, sz); 404 405 current_state = "decode"; 406 ret = (*decode) (buf, tests[i].byte_len, data, &sz); 407 if (ret == 0) { 408 printf ("sucessfully decoded %s\n", tests[i].name); 409 ++failures; 410 continue; 411 } 412 413 current_state = "free"; 414 if (buf) 415 map_free(buf_map, tests[i].name, "encode"); 416 map_free(data_map, tests[i].name, "data"); 417 418#ifdef HAVE_SIGACTION 419 sigaction (SIGSEGV, &osa, NULL); 420#endif 421 } 422 current_state = "done"; 423 return failures; 424} 425