t_kcov.c revision 1.8 1 /*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2018, 2019 Andrew Turner
5 *
6 * This software was developed by SRI International and the University of
7 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
8 * ("CTSRD"), as part of the DARPA CRASH research programme.
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 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31 #include <sys/cdefs.h>
32
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/kcov.h>
36 #include <sys/mman.h>
37
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pthread.h>
41 #include <semaphore.h>
42 #include <unistd.h>
43
44 #include <atf-c.h>
45
46 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
47
48 static int
49 open_kcov(void)
50 {
51 int fd;
52
53 fd = open("/dev/kcov", O_RDWR);
54 if (fd == -1)
55 atf_tc_skip("Failed to open /dev/kcov");
56
57 return fd;
58 }
59
60 static int
61 pick_unassigned_fd(int greater_than_fd)
62 {
63 int fd2;
64
65 fd2 = greater_than_fd;
66 do {
67 ++fd2;
68 } while (fcntl(fd2, F_GETFL) != -1 || errno != EBADF);
69
70 return fd2;
71 }
72
73 ATF_TC_WITHOUT_HEAD(kcov_dup2);
74 ATF_TC_BODY(kcov_dup2, tc)
75 {
76 int fd1, fd2;
77 fd1 = open_kcov();
78
79 fd2 = pick_unassigned_fd(fd1);
80
81 /* Test the dup2(2) trick used by syzkaller */
82 ATF_REQUIRE_EQ(dup2(fd1, fd2), fd2);
83
84 close(fd1);
85 close(fd2);
86 }
87
88 ATF_TC_WITHOUT_HEAD(kcov_multiopen);
89 ATF_TC_BODY(kcov_multiopen, tc)
90 {
91 int fd1, fd2;
92 fd1 = open_kcov();
93
94 fd2 = open("/dev/kcov", O_RDWR);
95 ATF_REQUIRE(fd2 != -1);
96
97 close(fd1);
98 close(fd2);
99 }
100
101 ATF_TC_WITHOUT_HEAD(kcov_open_close_open);
102 ATF_TC_BODY(kcov_open_close_open, tc)
103 {
104 int fd;
105
106 fd = open_kcov();
107 close(fd);
108 fd = open("/dev/kcov", O_RDWR);
109 ATF_REQUIRE(fd != -1);
110
111 close(fd);
112 }
113
114 ATF_TC_WITHOUT_HEAD(kcov_bufsize);
115 ATF_TC_BODY(kcov_bufsize, tc)
116 {
117 int fd;
118 uint64_t size;
119 fd = open_kcov();
120
121 size = 0;
122 ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1);
123 size = 2;
124 ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
125
126 close(fd);
127 }
128
129 ATF_TC_WITHOUT_HEAD(kcov_mmap);
130 ATF_TC_BODY(kcov_mmap, tc)
131 {
132 void *data;
133 int fd;
134 uint64_t size = 2 * PAGE_SIZE / KCOV_ENTRY_SIZE;
135
136 fd = open_kcov();
137
138 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
139 fd, 0) == MAP_FAILED);
140
141 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
142
143 ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
144 MAP_SHARED, fd, 0)) != MAP_FAILED);
145
146 munmap(data, 2 * PAGE_SIZE);
147
148 close(fd);
149 }
150
151 /* This shouldn't panic */
152 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
153 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
154 {
155 int fd;
156 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
157
158 fd = open_kcov();
159
160 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
161
162 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
163 fd, 0) != MAP_FAILED);
164
165 close(fd);
166 }
167
168 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
169 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
170 {
171 int fd;
172 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
173
174 fd = open_kcov();
175
176 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
177
178 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
179 fd, 0) != MAP_FAILED);
180 }
181
182 static sem_t sem1, sem2;
183
184 static void *
185 kcov_mmap_enable_thread(void *data)
186 {
187 int fd;
188 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
189 int mode;
190
191 fd = open_kcov();
192 *(int *)data = fd;
193
194 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
195 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
196 fd, 0) != MAP_FAILED);
197 mode = KCOV_MODE_NONE;
198 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
199
200 sem_post(&sem1);
201 sem_wait(&sem2);
202
203 return NULL;
204 }
205
206 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
207 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
208 {
209 pthread_t thread;
210 int fd;
211
212 sem_init(&sem1, 0, 0);
213 sem_init(&sem2, 0, 0);
214 pthread_create(&thread, NULL,
215 kcov_mmap_enable_thread, &fd);
216 sem_wait(&sem1);
217 close(fd);
218 sem_post(&sem2);
219 pthread_join(thread, NULL);
220 }
221
222 ATF_TC_WITHOUT_HEAD(kcov_enable);
223 ATF_TC_BODY(kcov_enable, tc)
224 {
225 int fd;
226 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
227 int mode;
228
229 fd = open_kcov();
230
231 mode = KCOV_MODE_NONE;
232 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1);
233
234 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
235
236 /* We need to enable before disable */
237 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
238
239 /* Check enabling works only with a valid trace method */
240 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
241 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1);
242
243 /* Disable should only be called once */
244 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
245 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
246
247 /* Re-enabling and changing mode should also work */
248 mode = KCOV_MODE_NONE;
249 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
250 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
251 mode = KCOV_MODE_TRACE_PC;
252 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
253 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
254 mode = KCOV_MODE_TRACE_CMP;
255 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
256 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
257
258 close(fd);
259 }
260
261 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
262 ATF_TC_BODY(kcov_enable_no_disable, tc)
263 {
264 int fd;
265 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
266 int mode;
267
268 fd = open_kcov();
269 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
270 mode = KCOV_MODE_NONE;
271 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
272 close(fd);
273 }
274
275 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
276 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
277 {
278 int fd;
279 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
280 int mode;
281
282 fd = open_kcov();
283 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
284 mode = KCOV_MODE_NONE;
285 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
286 }
287
288 static void *
289 common_head_raw(bool fd_dup, int *fdp)
290 {
291 void *data;
292 int fd, fd2;
293 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
294
295 fd = open_kcov();
296
297 /* Test the dup2(2) trick used by syzkaller */
298 if (fd_dup) {
299 fd2 = pick_unassigned_fd(fd);
300 ATF_REQUIRE_EQ(dup2(fd, fd2), fd2);
301 close(fd);
302 fd = fd2;
303 }
304
305 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0,
306 "Unable to set the kcov buffer size");
307
308 data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
309 ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
310
311 *fdp = fd;
312 return data;
313 }
314
315 static void *
316 common_head(int *fdp)
317 {
318
319 return common_head_raw(false, fdp);
320 }
321
322 static void
323 common_tail(int fd, kcov_int_t *data)
324 {
325
326 ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0,
327 "Unable to unmap the kcov buffer");
328
329 close(fd);
330 }
331
332 static void
333 kcov_basic(bool fd_dup, int mode)
334 {
335 kcov_int_t *buf;
336 int fd;
337
338 buf = common_head_raw(fd_dup, &fd);
339 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0,
340 "Unable to enable kcov ");
341
342 KCOV_STORE(buf[0], 0);
343
344 sleep(0); /* XXX: Is it enough for all trace types? */
345 ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
346
347 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
348 "Unable to disable kcov");
349
350 common_tail(fd, buf);
351 }
352
353 ATF_TC_WITHOUT_HEAD(kcov_basic_pc);
354 ATF_TC_BODY(kcov_basic_pc, tc)
355 {
356
357 kcov_basic(false, KCOV_MODE_TRACE_PC);
358 }
359
360 ATF_TC_WITHOUT_HEAD(kcov_basic_cmp);
361 ATF_TC_BODY(kcov_basic_cmp, tc)
362 {
363
364 atf_tc_skip("XXX: GCC8 needed");
365
366 kcov_basic(false, KCOV_MODE_TRACE_CMP);
367 }
368
369 ATF_TC_WITHOUT_HEAD(kcov_basic_dup2_pc);
370 ATF_TC_BODY(kcov_basic_dup2_pc, tc)
371 {
372
373 kcov_basic(true, KCOV_MODE_TRACE_PC);
374 }
375
376 ATF_TC_WITHOUT_HEAD(kcov_basic_dup2_cmp);
377 ATF_TC_BODY(kcov_basic_dup2_cmp, tc)
378 {
379
380 atf_tc_skip("XXX: GCC8 needed");
381
382 kcov_basic(true, KCOV_MODE_TRACE_CMP);
383 }
384
385 ATF_TC_WITHOUT_HEAD(kcov_multienable_on_the_same_thread);
386 ATF_TC_BODY(kcov_multienable_on_the_same_thread, tc)
387 {
388 kcov_int_t *buf1, *buf2;
389 int fd1, fd2;
390 int mode;
391
392 buf1 = common_head(&fd1);
393 buf2 = common_head(&fd2);
394 mode = KCOV_MODE_NONE;
395 ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_ENABLE, &mode) == 0,
396 "Unable to enable kcov");
397 ATF_REQUIRE_ERRNO(EBUSY, ioctl(fd2, KCOV_IOC_ENABLE, &mode) != 0);
398
399 ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_DISABLE) == 0,
400 "Unable to disable kcov");
401
402 common_tail(fd1, buf1);
403 common_tail(fd2, buf2);
404 }
405
406 static void *
407 thread_buffer_access_test_helper(void *ptr)
408 {
409 kcov_int_t *buf = ptr;
410
411 /* Test mapped buffer access from a custom thread */
412 KCOV_STORE(buf[0], KCOV_LOAD(buf[0]));
413
414 return NULL;
415 }
416
417 ATF_TC_WITHOUT_HEAD(kcov_buffer_access_from_custom_thread);
418 ATF_TC_BODY(kcov_buffer_access_from_custom_thread, tc)
419 {
420 pthread_t thread;
421 kcov_int_t *buf;
422 int fd;
423 int mode;
424
425 buf = common_head(&fd);
426
427 mode = KCOV_MODE_TRACE_PC;
428 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0,
429 "Unable to enable kcov ");
430
431 pthread_create(&thread, NULL, thread_buffer_access_test_helper,
432 __UNVOLATILE(buf));
433 pthread_join(thread, NULL);
434
435 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
436 "Unable to disable kcov");
437
438 common_tail(fd, buf);
439 }
440
441 static void *
442 thread_test_helper(void *ptr)
443 {
444 volatile int i;
445
446 /* It does not matter what operation is in action. */
447 for (i = 0; i < 1000; i++) {
448 if (getpid() == 0)
449 break;
450 }
451
452 return NULL;
453 }
454
455 ATF_TC_WITHOUT_HEAD(kcov_thread);
456 ATF_TC_BODY(kcov_thread, tc)
457 {
458 pthread_t thread;
459 kcov_int_t *buf;
460 int fd;
461 int mode;
462 volatile int i;
463
464 buf = common_head(&fd);
465
466 mode = KCOV_MODE_TRACE_PC;
467 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0,
468 "Unable to enable kcov ");
469
470 /* The thread does something, does not matter what exactly. */
471 pthread_create(&thread, NULL, thread_test_helper, __UNVOLATILE(buf));
472
473 KCOV_STORE(buf[0], 0);
474 for (i = 0; i < 10000; i++)
475 continue;
476 ATF_REQUIRE_EQ_MSG(KCOV_LOAD(buf[0]), 0,
477 "Records changed in blocked thread");
478
479 pthread_join(thread, NULL);
480
481 ATF_REQUIRE_EQ_MSG(ioctl(fd, KCOV_IOC_DISABLE), 0,
482 "Unable to disable kcov");
483
484 common_tail(fd, buf);
485 }
486
487 static void *
488 multiple_threads_helper(void *ptr __unused)
489 {
490 kcov_int_t *buf;
491 int fd;
492 int mode;
493
494 buf = common_head(&fd);
495 mode = KCOV_MODE_TRACE_PC;
496 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0,
497 "Unable to enable kcov ");
498
499 KCOV_STORE(buf[0], 0);
500
501 sleep(0);
502 ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
503
504 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
505 "Unable to disable kcov");
506
507 common_tail(fd, buf);
508
509 return NULL;
510 }
511
512 static void
513 kcov_multiple_threads(size_t N)
514 {
515 pthread_t thread[32];
516 size_t i;
517
518 ATF_REQUIRE(__arraycount(thread) >= N);
519
520 for (i = 0; i < N; i++)
521 pthread_create(&thread[i], NULL, multiple_threads_helper, NULL);
522
523 for (i = 0; i < N; i++)
524 pthread_join(thread[i], NULL);
525 }
526
527 #define KCOV_MULTIPLE_THREADS(n) \
528 ATF_TC_WITHOUT_HEAD(kcov_multiple_threads##n); \
529 ATF_TC_BODY(kcov_multiple_threads##n, tc) \
530 { \
531 \
532 kcov_multiple_threads(n); \
533 }
534
535 KCOV_MULTIPLE_THREADS(2)
536 KCOV_MULTIPLE_THREADS(4)
537 KCOV_MULTIPLE_THREADS(8)
538 KCOV_MULTIPLE_THREADS(16)
539 KCOV_MULTIPLE_THREADS(32)
540
541 ATF_TP_ADD_TCS(tp)
542 {
543
544 ATF_TP_ADD_TC(tp, kcov_dup2);
545 ATF_TP_ADD_TC(tp, kcov_multiopen);
546 ATF_TP_ADD_TC(tp, kcov_open_close_open);
547 ATF_TP_ADD_TC(tp, kcov_bufsize);
548 ATF_TP_ADD_TC(tp, kcov_mmap);
549 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
550 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
551 ATF_TP_ADD_TC(tp, kcov_enable);
552 ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
553 ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
554 ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
555 ATF_TP_ADD_TC(tp, kcov_basic_pc);
556 ATF_TP_ADD_TC(tp, kcov_basic_cmp);
557 ATF_TP_ADD_TC(tp, kcov_basic_dup2_pc);
558 ATF_TP_ADD_TC(tp, kcov_basic_dup2_cmp);
559 ATF_TP_ADD_TC(tp, kcov_multienable_on_the_same_thread);
560 ATF_TP_ADD_TC(tp, kcov_buffer_access_from_custom_thread);
561 ATF_TP_ADD_TC(tp, kcov_thread);
562 ATF_TP_ADD_TC(tp, kcov_multiple_threads2);
563 ATF_TP_ADD_TC(tp, kcov_multiple_threads4);
564 ATF_TP_ADD_TC(tp, kcov_multiple_threads8);
565 ATF_TP_ADD_TC(tp, kcov_multiple_threads16);
566 ATF_TP_ADD_TC(tp, kcov_multiple_threads32);
567 return atf_no_error();
568 }
569