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

Merge branch 'enable-bpf-programs-to-declare-arrays-of-kptr-bpf_rb_root-and-bpf_list_head'

Kui-Feng Lee says:

====================
Enable BPF programs to declare arrays of kptr, bpf_rb_root, and bpf_list_head.

Some types, such as type kptr, bpf_rb_root, and bpf_list_head, are
treated in a special way. Previously, these types could not be the
type of a field in a struct type that is used as the type of a global
variable. They could not be the type of a field in a struct type that
is used as the type of a field in the value type of a map either. They
could not even be the type of array elements. This means that they can
only be the type of global variables or of direct fields in the value
type of a map.

The patch set aims to enable the use of these specific types in arrays
and struct fields, providing flexibility. It examines the types of
global variables or the value types of maps, such as arrays and struct
types, recursively to identify these special types and generate field
information for them.

For example,

...
struct task_struct __kptr *ptr[3];
...

it will create 3 instances of "struct btf_field" in the "btf_record" of
the data section.

[...,
btf_field(offset=0x100, type=BPF_KPTR_REF),
btf_field(offset=0x108, type=BPF_KPTR_REF),
btf_field(offset=0x110, type=BPF_KPTR_REF),
...
]

It creates a record of each of three elements. These three records are
almost identical except their offsets.

Another example is

...
struct A {
...
struct task_struct __kptr *task;
struct bpf_rb_root root;
...
}

struct A foo[2];

it will create 4 records.

[...,
btf_field(offset=0x7100, type=BPF_KPTR_REF),
btf_field(offset=0x7108, type=BPF_RB_ROOT:),
btf_field(offset=0x7200, type=BPF_KPTR_REF),
btf_field(offset=0x7208, type=BPF_RB_ROOT:),
...
]

Assuming that the size of an element/struct A is 0x100 and "foo"
starts at 0x7000, it includes two kptr records at 0x7100 and 0x7200,
and two rbtree root records at 0x7108 and 0x7208.

All these field information will be flatten, for struct types, and
repeated, for arrays.
---
Changes from v6:

- Return BPF_KPTR_REF from btf_get_field_type() only if var_type is a
struct type.

- Pass btf and type to btf_get_field_type().

Changes from v5:

- Ensure field->offset values of kptrs are advanced correctly from
one nested struct/or array to another.

Changes from v4:

- Return -E2BIG for i == MAX_RESOLVE_DEPTH.

Changes from v3:

- Refactor the common code of btf_find_struct_field() and
btf_find_datasec_var().

- Limit the number of levels looking into a struct types.

Changes from v2:

- Support fields in nested struct type.

- Remove nelems and duplicate field information with offset
adjustments for arrays.

Changes from v1:

- Move the check of element alignment out of btf_field_cmp() to
btf_record_find().

- Change the order of the previous patch 4 "bpf:
check_map_kptr_access() compute the offset from the reg state" as
the patch 7 now.

- Reject BPF_RB_NODE and BPF_LIST_NODE with nelems > 1.

- Rephrase the commit log of the patch "bpf: check_map_access() with
the knowledge of arrays" to clarify the alignment on elements.

v6: https://lore.kernel.org/all/20240520204018.884515-1-thinker.li@gmail.com/
v5: https://lore.kernel.org/all/20240510011312.1488046-1-thinker.li@gmail.com/
v4: https://lore.kernel.org/all/20240508063218.2806447-1-thinker.li@gmail.com/
v3: https://lore.kernel.org/all/20240501204729.484085-1-thinker.li@gmail.com/
v2: https://lore.kernel.org/all/20240412210814.603377-1-thinker.li@gmail.com/
v1: https://lore.kernel.org/bpf/20240410004150.2917641-1-thinker.li@gmail.com/

Kui-Feng Lee (9):
bpf: Remove unnecessary checks on the offset of btf_field.
bpf: Remove unnecessary call to btf_field_type_size().
bpf: refactor btf_find_struct_field() and btf_find_datasec_var().
bpf: create repeated fields for arrays.
bpf: look into the types of the fields of a struct type recursively.
bpf: limit the number of levels of a nested struct type.
selftests/bpf: Test kptr arrays and kptrs in nested struct fields.
selftests/bpf: Test global bpf_rb_root arrays and fields in nested
struct types.
selftests/bpf: Test global bpf_list_head arrays.

kernel/bpf/btf.c | 310 ++++++++++++------
kernel/bpf/verifier.c | 4 +-
.../selftests/bpf/prog_tests/cpumask.c | 5 +
.../selftests/bpf/prog_tests/linked_list.c | 12 +
.../testing/selftests/bpf/prog_tests/rbtree.c | 47 +++
.../selftests/bpf/progs/cpumask_success.c | 171 ++++++++++
.../testing/selftests/bpf/progs/linked_list.c | 42 +++
tools/testing/selftests/bpf/progs/rbtree.c | 77 +++++
8 files changed, 558 insertions(+), 110 deletions(-)
====================

