Skip to content

Commit 49d9601

Browse files
committed
Alexei Starovoitov says: ==================== bpf 2023-01-04 We've added 5 non-merge commits during the last 8 day(s) which contain a total of 5 files changed, 112 insertions(+), 18 deletions(-). The main changes are: 1) Always use maximal size for copy_array in the verifier to fix KASAN tracking, from Kees. 2) Fix bpf task iterator walking through dead tasks, from Kui-Feng. 3) Make sure livepatch and bpf fexit can coexist, from Chuang. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: bpf: Always use maximal size for copy_array() selftests/bpf: add a test for iter/task_vma for short-lived processes bpf: keep a reference to the mm, in case the task is dead. selftests/bpf: Temporarily disable part of btf_dump:var_data test. bpf: Fix panic due to wrong pageattr of im->image ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 5580167 + 45435d8 commit 49d9601

File tree

5 files changed

+112
-18
lines changed

5 files changed

+112
-18
lines changed

kernel/bpf/task_iter.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ struct bpf_iter_seq_task_vma_info {
438438
*/
439439
struct bpf_iter_seq_task_common common;
440440
struct task_struct *task;
441+
struct mm_struct *mm;
441442
struct vm_area_struct *vma;
442443
u32 tid;
443444
unsigned long prev_vm_start;
@@ -456,16 +457,19 @@ task_vma_seq_get_next(struct bpf_iter_seq_task_vma_info *info)
456457
enum bpf_task_vma_iter_find_op op;
457458
struct vm_area_struct *curr_vma;
458459
struct task_struct *curr_task;
460+
struct mm_struct *curr_mm;
459461
u32 saved_tid = info->tid;
460462

461463
/* If this function returns a non-NULL vma, it holds a reference to
462-
* the task_struct, and holds read lock on vma->mm->mmap_lock.
464+
* the task_struct, holds a refcount on mm->mm_users, and holds
465+
* read lock on vma->mm->mmap_lock.
463466
* If this function returns NULL, it does not hold any reference or
464467
* lock.
465468
*/
466469
if (info->task) {
467470
curr_task = info->task;
468471
curr_vma = info->vma;
472+
curr_mm = info->mm;
469473
/* In case of lock contention, drop mmap_lock to unblock
470474
* the writer.
471475
*
@@ -504,13 +508,15 @@ task_vma_seq_get_next(struct bpf_iter_seq_task_vma_info *info)
504508
* 4.2) VMA2 and VMA2' covers different ranges, process
505509
* VMA2'.
506510
*/
507-
if (mmap_lock_is_contended(curr_task->mm)) {
511+
if (mmap_lock_is_contended(curr_mm)) {
508512
info->prev_vm_start = curr_vma->vm_start;
509513
info->prev_vm_end = curr_vma->vm_end;
510514
op = task_vma_iter_find_vma;
511-
mmap_read_unlock(curr_task->mm);
512-
if (mmap_read_lock_killable(curr_task->mm))
515+
mmap_read_unlock(curr_mm);
516+
if (mmap_read_lock_killable(curr_mm)) {
517+
mmput(curr_mm);
513518
goto finish;
519+
}
514520
} else {
515521
op = task_vma_iter_next_vma;
516522
}
@@ -535,42 +541,47 @@ task_vma_seq_get_next(struct bpf_iter_seq_task_vma_info *info)
535541
op = task_vma_iter_find_vma;
536542
}
537543

538-
if (!curr_task->mm)
544+
curr_mm = get_task_mm(curr_task);
545+
if (!curr_mm)
539546
goto next_task;
540547

541-
if (mmap_read_lock_killable(curr_task->mm))
548+
if (mmap_read_lock_killable(curr_mm)) {
549+
mmput(curr_mm);
542550
goto finish;
551+
}
543552
}
544553

545554
switch (op) {
546555
case task_vma_iter_first_vma:
547-
curr_vma = find_vma(curr_task->mm, 0);
556+
curr_vma = find_vma(curr_mm, 0);
548557
break;
549558
case task_vma_iter_next_vma:
550-
curr_vma = find_vma(curr_task->mm, curr_vma->vm_end);
559+
curr_vma = find_vma(curr_mm, curr_vma->vm_end);
551560
break;
552561
case task_vma_iter_find_vma:
553562
/* We dropped mmap_lock so it is necessary to use find_vma
554563
* to find the next vma. This is similar to the mechanism
555564
* in show_smaps_rollup().
556565
*/
557-
curr_vma = find_vma(curr_task->mm, info->prev_vm_end - 1);
566+
curr_vma = find_vma(curr_mm, info->prev_vm_end - 1);
558567
/* case 1) and 4.2) above just use curr_vma */
559568

560569
/* check for case 2) or case 4.1) above */
561570
if (curr_vma &&
562571
curr_vma->vm_start == info->prev_vm_start &&
563572
curr_vma->vm_end == info->prev_vm_end)
564-
curr_vma = find_vma(curr_task->mm, curr_vma->vm_end);
573+
curr_vma = find_vma(curr_mm, curr_vma->vm_end);
565574
break;
566575
}
567576
if (!curr_vma) {
568577
/* case 3) above, or case 2) 4.1) with vma->next == NULL */
569-
mmap_read_unlock(curr_task->mm);
578+
mmap_read_unlock(curr_mm);
579+
mmput(curr_mm);
570580
goto next_task;
571581
}
572582
info->task = curr_task;
573583
info->vma = curr_vma;
584+
info->mm = curr_mm;
574585
return curr_vma;
575586

576587
next_task:
@@ -579,6 +590,7 @@ task_vma_seq_get_next(struct bpf_iter_seq_task_vma_info *info)
579590

580591
put_task_struct(curr_task);
581592
info->task = NULL;
593+
info->mm = NULL;
582594
info->tid++;
583595
goto again;
584596

@@ -587,6 +599,7 @@ task_vma_seq_get_next(struct bpf_iter_seq_task_vma_info *info)
587599
put_task_struct(curr_task);
588600
info->task = NULL;
589601
info->vma = NULL;
602+
info->mm = NULL;
590603
return NULL;
591604
}
592605

