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