Link: https://lore.kernel.org/r/20240523174202.461236-1-thinker.li@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+558 -110
+202 -108
kernel/bpf/btf.c
··· 3442 3442 goto end; \ 3443 3443 } 3444 3444 3445 - static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask, 3445 + static int btf_get_field_type(const struct btf *btf, const struct btf_type *var_type, 3446 + u32 field_mask, u32 *seen_mask, 3446 3447 int *align, int *sz) 3447 3448 { 3448 3449 int type = 0; 3450 + const char *name = __btf_name_by_offset(btf, var_type->name_off); 3449 3451 3450 3452 if (field_mask & BPF_SPIN_LOCK) { 3451 3453 if (!strcmp(name, "bpf_spin_lock")) { ··· 3483 3481 field_mask_test_name(BPF_REFCOUNT, "bpf_refcount"); 3484 3482 3485 3483 /* Only return BPF_KPTR when all other types with matchable names fail */ 3486 - if (field_mask & BPF_KPTR) { 3484 + if (field_mask & BPF_KPTR && !__btf_type_is_struct(var_type)) { 3487 3485 type = BPF_KPTR_REF; 3488 3486 goto end; 3489 3487 } ··· 3496 3494 3497 3495 #undef field_mask_test_name 3498 3496 3497 + /* Repeat a number of fields for a specified number of times. 3498 + * 3499 + * Copy the fields starting from the first field and repeat them for 3500 + * repeat_cnt times. The fields are repeated by adding the offset of each 3501 + * field with 3502 + * (i + 1) * elem_size 3503 + * where i is the repeat index and elem_size is the size of an element. 3504 + */ 3505 + static int btf_repeat_fields(struct btf_field_info *info, 3506 + u32 field_cnt, u32 repeat_cnt, u32 elem_size) 3507 + { 3508 + u32 i, j; 3509 + u32 cur; 3510 + 3511 + /* Ensure not repeating fields that should not be repeated. */ 3512 + for (i = 0; i < field_cnt; i++) { 3513 + switch (info[i].type) { 3514 + case BPF_KPTR_UNREF: 3515 + case BPF_KPTR_REF: 3516 + case BPF_KPTR_PERCPU: 3517 + case BPF_LIST_HEAD: 3518 + case BPF_RB_ROOT: 3519 + break; 3520 + default: 3521 + return -EINVAL; 3522 + } 3523 + } 3524 + 3525 + cur = field_cnt; 3526 + for (i = 0; i < repeat_cnt; i++) { 3527 + memcpy(&info[cur], &info[0], field_cnt * sizeof(info[0])); 3528 + for (j = 0; j < field_cnt; j++) 3529 + info[cur++].off += (i + 1) * elem_size; 3530 + } 3531 + 3532 + return 0; 3533 + } 3534 + 3499 3535 static int btf_find_struct_field(const struct btf *btf, 3500 3536 const struct btf_type *t, u32 field_mask, 3501 - struct btf_field_info *info, int info_cnt) 3537 + struct btf_field_info *info, int info_cnt, 3538 + u32 level); 3539 + 3540 + /* Find special fields in the struct type of a field. 3541 + * 3542 + * This function is used to find fields of special types that is not a 3543 + * global variable or a direct field of a struct type. It also handles the 3544 + * repetition if it is the element type of an array. 3545 + */ 3546 + static int btf_find_nested_struct(const struct btf *btf, const struct btf_type *t, 3547 + u32 off, u32 nelems, 3548 + u32 field_mask, struct btf_field_info *info, 3549 + int info_cnt, u32 level) 3502 3550 { 3503 - int ret, idx = 0, align, sz, field_type; 3504 - const struct btf_member *member; 3551 + int ret, err, i; 3552 + 3553 + level++; 3554 + if (level >= MAX_RESOLVE_DEPTH) 3555 + return -E2BIG; 3556 + 3557 + ret = btf_find_struct_field(btf, t, field_mask, info, info_cnt, level); 3558 + 3559 + if (ret <= 0) 3560 + return ret; 3561 + 3562 + /* Shift the offsets of the nested struct fields to the offsets 3563 + * related to the container. 3564 + */ 3565 + for (i = 0; i < ret; i++) 3566 + info[i].off += off; 3567 + 3568 + if (nelems > 1) { 3569 + err = btf_repeat_fields(info, ret, nelems - 1, t->size); 3570 + if (err == 0) 3571 + ret *= nelems; 3572 + else 3573 + ret = err; 3574 + } 3575 + 3576 + return ret; 3577 + } 3578 + 3579 + static int btf_find_field_one(const struct btf *btf, 3580 + const struct btf_type *var, 3581 + const struct btf_type *var_type, 3582 + int var_idx, 3583 + u32 off, u32 expected_size, 3584 + u32 field_mask, u32 *seen_mask, 3585 + struct btf_field_info *info, int info_cnt, 3586 + u32 level) 3587 + { 3588 + int ret, align, sz, field_type; 3505 3589 struct btf_field_info tmp; 3590 + const struct btf_array *array; 3591 + u32 i, nelems = 1; 3592 + 3593 + /* Walk into array types to find the element type and the number of 3594 + * elements in the (flattened) array. 3595 + */ 3596 + for (i = 0; i < MAX_RESOLVE_DEPTH && btf_type_is_array(var_type); i++) { 3597 + array = btf_array(var_type); 3598 + nelems *= array->nelems; 3599 + var_type = btf_type_by_id(btf, array->type); 3600 + } 3601 + if (i == MAX_RESOLVE_DEPTH) 3602 + return -E2BIG; 3603 + if (nelems == 0) 3604 + return 0; 3605 + 3606 + field_type = btf_get_field_type(btf, var_type, 3607 + field_mask, seen_mask, &align, &sz); 3608 + /* Look into variables of struct types */ 3609 + if (!field_type && __btf_type_is_struct(var_type)) { 3610 + sz = var_type->size; 3611 + if (expected_size && expected_size != sz * nelems) 3612 + return 0; 3613 + ret = btf_find_nested_struct(btf, var_type, off, nelems, field_mask, 3614 + &info[0], info_cnt, level); 3615 + return ret; 3616 + } 3617 + 3618 + if (field_type == 0) 3619 + return 0; 3620 + if (field_type < 0) 3621 + return field_type; 3622 + 3623 + if (expected_size && expected_size != sz * nelems) 3624 + return 0; 3625 + if (off % align) 3626 + return 0; 3627 + 3628 + switch (field_type) { 3629 + case BPF_SPIN_LOCK: 3630 + case BPF_TIMER: 3631 + case BPF_WORKQUEUE: 3632 + case BPF_LIST_NODE: 3633 + case BPF_RB_NODE: 3634 + case BPF_REFCOUNT: 3635 + ret = btf_find_struct(btf, var_type, off, sz, field_type, 3636 + info_cnt ? &info[0] : &tmp); 3637 + if (ret < 0) 3638 + return ret; 3639 + break; 3640 + case BPF_KPTR_UNREF: 3641 + case BPF_KPTR_REF: 3642 + case BPF_KPTR_PERCPU: 3643 + ret = btf_find_kptr(btf, var_type, off, sz, 3644 + info_cnt ? &info[0] : &tmp); 3645 + if (ret < 0) 3646 + return ret; 3647 + break; 3648 + case BPF_LIST_HEAD: 3649 + case BPF_RB_ROOT: 3650 + ret = btf_find_graph_root(btf, var, var_type, 3651 + var_idx, off, sz, 3652 + info_cnt ? &info[0] : &tmp, 3653 + field_type); 3654 + if (ret < 0) 3655 + return ret; 3656 + break; 3657 + default: 3658 + return -EFAULT; 3659 + } 3660 + 3661 + if (ret == BTF_FIELD_IGNORE) 3662 + return 0; 3663 + if (nelems > info_cnt) 3664 + return -E2BIG; 3665 + if (nelems > 1) { 3666 + ret = btf_repeat_fields(info, 1, nelems - 1, sz); 3667 + if (ret < 0) 3668 + return ret; 3669 + } 3670 + return nelems; 3671 + } 3672 + 3673 + static int btf_find_struct_field(const struct btf *btf, 3674 + const struct btf_type *t, u32 field_mask, 3675 + struct btf_field_info *info, int info_cnt, 3676 + u32 level) 3677 + { 3678 + int ret, idx = 0; 3679 + const struct btf_member *member; 3506 3680 u32 i, off, seen_mask = 0; 3507 3681 3508 3682 for_each_member(i, t, member) { 3509 3683 const struct btf_type *member_type = btf_type_by_id(btf, 3510 3684 member->type); 3511 3685 3512 - field_type = btf_get_field_type(__btf_name_by_offset(btf, member_type->name_off), 3513 - field_mask, &seen_mask, &align, &sz); 3514 - if (field_type == 0) 3515 - continue; 3516 - if (field_type < 0) 3517 - return field_type; 3518 - 3519 3686 off = __btf_member_bit_offset(t, member); 3520 3687 if (off % 8) 3521 3688 /* valid C code cannot generate such BTF */ 3522 3689 return -EINVAL; 3523 3690 off /= 8; 3524 - if (off % align) 3525 - continue; 3526 3691 3527 - switch (field_type) { 3528 - case BPF_SPIN_LOCK: 3529 - case BPF_TIMER: 3530 - case BPF_WORKQUEUE: 3531 - case BPF_LIST_NODE: 3532 - case BPF_RB_NODE: 3533 - case BPF_REFCOUNT: 3534 - ret = btf_find_struct(btf, member_type, off, sz, field_type, 3535 - idx < info_cnt ? &info[idx] : &tmp); 3536 - if (ret < 0) 3537 - return ret; 3538 - break; 3539 - case BPF_KPTR_UNREF: 3540 - case BPF_KPTR_REF: 3541 - case BPF_KPTR_PERCPU: 3542 - ret = btf_find_kptr(btf, member_type, off, sz, 3543 - idx < info_cnt ? &info[idx] : &tmp); 3544 - if (ret < 0) 3545 - return ret; 3546 - break; 3547 - case BPF_LIST_HEAD: 3548 - case BPF_RB_ROOT: 3549 - ret = btf_find_graph_root(btf, t, member_type, 3550 - i, off, sz, 3551 - idx < info_cnt ? &info[idx] : &tmp, 3552 - field_type); 3553 - if (ret < 0) 3554 - return ret; 3555 - break; 3556 - default: 3557 - return -EFAULT; 3558 - } 3559 - 3560 - if (ret == BTF_FIELD_IGNORE) 3561 - continue; 3562 - if (idx >= info_cnt) 3563 - return -E2BIG; 3564 - ++idx; 3692 + ret = btf_find_field_one(btf, t, member_type, i, 3693 + off, 0, 3694 + field_mask, &seen_mask, 3695 + &info[idx], info_cnt - idx, level); 3696 + if (ret < 0) 3697 + return ret; 3698 + idx += ret; 3565 3699 } 3566 3700 return idx; 3567 3701 } 3568 3702 3569 3703 static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t, 3570 3704 u32 field_mask, struct btf_field_info *info, 3571 - int info_cnt) 3705 + int info_cnt, u32 level) 3572 3706 { 3573 - int ret, idx = 0, align, sz, field_type; 3707 + int ret, idx = 0; 3574 3708 const struct btf_var_secinfo *vsi; 3575 - struct btf_field_info tmp; 3576 3709 u32 i, off, seen_mask = 0; 3577 3710 3578 3711 for_each_vsi(i, t, vsi) { 3579 3712 const struct btf_type *var = btf_type_by_id(btf, vsi->type); 3580 3713 const struct btf_type *var_type = btf_type_by_id(btf, var->type); 3581 3714 3582 - field_type = btf_get_field_type(__btf_name_by_offset(btf, var_type->name_off), 3583 - field_mask, &seen_mask, &align, &sz); 3584 - if (field_type == 0) 3585 - continue; 3586 - if (field_type < 0) 3587 - return field_type; 3588 - 3589 3715 off = vsi->offset; 3590 - if (vsi->size != sz) 3591 - continue; 3592 - if (off % align) 3593 - continue; 3594 - 3595 - switch (field_type) { 3596 - case BPF_SPIN_LOCK: 3597 - case BPF_TIMER: 3598 - case BPF_WORKQUEUE: 3599 - case BPF_LIST_NODE: 3600 - case BPF_RB_NODE: 3601 - case BPF_REFCOUNT: 3602 - ret = btf_find_struct(btf, var_type, off, sz, field_type, 3603 - idx < info_cnt ? &info[idx] : &tmp); 3604 - if (ret < 0) 3605 - return ret; 3606 - break; 3607 - case BPF_KPTR_UNREF: 3608 - case BPF_KPTR_REF: 3609 - case BPF_KPTR_PERCPU: 3610 - ret = btf_find_kptr(btf, var_type, off, sz, 3611 - idx < info_cnt ? &info[idx] : &tmp); 3612 - if (ret < 0) 3613 - return ret; 3614 - break; 3615 - case BPF_LIST_HEAD: 3616 - case BPF_RB_ROOT: 3617 - ret = btf_find_graph_root(btf, var, var_type, 3618 - -1, off, sz, 3619 - idx < info_cnt ? &info[idx] : &tmp, 3620 - field_type); 3621 - if (ret < 0) 3622 - return ret; 3623 - break; 3624 - default: 3625 - return -EFAULT; 3626 - } 3627 - 3628 - if (ret == BTF_FIELD_IGNORE) 3629 - continue; 3630 - if (idx >= info_cnt) 3631 - return -E2BIG; 3632 - ++idx; 3716 + ret = btf_find_field_one(btf, var, var_type, -1, off, vsi->size, 3717 + field_mask, &seen_mask, 3718 + &info[idx], info_cnt - idx, 3719 + level); 3720 + if (ret < 0) 3721 + return ret; 3722 + idx += ret; 3633 3723 } 3634 3724 return idx; 3635 3725 } ··· 3731 3637 int info_cnt) 3732 3638 { 3733 3639 if (__btf_type_is_struct(t)) 3734 - return btf_find_struct_field(btf, t, field_mask, info, info_cnt); 3640 + return btf_find_struct_field(btf, t, field_mask, info, info_cnt, 0); 3735 3641 else if (btf_type_is_datasec(t)) 3736 - return btf_find_datasec_var(btf, t, field_mask, info, info_cnt); 3642 + return btf_find_datasec_var(btf, t, field_mask, info, info_cnt, 0); 3737 3643 return -EINVAL; 3738 3644 } 3739 3645 ··· 6787 6693 for (i = 0; i < rec->cnt; i++) { 6788 6694 struct btf_field *field = &rec->fields[i]; 6789 6695 u32 offset = field->offset; 6790 - if (off < offset + btf_field_type_size(field->type) && offset < off + size) { 6696 + if (off < offset + field->size && offset < off + size) { 6791 6697 bpf_log(log, 6792 6698 "direct access to %s is disallowed\n", 6793 6699 btf_field_type_name(field->type));
+2 -2
kernel/bpf/verifier.c
··· 5448 5448 * this program. To check that [x1, x2) overlaps with [y1, y2), 5449 5449 * it is sufficient to check x1 < y2 && y1 < x2. 5450 5450 */ 5451 - if (reg->smin_value + off < p + btf_field_type_size(field->type) && 5451 + if (reg->smin_value + off < p + field->size && 5452 5452 p < reg->umax_value + off + size) { 5453 5453 switch (field->type) { 5454 5454 case BPF_KPTR_UNREF: ··· 11640 11640 11641 11641 node_off = reg->off + reg->var_off.value; 11642 11642 field = reg_find_field_offset(reg, node_off, node_field_type); 11643 - if (!field || field->offset != node_off) { 11643 + if (!field) { 11644 11644 verbose(env, "%s not found at offset=%u\n", node_type_name, node_off); 11645 11645 return -EINVAL; 11646 11646 }
+5
tools/testing/selftests/bpf/prog_tests/cpumask.c
··· 18 18 "test_insert_leave", 19 19 "test_insert_remove_release", 20 20 "test_global_mask_rcu", 21 + "test_global_mask_array_one_rcu", 22 + "test_global_mask_array_rcu", 23 + "test_global_mask_array_l2_rcu", 24 + "test_global_mask_nested_rcu", 25 + "test_global_mask_nested_deep_rcu", 21 26 "test_cpumask_weight", 22 27 }; 23 28
+12
tools/testing/selftests/bpf/prog_tests/linked_list.c
··· 183 183 if (!leave_in_map) 184 184 clear_fields(skel->maps.bss_A); 185 185 186 + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.global_list_push_pop_nested), &opts); 187 + ASSERT_OK(ret, "global_list_push_pop_nested"); 188 + ASSERT_OK(opts.retval, "global_list_push_pop_nested retval"); 189 + if (!leave_in_map) 190 + clear_fields(skel->maps.bss_A); 191 + 192 + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.global_list_array_push_pop), &opts); 193 + ASSERT_OK(ret, "global_list_array_push_pop"); 194 + ASSERT_OK(opts.retval, "global_list_array_push_pop retval"); 195 + if (!leave_in_map) 196 + clear_fields(skel->maps.bss_A); 197 + 186 198 if (mode == PUSH_POP) 187 199 goto end; 188 200
+47
tools/testing/selftests/bpf/prog_tests/rbtree.c
··· 31 31 rbtree__destroy(skel); 32 32 } 33 33 34 + static void test_rbtree_add_nodes_nested(void) 35 + { 36 + LIBBPF_OPTS(bpf_test_run_opts, opts, 37 + .data_in = &pkt_v4, 38 + .data_size_in = sizeof(pkt_v4), 39 + .repeat = 1, 40 + ); 41 + struct rbtree *skel; 42 + int ret; 43 + 44 + skel = rbtree__open_and_load(); 45 + if (!ASSERT_OK_PTR(skel, "rbtree__open_and_load")) 46 + return; 47 + 48 + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.rbtree_add_nodes_nested), &opts); 49 + ASSERT_OK(ret, "rbtree_add_nodes_nested run"); 50 + ASSERT_OK(opts.retval, "rbtree_add_nodes_nested retval"); 51 + ASSERT_EQ(skel->data->less_callback_ran, 1, "rbtree_add_nodes_nested less_callback_ran"); 52 + 53 + rbtree__destroy(skel); 54 + } 55 + 34 56 static void test_rbtree_add_and_remove(void) 35 57 { 36 58 LIBBPF_OPTS(bpf_test_run_opts, opts, ··· 71 49 ASSERT_OK(ret, "rbtree_add_and_remove"); 72 50 ASSERT_OK(opts.retval, "rbtree_add_and_remove retval"); 73 51 ASSERT_EQ(skel->data->removed_key, 5, "rbtree_add_and_remove first removed key"); 52 + 53 + rbtree__destroy(skel); 54 + } 55 + 56 + static void test_rbtree_add_and_remove_array(void) 57 + { 58 + LIBBPF_OPTS(bpf_test_run_opts, opts, 59 + .data_in = &pkt_v4, 60 + .data_size_in = sizeof(pkt_v4), 61 + .repeat = 1, 62 + ); 63 + struct rbtree *skel; 64 + int ret; 65 + 66 + skel = rbtree__open_and_load(); 67 + if (!ASSERT_OK_PTR(skel, "rbtree__open_and_load")) 68 + return; 69 + 70 + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.rbtree_add_and_remove_array), &opts); 71 + ASSERT_OK(ret, "rbtree_add_and_remove_array"); 72 + ASSERT_OK(opts.retval, "rbtree_add_and_remove_array retval"); 74 73 75 74 rbtree__destroy(skel); 76 75 } ··· 147 104 { 148 105 if (test__start_subtest("rbtree_add_nodes")) 149 106 test_rbtree_add_nodes(); 107 + if (test__start_subtest("rbtree_add_nodes_nested")) 108 + test_rbtree_add_nodes_nested(); 150 109 if (test__start_subtest("rbtree_add_and_remove")) 151 110 test_rbtree_add_and_remove(); 111 + if (test__start_subtest("rbtree_add_and_remove_array")) 112 + test_rbtree_add_and_remove_array(); 152 113 if (test__start_subtest("rbtree_first_and_remove")) 153 114 test_rbtree_first_and_remove(); 154 115 if (test__start_subtest("rbtree_api_release_aliasing"))
+171
tools/testing/selftests/bpf/progs/cpumask_success.c
··· 12 12 13 13 int pid, nr_cpus; 14 14 15 + struct kptr_nested { 16 + struct bpf_cpumask __kptr * mask; 17 + }; 18 + 19 + struct kptr_nested_pair { 20 + struct bpf_cpumask __kptr * mask_1; 21 + struct bpf_cpumask __kptr * mask_2; 22 + }; 23 + 24 + struct kptr_nested_mid { 25 + int dummy; 26 + struct kptr_nested m; 27 + }; 28 + 29 + struct kptr_nested_deep { 30 + struct kptr_nested_mid ptrs[2]; 31 + struct kptr_nested_pair ptr_pairs[3]; 32 + }; 33 + 34 + private(MASK) static struct bpf_cpumask __kptr * global_mask_array[2]; 35 + private(MASK) static struct bpf_cpumask __kptr * global_mask_array_l2[2][1]; 36 + private(MASK) static struct bpf_cpumask __kptr * global_mask_array_one[1]; 37 + private(MASK) static struct kptr_nested global_mask_nested[2]; 38 + private(MASK_DEEP) static struct kptr_nested_deep global_mask_nested_deep; 39 + 15 40 static bool is_test_task(void) 16 41 { 17 42 int cur_pid = bpf_get_current_pid_tgid() >> 32; ··· 482 457 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 483 458 bpf_rcu_read_unlock(); 484 459 460 + return 0; 461 + } 462 + 463 + SEC("tp_btf/task_newtask") 464 + int BPF_PROG(test_global_mask_array_one_rcu, struct task_struct *task, u64 clone_flags) 465 + { 466 + struct bpf_cpumask *local, *prev; 467 + 468 + if (!is_test_task()) 469 + return 0; 470 + 471 + /* Kptr arrays with one element are special cased, being treated 472 + * just like a single pointer. 473 + */ 474 + 475 + local = create_cpumask(); 476 + if (!local) 477 + return 0; 478 + 479 + prev = bpf_kptr_xchg(&global_mask_array_one[0], local); 480 + if (prev) { 481 + bpf_cpumask_release(prev); 482 + err = 3; 483 + return 0; 484 + } 485 + 486 + bpf_rcu_read_lock(); 487 + local = global_mask_array_one[0]; 488 + if (!local) { 489 + err = 4; 490 + bpf_rcu_read_unlock(); 491 + return 0; 492 + } 493 + 494 + bpf_rcu_read_unlock(); 495 + 496 + return 0; 497 + } 498 + 499 + static int _global_mask_array_rcu(struct bpf_cpumask **mask0, 500 + struct bpf_cpumask **mask1) 501 + { 502 + struct bpf_cpumask *local; 503 + 504 + if (!is_test_task()) 505 + return 0; 506 + 507 + /* Check if two kptrs in the array work and independently */ 508 + 509 + local = create_cpumask(); 510 + if (!local) 511 + return 0; 512 + 513 + bpf_rcu_read_lock(); 514 + 515 + local = bpf_kptr_xchg(mask0, local); 516 + if (local) { 517 + err = 1; 518 + goto err_exit; 519 + } 520 + 521 + /* [<mask 0>, NULL] */ 522 + if (!*mask0 || *mask1) { 523 + err = 2; 524 + goto err_exit; 525 + } 526 + 527 + local = create_cpumask(); 528 + if (!local) { 529 + err = 9; 530 + goto err_exit; 531 + } 532 + 533 + local = bpf_kptr_xchg(mask1, local); 534 + if (local) { 535 + err = 10; 536 + goto err_exit; 537 + } 538 + 539 + /* [<mask 0>, <mask 1>] */ 540 + if (!*mask0 || !*mask1 || *mask0 == *mask1) { 541 + err = 11; 542 + goto err_exit; 543 + } 544 + 545 + err_exit: 546 + if (local) 547 + bpf_cpumask_release(local); 548 + bpf_rcu_read_unlock(); 549 + return 0; 550 + } 551 + 552 + SEC("tp_btf/task_newtask") 553 + int BPF_PROG(test_global_mask_array_rcu, struct task_struct *task, u64 clone_flags) 554 + { 555 + return _global_mask_array_rcu(&global_mask_array[0], &global_mask_array[1]); 556 + } 557 + 558 + SEC("tp_btf/task_newtask") 559 + int BPF_PROG(test_global_mask_array_l2_rcu, struct task_struct *task, u64 clone_flags) 560 + { 561 + return _global_mask_array_rcu(&global_mask_array_l2[0][0], &global_mask_array_l2[1][0]); 562 + } 563 + 564 + SEC("tp_btf/task_newtask") 565 + int BPF_PROG(test_global_mask_nested_rcu, struct task_struct *task, u64 clone_flags) 566 + { 567 + return _global_mask_array_rcu(&global_mask_nested[0].mask, &global_mask_nested[1].mask); 568 + } 569 + 570 + /* Ensure that the field->offset has been correctly advanced from one 571 + * nested struct or array sub-tree to another. In the case of 572 + * kptr_nested_deep, it comprises two sub-trees: ktpr_1 and kptr_2. By 573 + * calling bpf_kptr_xchg() on every single kptr in both nested sub-trees, 574 + * the verifier should reject the program if the field->offset of any kptr 575 + * is incorrect. 576 + * 577 + * For instance, if we have 10 kptrs in a nested struct and a program that 578 + * accesses each kptr individually with bpf_kptr_xchg(), the compiler 579 + * should emit instructions to access 10 different offsets if it works 580 + * correctly. If the field->offset values of any pair of them are 581 + * incorrectly the same, the number of unique offsets in btf_record for 582 + * this nested struct should be less than 10. The verifier should fail to 583 + * discover some of the offsets emitted by the compiler. 584 + * 585 + * Even if the field->offset values of kptrs are not duplicated, the 586 + * verifier should fail to find a btf_field for the instruction accessing a 587 + * kptr if the corresponding field->offset is pointing to a random 588 + * incorrect offset. 589 + */ 590 + SEC("tp_btf/task_newtask") 591 + int BPF_PROG(test_global_mask_nested_deep_rcu, struct task_struct *task, u64 clone_flags) 592 + { 593 + int r, i; 594 + 595 + r = _global_mask_array_rcu(&global_mask_nested_deep.ptrs[0].m.mask, 596 + &global_mask_nested_deep.ptrs[1].m.mask); 597 + if (r) 598 + return r; 599 + 600 + for (i = 0; i < 3; i++) { 601 + r = _global_mask_array_rcu(&global_mask_nested_deep.ptr_pairs[i].mask_1, 602 + &global_mask_nested_deep.ptr_pairs[i].mask_2); 603 + if (r) 604 + return r; 605 + } 485 606 return 0; 486 607 } 487 608
+42
tools/testing/selftests/bpf/progs/linked_list.c
··· 11 11 12 12 #include "linked_list.h" 13 13 14 + struct head_nested_inner { 15 + struct bpf_spin_lock lock; 16 + struct bpf_list_head head __contains(foo, node2); 17 + }; 18 + 19 + struct head_nested { 20 + int dummy; 21 + struct head_nested_inner inner; 22 + }; 23 + 24 + private(C) struct bpf_spin_lock glock_c; 25 + private(C) struct bpf_list_head ghead_array[2] __contains(foo, node2); 26 + private(C) struct bpf_list_head ghead_array_one[1] __contains(foo, node2); 27 + 28 + private(D) struct head_nested ghead_nested; 29 + 14 30 static __always_inline 15 31 int list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map) 16 32 { ··· 323 307 int global_list_push_pop(void *ctx) 324 308 { 325 309 return test_list_push_pop(&glock, &ghead); 310 + } 311 + 312 + SEC("tc") 313 + int global_list_push_pop_nested(void *ctx) 314 + { 315 + return test_list_push_pop(&ghead_nested.inner.lock, &ghead_nested.inner.head); 316 + } 317 + 318 + SEC("tc") 319 + int global_list_array_push_pop(void *ctx) 320 + { 321 + int r; 322 + 323 + r = test_list_push_pop(&glock_c, &ghead_array[0]); 324 + if (r) 325 + return r; 326 + 327 + r = test_list_push_pop(&glock_c, &ghead_array[1]); 328 + if (r) 329 + return r; 330 + 331 + /* Arrays with only one element is a special case, being treated 332 + * just like a bpf_list_head variable by the verifier, not an 333 + * array. 334 + */ 335 + return test_list_push_pop(&glock_c, &ghead_array_one[0]); 326 336 } 327 337 328 338 SEC("tc")
+77
tools/testing/selftests/bpf/progs/rbtree.c
··· 13 13 struct bpf_rb_node node; 14 14 }; 15 15 16 + struct root_nested_inner { 17 + struct bpf_spin_lock glock; 18 + struct bpf_rb_root root __contains(node_data, node); 19 + }; 20 + 21 + struct root_nested { 22 + struct root_nested_inner inner; 23 + }; 24 + 16 25 long less_callback_ran = -1; 17 26 long removed_key = -1; 18 27 long first_data[2] = {-1, -1}; ··· 29 20 #define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8))) 30 21 private(A) struct bpf_spin_lock glock; 31 22 private(A) struct bpf_rb_root groot __contains(node_data, node); 23 + private(A) struct bpf_rb_root groot_array[2] __contains(node_data, node); 24 + private(A) struct bpf_rb_root groot_array_one[1] __contains(node_data, node); 25 + private(B) struct root_nested groot_nested; 32 26 33 27 static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) 34 28 { ··· 84 72 } 85 73 86 74 SEC("tc") 75 + long rbtree_add_nodes_nested(void *ctx) 76 + { 77 + return __add_three(&groot_nested.inner.root, &groot_nested.inner.glock); 78 + } 79 + 80 + SEC("tc") 87 81 long rbtree_add_and_remove(void *ctx) 88 82 { 89 83 struct bpf_rb_node *res = NULL; ··· 124 106 bpf_obj_drop(n); 125 107 if (m) 126 108 bpf_obj_drop(m); 109 + return 1; 110 + } 111 + 112 + SEC("tc") 113 + long rbtree_add_and_remove_array(void *ctx) 114 + { 115 + struct bpf_rb_node *res1 = NULL, *res2 = NULL, *res3 = NULL; 116 + struct node_data *nodes[3][2] = {{NULL, NULL}, {NULL, NULL}, {NULL, NULL}}; 117 + struct node_data *n; 118 + long k1 = -1, k2 = -1, k3 = -1; 119 + int i, j; 120 + 121 + for (i = 0; i < 3; i++) { 122 + for (j = 0; j < 2; j++) { 123 + nodes[i][j] = bpf_obj_new(typeof(*nodes[i][j])); 124 + if (!nodes[i][j]) 125 + goto err_out; 126 + nodes[i][j]->key = i * 2 + j; 127 + } 128 + } 129 + 130 + bpf_spin_lock(&glock); 131 + for (i = 0; i < 2; i++) 132 + for (j = 0; j < 2; j++) 133 + bpf_rbtree_add(&groot_array[i], &nodes[i][j]->node, less); 134 + for (j = 0; j < 2; j++) 135 + bpf_rbtree_add(&groot_array_one[0], &nodes[2][j]->node, less); 136 + res1 = bpf_rbtree_remove(&groot_array[0], &nodes[0][0]->node); 137 + res2 = bpf_rbtree_remove(&groot_array[1], &nodes[1][0]->node); 138 + res3 = bpf_rbtree_remove(&groot_array_one[0], &nodes[2][0]->node); 139 + bpf_spin_unlock(&glock); 140 + 141 + if (res1) { 142 + n = container_of(res1, struct node_data, node); 143 + k1 = n->key; 144 + bpf_obj_drop(n); 145 + } 146 + if (res2) { 147 + n = container_of(res2, struct node_data, node); 148 + k2 = n->key; 149 + bpf_obj_drop(n); 150 + } 151 + if (res3) { 152 + n = container_of(res3, struct node_data, node); 153 + k3 = n->key; 154 + bpf_obj_drop(n); 155 + } 156 + if (k1 != 0 || k2 != 2 || k3 != 4) 157 + return 2; 158 + 159 + return 0; 160 + 161 + err_out: 162 + for (i = 0; i < 3; i++) { 163 + for (j = 0; j < 2; j++) { 164 + if (nodes[i][j]) 165 + bpf_obj_drop(nodes[i][j]); 166 + } 167 + } 127 168 return 1; 128 169 } 129 170