@@ -658,7 +671,9 @@ static void task_vma_seq_stop(struct seq_file *seq, void *v)
658671
*/
659672
info->prev_vm_start = ~0UL;
660673
info->prev_vm_end = info->vma->vm_end;
661-
mmap_read_unlock(info->task->mm);
674+
mmap_read_unlock(info->mm);
675+
mmput(info->mm);
676+
info->mm = NULL;
662677
put_task_struct(info->task);
663678
info->task = NULL;
664679
}

kernel/bpf/trampoline.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,10 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
488488
/* reset fops->func and fops->trampoline for re-register */
489489
tr->fops->func = NULL;
490490
tr->fops->trampoline = 0;
491+
492+
/* reset im->image memory attr for arch_prepare_bpf_trampoline */
493+
set_memory_nx((long)im->image, 1);
494+
set_memory_rw((long)im->image, 1);
491495
goto again;
492496
}
493497
#endif

kernel/bpf/verifier.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,8 @@ static void print_insn_state(struct bpf_verifier_env *env,
10541054
*/
10551055
static void *copy_array(void *dst, const void *src, size_t n, size_t size, gfp_t flags)
10561056
{
1057+
size_t alloc_bytes;
1058+
void *orig = dst;
10571059
size_t bytes;
10581060

10591061
if (ZERO_OR_NULL_PTR(src))
@@ -1062,11 +1064,11 @@ static void *copy_array(void *dst, const void *src, size_t n, size_t size, gfp_t
10621064
if (unlikely(check_mul_overflow(n, size, &bytes)))
10631065
return NULL;
10641066

1065-
if (ksize(dst) < ksize(src)) {
1066-
kfree(dst);
1067-
dst = kmalloc_track_caller(kmalloc_size_roundup(bytes), flags);
1068-
if (!dst)
1069-
return NULL;
1067+
alloc_bytes = max(ksize(orig), kmalloc_size_roundup(bytes));
1068+
dst = krealloc(orig, alloc_bytes, flags);
1069+
if (!dst) {
1070+
kfree(orig);
1071+
return NULL;
10701072
}
10711073

10721074
memcpy(dst, src, bytes);

tools/testing/selftests/bpf/prog_tests/bpf_iter.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,77 @@ static void test_task_vma_common(struct bpf_iter_attach_opts *opts)
14651465
bpf_iter_task_vma__destroy(skel);
14661466
}
14671467

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+
14681539
void test_bpf_sockmap_map_iter_fd(void)
14691540
{
14701541
struct bpf_iter_sockmap *skel;
@@ -1586,6 +1657,8 @@ void test_bpf_iter(void)
15861657
test_task_file();
15871658
if (test__start_subtest("task_vma"))
15881659
test_task_vma();
1660+
if (test__start_subtest("task_vma_dead_task"))
1661+
test_task_vma_dead_task();
15891662
if (test__start_subtest("task_btf"))
15901663
test_task_btf();
15911664
if (test__start_subtest("tcp4"))

tools/testing/selftests/bpf/prog_tests/btf_dump.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
801801
static void test_btf_dump_var_data(struct btf *btf, struct btf_dump *d,
802802
char *str)
803803
{
804-
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
804+
#if 0
805805
TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_number", int, BTF_F_COMPACT,
806806
"int cpu_number = (int)100", 100);
807807
#endif

0 commit comments

Comments
 (0)