Commit much improved ASN.1 compiler from joda-choice-branch.
Highlighs for the compiler is support for CHOICE and in general better support for tags. This compiler support most of what is needed for PK-INIT, LDAP, X.509, PKCS-12 and many other protocols. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@15617 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (c) 1999 - 2003 Kungliga Tekniska H<>gskolan | ||||
|  * Copyright (c) 1999 - 2005 Kungliga Tekniska H<>gskolan | ||||
|  * (Royal Institute of Technology, Stockholm, Sweden).  | ||||
|  * All rights reserved.  | ||||
|  * | ||||
| @@ -34,6 +34,9 @@ | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include <config.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_MMAN_H | ||||
| #include <sys/mman.h> | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <err.h> | ||||
| @@ -43,6 +46,107 @@ | ||||
|  | ||||
| RCSID("$Id$"); | ||||
|  | ||||
| struct map_page { | ||||
|     void *start; | ||||
|     size_t size; | ||||
|     void *data_start; | ||||
|     size_t data_size; | ||||
|     enum map_type type; | ||||
| }; | ||||
|  | ||||
| /* #undef HAVE_MMAP */ | ||||
|  | ||||
| void * | ||||
| map_alloc(enum map_type type, const void *buf,  | ||||
| 	  size_t size, struct map_page **map) | ||||
| { | ||||
| #ifndef HAVE_MMAP | ||||
|     unsigned char *p; | ||||
|      | ||||
|     *map = ecalloc(1, sizeof(**map)); | ||||
|  | ||||
|     p = emalloc(size + 2); | ||||
|     (*map)->type = type; | ||||
|     (*map)->start = p; | ||||
|     (*map)->size = size + 2; | ||||
|     p[0] = 0xff; | ||||
|     p[(*map)->size] = 0xff; | ||||
|     (*map)->data_start = p + 1; | ||||
| #else | ||||
|     unsigned char *p; | ||||
|     int flags, ret, fd; | ||||
|     size_t pagesize = getpagesize(); | ||||
|  | ||||
|     *map = ecalloc(1, sizeof(**map)); | ||||
|  | ||||
|     (*map)->type = type; | ||||
|  | ||||
| #ifdef MAP_ANON | ||||
|     flags = MAP_ANON; | ||||
|     fd = -1; | ||||
| #else | ||||
|     flags = 0; | ||||
|     fd = open ("/dev/zero", O_RDONLY); | ||||
|     if(fd < 0) | ||||
| 	err (1, "open /dev/zero"); | ||||
| #endif | ||||
|     flags |= MAP_PRIVATE; | ||||
|  | ||||
|     (*map)->size = size + pagesize - (size % pagesize) + pagesize * 2; | ||||
|  | ||||
|     p = (char *)mmap(0, (*map)->size, PROT_READ | PROT_WRITE, | ||||
| 		      flags, fd, 0); | ||||
|     if (p == (unsigned char *)MAP_FAILED) | ||||
| 	err (1, "mmap"); | ||||
|  | ||||
|     (*map)->start = p; | ||||
|  | ||||
|     ret = mprotect (p, pagesize, 0); | ||||
|     if (ret < 0) | ||||
| 	err (1, "mprotect"); | ||||
|  | ||||
|     ret = mprotect (p + (*map)->size - pagesize, pagesize, 0); | ||||
|     if (ret < 0) | ||||
| 	err (1, "mprotect"); | ||||
|  | ||||
|     switch (type) { | ||||
|     case OVERRUN: | ||||
| 	(*map)->data_start = p + (*map)->size - pagesize - size; | ||||
| 	break; | ||||
|     case UNDERRUN: | ||||
| 	(*map)->data_start = p + pagesize; | ||||
| 	break; | ||||
|    default: | ||||
| 	abort(); | ||||
|     } | ||||
| #endif | ||||
|     (*map)->data_size = size; | ||||
|     if (buf) | ||||
| 	memcpy((*map)->data_start, buf, size); | ||||
|     return (*map)->data_start; | ||||
| } | ||||
|  | ||||
| void | ||||
| map_free(struct map_page *map, const char *test_name, const char *map_name) | ||||
| { | ||||
| #ifndef HAVE_MMAP | ||||
|     unsigned char *p = map->start; | ||||
|      | ||||
|     if (p[0] != 0xff) | ||||
| 	errx(1, "%s: %s underrun %x\n", test_name, map_name, p[0]); | ||||
|     if (p[map->size] != 0xff) | ||||
| 	errx(1, "%s: %s overrun %x\n", test_name, map_name, p[map->size - 1]); | ||||
|     free(map->start); | ||||
| #else | ||||
|     int ret; | ||||
|      | ||||
|     ret = munmap (map->start, map->size); | ||||
|     if (ret < 0) | ||||
| 	err (1, "munmap"); | ||||
| #endif | ||||
|     free(map); | ||||
| } | ||||
|  | ||||
| static void | ||||
| print_bytes (unsigned const char *buf, size_t len) | ||||
| { | ||||
| @@ -52,6 +156,31 @@ print_bytes (unsigned const char *buf, size_t len) | ||||
| 	printf ("%02x ", buf[i]); | ||||
| } | ||||
|  | ||||
| #ifndef MAP_FAILED | ||||
| #define MAP_FAILED (-1) | ||||
| #endif | ||||
|  | ||||
| static char *current_test = "<uninit>"; | ||||
| static char *current_state = "<uninit>"; | ||||
|  | ||||
| static RETSIGTYPE | ||||
| segv_handler(int sig) | ||||
| { | ||||
|     int fd; | ||||
|     char msg[] = "SIGSEGV i current test: "; | ||||
|      | ||||
|     fd = open("/dev/stdout", O_WRONLY, 0600); | ||||
|     if (fd >= 0) { | ||||
| 	write(fd, msg, sizeof(msg)); | ||||
| 	write(fd, current_test, strlen(current_test)); | ||||
| 	write(fd, " ", 1); | ||||
| 	write(fd, current_state, strlen(current_state)); | ||||
| 	write(fd, "\n", 1); | ||||
| 	close(fd); | ||||
|     } | ||||
|     _exit(1); | ||||
| } | ||||
|  | ||||
| int | ||||
| generic_test (const struct test_case *tests, | ||||
| 	      unsigned ntests, | ||||
| @@ -59,67 +188,181 @@ generic_test (const struct test_case *tests, | ||||
| 	      int (*encode)(unsigned char *, size_t, void *, size_t *), | ||||
| 	      int (*length)(void *), | ||||
| 	      int (*decode)(unsigned char *, size_t, void *, size_t *), | ||||
| 	      int (*free_data)(void *), | ||||
| 	      int (*cmp)(void *a, void *b)) | ||||
| { | ||||
|     unsigned char buf[4711]; | ||||
|     unsigned char *buf, *buf2; | ||||
|     int i; | ||||
|     int failures = 0; | ||||
|     void *val = malloc (data_size); | ||||
|     void *data; | ||||
|     struct map_page *data_map, *buf_map, *buf2_map; | ||||
|  | ||||
|     if (data_size != 0 && val == NULL) | ||||
| 	err (1, "malloc"); | ||||
|     struct sigaction sa, osa; | ||||
|  | ||||
|     for (i = 0; i < ntests; ++i) { | ||||
| 	int ret; | ||||
| 	size_t sz, consumed_sz, length_sz; | ||||
| 	unsigned char *beg; | ||||
| 	size_t sz, consumed_sz, length_sz, buf_sz; | ||||
|  | ||||
| 	ret = (*encode) (buf + sizeof(buf) - 1, sizeof(buf), | ||||
| 	current_test = tests[i].name; | ||||
|  | ||||
| 	current_state = "init"; | ||||
|  | ||||
| 	sigemptyset (&sa.sa_mask); | ||||
| 	sa.sa_flags = 0; | ||||
| #ifdef SA_RESETHAND | ||||
| 	sa.sa_flags |= SA_RESETHAND; | ||||
| #endif | ||||
| 	sa.sa_handler = segv_handler; | ||||
| 	sigaction (SIGSEGV, &sa, &osa); | ||||
|  | ||||
| 	data = map_alloc(OVERRUN, NULL, data_size, &data_map); | ||||
|  | ||||
| 	buf_sz = tests[i].byte_len; | ||||
| 	buf = map_alloc(UNDERRUN, NULL, buf_sz, &buf_map); | ||||
|  | ||||
| 	current_state = "encode"; | ||||
| 	ret = (*encode) (buf + buf_sz - 1, buf_sz, | ||||
| 			 tests[i].val, &sz); | ||||
| 	beg = buf + sizeof(buf) - sz; | ||||
| 	if (ret != 0) { | ||||
| 	    printf ("encoding of %s failed\n", tests[i].name); | ||||
| 	    printf ("encoding of %s failed %d\n", tests[i].name, ret); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
| 	if (sz != tests[i].byte_len) { | ||||
| 	    printf ("encoding of %s has wrong len (%lu != %lu)\n", | ||||
| 		    tests[i].name,  | ||||
| 		    (unsigned long)sz, (unsigned long)tests[i].byte_len); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
|  | ||||
| 	current_state = "length"; | ||||
| 	length_sz = (*length) (tests[i].val); | ||||
| 	if (sz != length_sz) { | ||||
| 	    printf ("length for %s is bad (%lu != %lu)\n", | ||||
| 		    tests[i].name, (unsigned long)length_sz, (unsigned long)sz); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
|  | ||||
| 	if (memcmp (beg, tests[i].bytes, tests[i].byte_len) != 0) { | ||||
| 	current_state = "memcmp"; | ||||
| 	if (memcmp (buf, tests[i].bytes, tests[i].byte_len) != 0) { | ||||
| 	    printf ("encoding of %s has bad bytes:\n" | ||||
| 		    "correct: ", tests[i].name); | ||||
| 	    print_bytes (tests[i].bytes, tests[i].byte_len); | ||||
| 	    printf ("\nactual:  "); | ||||
| 	    print_bytes (beg, sz); | ||||
| 	    print_bytes (buf, sz); | ||||
| 	    printf ("\n"); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
| 	ret = (*decode) (beg, sz, val, &consumed_sz); | ||||
|  | ||||
| 	buf2 = map_alloc(OVERRUN, buf, sz, &buf2_map); | ||||
|  | ||||
| 	current_state = "decode"; | ||||
| 	ret = (*decode) (buf2, sz, data, &consumed_sz); | ||||
| 	if (ret != 0) { | ||||
| 	    printf ("decoding of %s failed\n", tests[i].name); | ||||
| 	    printf ("decoding of %s failed %d\n", tests[i].name, ret); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
| 	if (sz != consumed_sz) { | ||||
| 	    printf ("different length decoding %s (%ld != %ld)\n", | ||||
| 		    tests[i].name,  | ||||
| 		    (unsigned long)sz, (unsigned long)consumed_sz); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
| 	if ((*cmp)(val, tests[i].val) != 0) { | ||||
| 	current_state = "cmp"; | ||||
| 	if ((*cmp)(data, tests[i].val) != 0) { | ||||
| 	    printf ("%s: comparison failed\n", tests[i].name); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
| 	current_state = "free"; | ||||
| 	if (free_data) | ||||
| 	    (*free_data)(data); | ||||
|  | ||||
| 	current_state = "free"; | ||||
| 	map_free(buf_map, tests[i].name, "encode"); | ||||
| 	map_free(buf2_map, tests[i].name, "decode"); | ||||
| 	map_free(data_map, tests[i].name, "data"); | ||||
|  | ||||
| 	sigaction (SIGSEGV, &osa, NULL); | ||||
|     } | ||||
|     free (val); | ||||
|     current_state = "done"; | ||||
|     return failures; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * check for failures | ||||
|  *  | ||||
|  * a test size (byte_len) of -1 means that the test tries to trigger a | ||||
|  * integer overflow (and later a malloc of to little memory), just | ||||
|  * allocate some memory and hope that is enough for that test. | ||||
|  */ | ||||
|  | ||||
| int | ||||
| generic_decode_fail (const struct test_case *tests, | ||||
| 		     unsigned ntests, | ||||
| 		     size_t data_size, | ||||
| 		     int (*decode)(unsigned char *, size_t, void *, size_t *)) | ||||
| { | ||||
|     unsigned char *buf; | ||||
|     int i; | ||||
|     int failures = 0; | ||||
|     void *data; | ||||
|     struct map_page *data_map, *buf_map; | ||||
|  | ||||
|     struct sigaction sa, osa; | ||||
|  | ||||
|     for (i = 0; i < ntests; ++i) { | ||||
| 	int ret; | ||||
| 	size_t sz; | ||||
| 	const void *bytes; | ||||
| 	 | ||||
| 	current_test = tests[i].name; | ||||
|  | ||||
| 	current_state = "init"; | ||||
|  | ||||
| 	sigemptyset (&sa.sa_mask); | ||||
| 	sa.sa_flags = 0; | ||||
| #ifdef SA_RESETHAND | ||||
| 	sa.sa_flags |= SA_RESETHAND; | ||||
| #endif | ||||
| 	sa.sa_handler = segv_handler; | ||||
| 	sigaction (SIGSEGV, &sa, &osa); | ||||
|  | ||||
| 	data = map_alloc(OVERRUN, NULL, data_size, &data_map); | ||||
|  | ||||
| 	if (tests[i].byte_len != -1) { | ||||
| 	    sz = tests[i].byte_len; | ||||
| 	    bytes = tests[i].bytes; | ||||
| 	} else { | ||||
| 	    sz = 4096; | ||||
| 	    bytes = NULL; | ||||
| 	} | ||||
| 		 | ||||
| 	buf = map_alloc(OVERRUN, bytes, sz, &buf_map); | ||||
|  | ||||
| 	if (tests[i].byte_len == -1) | ||||
| 	    memset(buf, 0, sz); | ||||
|  | ||||
| 	current_state = "decode"; | ||||
| 	ret = (*decode) (buf, tests[i].byte_len, data, &sz); | ||||
| 	if (ret == 0) { | ||||
| 	    printf ("sucessfully decoded %s\n", tests[i].name); | ||||
| 	    ++failures; | ||||
| 	    continue; | ||||
| 	} | ||||
|  | ||||
| 	current_state = "free"; | ||||
| 	if (buf) | ||||
| 	    map_free(buf_map, tests[i].name, "encode"); | ||||
| 	map_free(data_map, tests[i].name, "data"); | ||||
|  | ||||
| 	sigaction (SIGSEGV, &osa, NULL); | ||||
|     } | ||||
|     current_state = "done"; | ||||
|     return failures; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Love Hörnquist Åstrand
					Love Hörnquist Åstrand