Sun Mar 10 22:34:14 2019 UTC ()
Introduce enhancements to the kcov(4) code

Add new tests verifying dup2(2) scenarios:
 - kcov_dup2
 - kcov_basic_dup2_pc
 - kcov_basic_dup2_cmp

The dup2(2) trick is used by syzkaller and assert that it works.
All new tests pass.

While there add minor non-functional cleanup changes.


(kamil)
diff -r1.5 -r1.6 src/sys/kern/subr_kcov.c
diff -r1.7 -r1.8 src/tests/modules/t_kcov.c

cvs diff -r1.5 -r1.6 src/sys/kern/subr_kcov.c (expand / switch to unified diff)

--- src/sys/kern/subr_kcov.c 2019/03/10 17:51:00 1.5
+++ src/sys/kern/subr_kcov.c 2019/03/10 22:34:14 1.6
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: subr_kcov.c,v 1.5 2019/03/10 17:51:00 kamil Exp $ */ 1/* $NetBSD: subr_kcov.c,v 1.6 2019/03/10 22:34:14 kamil Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 4 * Copyright (c) 2019 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Siddharth Muralee. 8 * by Siddharth Muralee.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -407,27 +407,27 @@ trace_cmp(uint64_t type, uint64_t arg1,  @@ -407,27 +407,27 @@ trace_cmp(uint64_t type, uint64_t arg1,
407 407
408 kd = lwp_getspecific(kcov_lwp_key); 408 kd = lwp_getspecific(kcov_lwp_key);
409 if (__predict_true(kd == NULL)) { 409 if (__predict_true(kd == NULL)) {
410 /* Not traced. */ 410 /* Not traced. */
411 return; 411 return;
412 } 412 }
413 413
414 if (!kd->enabled) { 414 if (!kd->enabled) {
415 /* Tracing not enabled */ 415 /* Tracing not enabled */
416 return; 416 return;
417 } 417 }
418 418
419 if (kd->mode != KCOV_MODE_TRACE_CMP) { 419 if (kd->mode != KCOV_MODE_TRACE_CMP) {
420 /* PC tracing mode not enabled */ 420 /* CMP tracing mode not enabled */
421 return; 421 return;
422 } 422 }
423 423
424 idx = KCOV_LOAD(kd->buf[0]); 424 idx = KCOV_LOAD(kd->buf[0]);
425 if ((idx * 4 + 4) <= kd->bufnent) { 425 if ((idx * 4 + 4) <= kd->bufnent) {
426 KCOV_STORE(kd->buf[idx * 4 + 1], type); 426 KCOV_STORE(kd->buf[idx * 4 + 1], type);
427 KCOV_STORE(kd->buf[idx * 4 + 2], arg1); 427 KCOV_STORE(kd->buf[idx * 4 + 2], arg1);
428 KCOV_STORE(kd->buf[idx * 4 + 3], arg2); 428 KCOV_STORE(kd->buf[idx * 4 + 3], arg2);
429 KCOV_STORE(kd->buf[idx * 4 + 4], pc); 429 KCOV_STORE(kd->buf[idx * 4 + 4], pc);
430 KCOV_STORE(kd->buf[0], idx + 1); 430 KCOV_STORE(kd->buf[0], idx + 1);
431 } 431 }
432} 432}
433 433

cvs diff -r1.7 -r1.8 src/tests/modules/t_kcov.c (expand / switch to unified diff)

--- src/tests/modules/t_kcov.c 2019/03/10 17:51:00 1.7
+++ src/tests/modules/t_kcov.c 2019/03/10 22:34:14 1.8
@@ -47,26 +47,54 @@ @@ -47,26 +47,54 @@
47 47
48static int 48static int
49open_kcov(void) 49open_kcov(void)
50{ 50{
51 int fd; 51 int fd;
52 52
53 fd = open("/dev/kcov", O_RDWR); 53 fd = open("/dev/kcov", O_RDWR);
54 if (fd == -1) 54 if (fd == -1)
55 atf_tc_skip("Failed to open /dev/kcov"); 55 atf_tc_skip("Failed to open /dev/kcov");
56 56
57 return fd; 57 return fd;
58} 58}
59 59
 60static int
 61pick_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
 73ATF_TC_WITHOUT_HEAD(kcov_dup2);
 74ATF_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
