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