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 = ecalloc(1, sizeof(**map)); 68 69 p = emalloc(len); 70 (*map)->type = type; 71 (*map)->start = p; 72 (*map)->size = len; 73 (*map)->data_start = p + sizeof(long); 74 for (i = sizeof(long); i > 0; i--) 75 p[sizeof(long) - i] = 0xff - i; 76 for (i = sizeof(long); i > 0; i--) 77 p[len - i] = 0xff - i; 78#else 79 unsigned char *p; 80 int flags, ret, fd; 81 size_t pagesize = getpagesize(); 82 83 *map = ecalloc(1, sizeof(**map)); 84 85 (*map)->type = type; 86 87#ifdef MAP_ANON 88 flags = MAP_ANON; 89 fd = -1; 90#else 91 flags = 0; 92 fd = open ("/dev/zero", O_RDONLY); 93 if(fd < 0) 94 err (1, "open /dev/zero"); 95#endif 96 flags |= MAP_PRIVATE; 97 98 (*map)->size = size + pagesize - (size % pagesize) + pagesize * 2; 99 100 p = (unsigned char *)mmap(0, (*map)->size, PROT_READ | PROT_WRITE, 101 flags, fd, 0); 102 if (p == (unsigned char *)MAP_FAILED) 103 err (1, "mmap"); 104 105 (*map)->start = p; 106 107 ret = mprotect (p, pagesize, 0); 108 if (ret < 0) 109 err (1, "mprotect"); 110 111 ret = mprotect (p + (*map)->size - pagesize, pagesize, 0); 112 if (ret < 0) 113 err (1, "mprotect"); 114 115 switch (type) { 116 case OVERRUN: 117 (*map)->data_start = p + (*map)->size - pagesize - size; 118 break; 119 case UNDERRUN: 120 (*map)->data_start = p + pagesize; 121 break; 122 default: 123 abort(); 124 } 125#endif 126 (*map)->data_size = size; 127 if (buf) 128 memcpy((*map)->data_start, buf, size); 129 return (*map)->data_start; 130} 131 132void 133map_free(struct map_page *map, const char *test_name, const char *map_name) 134{ 135#ifndef HAVE_MMAP 136 unsigned char *p = map->start; 137 int i; 138 139 for (i = sizeof(long); i > 0; i--) 140 if (p[sizeof(long) - i] != 0xff - i) 141 errx(1, "%s: %s underrun %d\n", test_name, map_name, i); 142 for (i = sizeof(long); i > 0; i--) 143 if (p[map->size - i] != 0xff - i) 144 errx(1, "%s: %s overrun %lu\n", test_name, map_name, 145 (unsigned long)map->size - i); 146 free(map->start); 147#else 148 int ret; 149 150 ret = munmap (map->start, map->size); 151 if (ret < 0) 152 err (1, "munmap"); 153#endif 154 free(map); 155} 156 157static void 158print_bytes (unsigned const char *buf, size_t len) 159{ 160 int i; 161 162 for (i = 0; i < len; ++i) 163 printf ("%02x ", buf[i]); 164} 165 166#ifndef MAP_FAILED 167#define MAP_FAILED (-1) 168#endif 169 170static char *current_test = "<uninit>"; 171static char *current_state = "<uninit>"; 172 173static RETSIGTYPE 174segv_handler(int sig) 175{ 176 int fd; 177 char msg[] = "SIGSEGV i current test: "; 178 179 fd = open("/dev/stdout", O_WRONLY, 0600); 180 if (fd >= 0) { 181 write(fd, msg, sizeof(msg)); 182 write(fd, current_test, strlen(current_test)); 183 write(fd, " ", 1); 184 write(fd, current_state, strlen(current_state)); 185 write(fd, "\n", 1); 186 close(fd); 187 } 188 _exit(1); 189} 190 191int 192generic_test (const struct test_case *tests, 193 unsigned ntests, 194 size_t data_size, 195 int (ASN1CALL *encode)(unsigned char *, size_t, void *, size_t *), 196 int (ASN1CALL *length)(void *), 197 int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *), 198 int (ASN1CALL *free_data)(void *), 199 int (*cmp)(void *a, void *b), 200 int (ASN1CALL *copy)(const void *from, void *to)) 201{ 202 unsigned char *buf, *buf2; 203 int i; 204 int failures = 0; 205 void *data; 206 struct map_page *data_map, *buf_map, *buf2_map; 207 208#ifdef HAVE_SIGACTION 209 struct sigaction sa, osa; 210#endif 211 212 for (i = 0; i < ntests; ++i) { 213 int ret; 214 size_t sz, consumed_sz, length_sz, buf_sz; 215 void *to = NULL; 216 217 current_test = tests[i].name; 218 219 current_state = "init"; 220 221#ifdef HAVE_SIGACTION 222 sigemptyset (&sa.sa_mask); 223 sa.sa_flags = 0; 224#ifdef SA_RESETHAND 225 sa.sa_flags |= SA_RESETHAND; 226#endif 227 sa.sa_handler = segv_handler; 228 sigaction (SIGSEGV, &sa, &osa); 229#endif 230 231 data = map_alloc(OVERRUN, NULL, data_size, &data_map); 232 233 buf_sz = tests[i].byte_len; 234 buf = map_alloc(UNDERRUN, NULL, buf_sz, &buf_map); 235 236 current_state = "encode"; 237 ret = (*encode) (buf + buf_sz - 1, buf_sz, 238 tests[i].val, &sz); 239 if (ret != 0) { 240 printf ("encoding of %s failed %d\n", tests[i].name, ret); 241 ++failures; 242 continue; 243 } 244 if (sz != tests[i].byte_len) { 245 printf ("encoding of %s has wrong len (%lu != %lu)\n", 246 tests[i].name, 247 (unsigned long)sz, (unsigned long)tests[i].byte_len); 248 ++failures; 249 continue; 250 } 251 252 current_state = "length"; 253 length_sz = (*length) (tests[i].val); 254 if (sz != length_sz) { 255 printf ("length for %s is bad (%lu != %lu)\n", 256 tests[i].name, (unsigned long)length_sz, (unsigned long)sz); 257 ++failures; 258 continue; 259 } 260 261 current_state = "memcmp"; 262 if (memcmp (buf, tests[i].bytes, tests[i].byte_len) != 0) { 263 printf ("encoding of %s has bad bytes:\n" 264 "correct: ", tests[i].name); 265 print_bytes ((unsigned char *)tests[i].bytes, tests[i].byte_len); 266 printf ("\nactual: "); 267 print_bytes (buf, sz); 268 printf ("\n"); 269#if 0 270 rk_dumpdata("correct", tests[i].bytes, tests[i].byte_len); 271 rk_dumpdata("actual", buf, sz); 272 exit (1); 273#endif 274 ++failures; 275 continue; 276 } 277 278 buf2 = map_alloc(OVERRUN, buf, sz, &buf2_map); 279 280 current_state = "decode"; 281 ret = (*decode) (buf2, sz, data, &consumed_sz); 282 if (ret != 0) { 283 printf ("decoding of %s failed %d\n", tests[i].name, ret); 284 ++failures; 285 continue; 286 } 287 if (sz != consumed_sz) { 288 printf ("different length decoding %s (%ld != %ld)\n", 289 tests[i].name, 290 (unsigned long)sz, (unsigned long)consumed_sz); 291 ++failures; 292 continue; 293 } 294 current_state = "cmp"; 295 if ((*cmp)(data, tests[i].val) != 0) { 296 printf ("%s: comparison failed\n", tests[i].name); 297 ++failures; 298 continue; 299 } 300 301 current_state = "copy"; 302 if (copy) { 303 to = emalloc(data_size); 304 ret = (*copy)(data, to); 305 if (ret != 0) { 306 printf ("copy of %s failed %d\n", tests[i].name, ret); 307 ++failures; 308 continue; 309 } 310 311 current_state = "cmp-copy"; 312 if ((*cmp)(data, to) != 0) { 313 printf ("%s: copy comparison failed\n", tests[i].name); 314 ++failures; 315 continue; 316 } 317 } 318 319 current_state = "free"; 320 if (free_data) { 321 (*free_data)(data); 322 if (to) { 323 (*free_data)(to); 324 free(to); 325 } 326 } 327 328 current_state = "free"; 329 map_free(buf_map, tests[i].name, "encode"); 330 map_free(buf2_map, tests[i].name, "decode"); 331 map_free(data_map, tests[i].name, "data"); 332 333#ifdef HAVE_SIGACTION 334 sigaction (SIGSEGV, &osa, NULL); 335#endif 336 } 337 current_state = "done"; 338 return failures; 339} 340 341/* 342 * check for failures 343 * 344 * a test size (byte_len) of -1 means that the test tries to trigger a 345 * integer overflow (and later a malloc of to little memory), just 346 * allocate some memory and hope that is enough for that test. 347 */ 348 349int 350generic_decode_fail (const struct test_case *tests, 351 unsigned ntests, 352 size_t data_size, 353 int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)) 354{ 355 unsigned char *buf; 356 int i; 357 int failures = 0; 358 void *data; 359 struct map_page *data_map, *buf_map; 360 361#ifdef HAVE_SIGACTION 362 struct sigaction sa, osa; 363#endif 364 365 for (i = 0; i < ntests; ++i) { 366 int ret; 367 size_t sz; 368 const void *bytes; 369 370 current_test = tests[i].name; 371 372 current_state = "init"; 373 374#ifdef HAVE_SIGACTION 375 sigemptyset (&sa.sa_mask); 376 sa.sa_flags = 0; 377#ifdef SA_RESETHAND 378 sa.sa_flags |= SA_RESETHAND; 379#endif 380 sa.sa_handler = segv_handler; 381 sigaction (SIGSEGV, &sa, &osa); 382#endif 383 384 data = map_alloc(OVERRUN, NULL, data_size, &data_map); 385 386 if (tests[i].byte_len < 0xffffff && tests[i].byte_len >= 0) { 387 sz = tests[i].byte_len; 388 bytes = tests[i].bytes; 389 } else { 390 sz = 4096; 391 bytes = NULL; 392 } 393 394 buf = map_alloc(OVERRUN, bytes, sz, &buf_map); 395 396 if (tests[i].byte_len == -1) 397 memset(buf, 0, sz); 398 399 current_state = "decode"; 400 ret = (*decode) (buf, tests[i].byte_len, data, &sz); 401 if (ret == 0) { 402 printf ("sucessfully decoded %s\n", tests[i].name); 403 ++failures; 404 continue; 405 } 406 407 current_state = "free"; 408 if (buf) 409 map_free(buf_map, tests[i].name, "encode"); 410 map_free(data_map, tests[i].name, "data"); 411 412#ifdef HAVE_SIGACTION 413 sigaction (SIGSEGV, &osa, NULL); 414#endif 415 } 416 current_state = "done"; 417 return failures; 418} 419