60ATF_TC_WITHOUT_HEAD(kcov_multiopen); 88ATF_TC_WITHOUT_HEAD(kcov_multiopen);
61ATF_TC_BODY(kcov_multiopen, tc) 89ATF_TC_BODY(kcov_multiopen, tc)
62{ 90{
63 int fd1, fd2; 91 int fd1, fd2;
64 fd1 = open_kcov(); 92 fd1 = open_kcov();
65 93
66 fd2 = open("/dev/kcov", O_RDWR); 94 fd2 = open("/dev/kcov", O_RDWR);
67 ATF_REQUIRE(fd2 != -1); 95 ATF_REQUIRE(fd2 != -1);
68 96
69 close(fd1); 97 close(fd1);
70 close(fd2); 98 close(fd2);
71} 99}
72 100
@@ -206,31 +234,27 @@ ATF_TC_BODY(kcov_enable, tc) @@ -206,31 +234,27 @@ ATF_TC_BODY(kcov_enable, tc)
206 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 234 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
207 235
208 /* We need to enable before disable */ 236 /* We need to enable before disable */
209 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1); 237 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
210 238
211 /* Check enabling works only with a valid trace method */ 239 /* Check enabling works only with a valid trace method */
212 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 240 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
213 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1); 241 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1);
214 242
215 /* Disable should only be called once */ 243 /* Disable should only be called once */
216 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 244 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
217 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1); 245 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
218 246
219 /* Re-enabling should also work */ 247 /* Re-enabling and changing mode should also work */
220 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 
221 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 
222 
223 /* Re-enablibling and changing mode should also work */ 
224 mode = KCOV_MODE_NONE; 248 mode = KCOV_MODE_NONE;
225 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 249 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
226 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 250 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
227 mode = KCOV_MODE_TRACE_PC; 251 mode = KCOV_MODE_TRACE_PC;
228 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 252 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
229 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 253 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
230 mode = KCOV_MODE_TRACE_CMP; 254 mode = KCOV_MODE_TRACE_CMP;
231 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 255 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
232 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 256 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
233 257
234 close(fd); 258 close(fd);
235} 259}
236 260
@@ -252,89 +276,120 @@ ATF_TC_WITHOUT_HEAD(kcov_enable_no_disab @@ -252,89 +276,120 @@ ATF_TC_WITHOUT_HEAD(kcov_enable_no_disab
252ATF_TC_BODY(kcov_enable_no_disable_no_close, tc) 276ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
253{ 277{
254 int fd; 278 int fd;
255 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 279 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
256 int mode; 280 int mode;
257 281
258 fd = open_kcov(); 282 fd = open_kcov();
259 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 283 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
260 mode = KCOV_MODE_NONE; 284 mode = KCOV_MODE_NONE;
261 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 285 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0);
262} 286}
263 287
264static void * 288static void *
265common_head(int *fdp) 289common_head_raw(bool fd_dup, int *fdp)
266{ 290{
267 void *data; 291 void *data;
268 int fd; 292 int fd, fd2;
269 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 293 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
270 294
271 fd = open_kcov(); 295 fd = open_kcov();
272 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
273 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0, 305 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0,
274 "Unable to set the kcov buffer size"); 306 "Unable to set the kcov buffer size");
275 307
276 data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 308 data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
277 ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer"); 309 ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
278 310
279 *fdp = fd; 311 *fdp = fd;
280 return data; 312 return data;
281} 313}
282 314
 315static void *
 316common_head(int *fdp)
 317{
 318
 319 return common_head_raw(false, fdp);
 320}
 321
283static void 322static void
284common_tail(int fd, kcov_int_t *data) 323common_tail(int fd, kcov_int_t *data)
285{ 324{
286 325
287 ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0, 326 ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0,
288 "Unable to unmap the kcov buffer"); 327 "Unable to unmap the kcov buffer");
289 328
290 close(fd); 329 close(fd);
291} 330}
292 331
293static void 332static void
294kcov_basic(int mode) 333kcov_basic(bool fd_dup, int mode)
295{ 334{
296 kcov_int_t *buf; 335 kcov_int_t *buf;
297 int fd; 336 int fd;
298 337
299 buf = common_head(&fd); 338 buf = common_head_raw(fd_dup, &fd);
300 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0, 339 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0,
301 "Unable to enable kcov "); 340 "Unable to enable kcov ");
302 341
303 KCOV_STORE(buf[0], 0); 342 KCOV_STORE(buf[0], 0);
304 343
305 sleep(0); /* XXX: Is it enough for all trace types? */ 344 sleep(0); /* XXX: Is it enough for all trace types? */
306 ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found"); 345 ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
307 346
308 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0, 347 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
309 "Unable to disable kcov"); 348 "Unable to disable kcov");
310 349
311 common_tail(fd, buf); 350 common_tail(fd, buf);
312} 351}
313 352
314ATF_TC_WITHOUT_HEAD(kcov_basic_pc); 353ATF_TC_WITHOUT_HEAD(kcov_basic_pc);
315ATF_TC_BODY(kcov_basic_pc, tc) 354ATF_TC_BODY(kcov_basic_pc, tc)
316{ 355{
317 356
318 kcov_basic(KCOV_MODE_TRACE_PC); 357 kcov_basic(false, KCOV_MODE_TRACE_PC);
319} 358}
320 359
321ATF_TC_WITHOUT_HEAD(kcov_basic_cmp); 360ATF_TC_WITHOUT_HEAD(kcov_basic_cmp);
322ATF_TC_BODY(kcov_basic_cmp, tc) 361ATF_TC_BODY(kcov_basic_cmp, tc)
323{ 362{
324 363
325 atf_tc_skip("XXX: GCC8 needed"); 364 atf_tc_skip("XXX: GCC8 needed");
326 365
327 kcov_basic(KCOV_MODE_TRACE_CMP); 366 kcov_basic(false, KCOV_MODE_TRACE_CMP);
 367}
 368
 369ATF_TC_WITHOUT_HEAD(kcov_basic_dup2_pc);
 370ATF_TC_BODY(kcov_basic_dup2_pc, tc)
 371{
 372
 373 kcov_basic(true, KCOV_MODE_TRACE_PC);
 374}
 375
 376ATF_TC_WITHOUT_HEAD(kcov_basic_dup2_cmp);
 377ATF_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);
