Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: add a test for iter/task_vma for short-lived processes

When a task iterator traverses vma(s), it is possible task->mm might
become invalid in the middle of traversal and this may cause kernel
misbehave (e.g., crash)

This test case creates iterators repeatedly and forks short-lived
processes in the background to detect this bug. The test will last
for 3 seconds to get the chance to trigger the issue.

Signed-off-by: Kui-Feng Lee <kuifeng@meta.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221216221855.4122288-3-kuifeng@meta.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kui-Feng Lee and committed by
Alexei Starovoitov
b7793c8d 7ff94f27

+73
+73
tools/testing/selftests/bpf/prog_tests/bpf_iter.c
··· 1465 1465 bpf_iter_task_vma__destroy(skel); 1466 1466 } 1467 1467 1468 + static void test_task_vma_dead_task(void) 1469 + { 1470 + struct bpf_iter_task_vma *skel; 1471 + int wstatus, child_pid = -1; 1472 + time_t start_tm, cur_tm; 1473 + int err, iter_fd = -1; 1474 + int wait_sec = 3; 1475 + 1476 + skel = bpf_iter_task_vma__open(); 1477 + if (!ASSERT_OK_PTR(skel, "bpf_iter_task_vma__open")) 1478 + return; 1479 + 1480 + skel->bss->pid = getpid(); 1481 + 1482 + err = bpf_iter_task_vma__load(skel); 1483 + if (!ASSERT_OK(err, "bpf_iter_task_vma__load")) 1484 + goto out; 1485 + 1486 + skel->links.proc_maps = bpf_program__attach_iter( 1487 + skel->progs.proc_maps, NULL); 1488 + 1489 + if (!ASSERT_OK_PTR(skel->links.proc_maps, "bpf_program__attach_iter")) { 1490 + skel->links.proc_maps = NULL; 1491 + goto out; 1492 + } 1493 + 1494 + start_tm = time(NULL); 1495 + cur_tm = start_tm; 1496 + 1497 + child_pid = fork(); 1498 + if (child_pid == 0) { 1499 + /* Fork short-lived processes in the background. */ 1500 + while (cur_tm < start_tm + wait_sec) { 1501 + system("echo > /dev/null"); 1502 + cur_tm = time(NULL); 1503 + } 1504 + exit(0); 1505 + } 1506 + 1507 + if (!ASSERT_GE(child_pid, 0, "fork_child")) 1508 + goto out; 1509 + 1510 + while (cur_tm < start_tm + wait_sec) { 1511 + iter_fd = bpf_iter_create(bpf_link__fd(skel->links.proc_maps)); 1512 + if (!ASSERT_GE(iter_fd, 0, "create_iter")) 1513 + goto out; 1514 + 1515 + /* Drain all data from iter_fd. */ 1516 + while (cur_tm < start_tm + wait_sec) { 1517 + err = read_fd_into_buffer(iter_fd, task_vma_output, CMP_BUFFER_SIZE); 1518 + if (!ASSERT_GE(err, 0, "read_iter_fd")) 1519 + goto out; 1520 + 1521 + cur_tm = time(NULL); 1522 + 1523 + if (err == 0) 1524 + break; 1525 + } 1526 + 1527 + close(iter_fd); 1528 + iter_fd = -1; 1529 + } 1530 + 1531 + check_bpf_link_info(skel->progs.proc_maps); 1532 + 1533 + out: 1534 + waitpid(child_pid, &wstatus, 0); 1535 + close(iter_fd); 1536 + bpf_iter_task_vma__destroy(skel); 1537 + } 1538 + 1468 1539 void test_bpf_sockmap_map_iter_fd(void) 1469 1540 { 1470 1541 struct bpf_iter_sockmap *skel; ··· 1657 1586 test_task_file(); 1658 1587 if (test__start_subtest("task_vma")) 1659 1588 test_task_vma(); 1589 + if (test__start_subtest("task_vma_dead_task")) 1590 + test_task_vma_dead_task(); 1660 1591 if (test__start_subtest("task_btf")) 1661 1592 test_task_btf(); 1662 1593 if (test__start_subtest("tcp4"))