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