328} 383}
329 384
330ATF_TC_WITHOUT_HEAD(kcov_multienable_on_the_same_thread); 385ATF_TC_WITHOUT_HEAD(kcov_multienable_on_the_same_thread);
331ATF_TC_BODY(kcov_multienable_on_the_same_thread, tc) 386ATF_TC_BODY(kcov_multienable_on_the_same_thread, tc)
332{ 387{
333 kcov_int_t *buf1, *buf2; 388 kcov_int_t *buf1, *buf2;
334 int fd1, fd2; 389 int fd1, fd2;
335 int mode; 390 int mode;
336 391
337 buf1 = common_head(&fd1); 392 buf1 = common_head(&fd1);
338 buf2 = common_head(&fd2); 393 buf2 = common_head(&fd2);
339 mode = KCOV_MODE_NONE; 394 mode = KCOV_MODE_NONE;
340 ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_ENABLE, &mode) == 0, 395 ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_ENABLE, &mode) == 0,
@@ -476,35 +531,38 @@ ATF_TC_BODY(kcov_multiple_threads##n, tc @@ -476,35 +531,38 @@ ATF_TC_BODY(kcov_multiple_threads##n, tc
476 \ 531 \
477 kcov_multiple_threads(n); \ 532 kcov_multiple_threads(n); \
478} 533}
479 534
480KCOV_MULTIPLE_THREADS(2) 535KCOV_MULTIPLE_THREADS(2)
481KCOV_MULTIPLE_THREADS(4) 536KCOV_MULTIPLE_THREADS(4)
482KCOV_MULTIPLE_THREADS(8) 537KCOV_MULTIPLE_THREADS(8)
483KCOV_MULTIPLE_THREADS(16) 538KCOV_MULTIPLE_THREADS(16)
484KCOV_MULTIPLE_THREADS(32) 539KCOV_MULTIPLE_THREADS(32)
485 540
486ATF_TP_ADD_TCS(tp) 541ATF_TP_ADD_TCS(tp)
487{ 542{
488 543
 544 ATF_TP_ADD_TC(tp, kcov_dup2);
489 ATF_TP_ADD_TC(tp, kcov_multiopen); 545 ATF_TP_ADD_TC(tp, kcov_multiopen);
490 ATF_TP_ADD_TC(tp, kcov_open_close_open); 546 ATF_TP_ADD_TC(tp, kcov_open_close_open);
491 ATF_TP_ADD_TC(tp, kcov_bufsize); 547 ATF_TP_ADD_TC(tp, kcov_bufsize);
492 ATF_TP_ADD_TC(tp, kcov_mmap); 548 ATF_TP_ADD_TC(tp, kcov_mmap);
493 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap); 549 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
494 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close); 550 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
495 ATF_TP_ADD_TC(tp, kcov_enable); 551 ATF_TP_ADD_TC(tp, kcov_enable);
496 ATF_TP_ADD_TC(tp, kcov_enable_no_disable); 552 ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
497 ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close); 553 ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
498 ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close); 554 ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
499 ATF_TP_ADD_TC(tp, kcov_basic_pc); 555 ATF_TP_ADD_TC(tp, kcov_basic_pc);
500 ATF_TP_ADD_TC(tp, kcov_basic_cmp); 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);
501 ATF_TP_ADD_TC(tp, kcov_multienable_on_the_same_thread); 559 ATF_TP_ADD_TC(tp, kcov_multienable_on_the_same_thread);
502 ATF_TP_ADD_TC(tp, kcov_buffer_access_from_custom_thread); 560 ATF_TP_ADD_TC(tp, kcov_buffer_access_from_custom_thread);
503 ATF_TP_ADD_TC(tp, kcov_thread); 561 ATF_TP_ADD_TC(tp, kcov_thread);
504 ATF_TP_ADD_TC(tp, kcov_multiple_threads2); 562 ATF_TP_ADD_TC(tp, kcov_multiple_threads2);
505 ATF_TP_ADD_TC(tp, kcov_multiple_threads4); 563 ATF_TP_ADD_TC(tp, kcov_multiple_threads4);
506 ATF_TP_ADD_TC(tp, kcov_multiple_threads8); 564 ATF_TP_ADD_TC(tp, kcov_multiple_threads8);
507 ATF_TP_ADD_TC(tp, kcov_multiple_threads16); 565 ATF_TP_ADD_TC(tp, kcov_multiple_threads16);
508 ATF_TP_ADD_TC(tp, kcov_multiple_threads32); 566 ATF_TP_ADD_TC(tp, kcov_multiple_threads32);
509 return atf_no_error(); 567 return atf_no_error();
510} 568}