xref: /freebsd/crypto/heimdal/lib/asn1/check-common.c (revision 39beb93c)
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