Re: [PATCH v2 bpf-next 07/13] bpf: Add support for bpf_rb_root and bpf_rb_node in kfunc args

Alexei Starovoitov
2022-12-29T04:00:40Z

On Sat, Dec 17, 2022 at 12:25:00AM -0800, Dave Marchevsky wrote:
>
> +static int
> +__process_kf_arg_ptr_to_graph_node(struct bpf_verifier_env *env,
> + struct bpf_reg_state *reg, u32 regno,
> + struct bpf_kfunc_call_arg_meta *meta,
> + enum btf_field_type head_field_type,
> + enum btf_field_type node_field_type,
> + struct btf_field **node_field)
> +{
> + const char *node_type_name;
> const struct btf_type *et, *t;
> struct btf_field *field;
> - u32 list_node_off;
> + u32 node_off;
>
> - if (meta->btf != btf_vmlinux ||
> - (meta->func_id != special_kfunc_list[KF_bpf_list_push_front] &&
> - meta->func_id != special_kfunc_list[KF_bpf_list_push_back])) {
> - verbose(env, "verifier internal error: bpf_list_node argument for unknown kfunc\n");
> + if (meta->btf != btf_vmlinux) {
> + verbose(env, "verifier internal error: unexpected btf mismatch in kfunc call\n");
> return -EFAULT;
> }
>
> + if (!check_kfunc_is_graph_node_api(env, node_field_type, meta->func_id))
> + return -EFAULT;
> +
> + node_type_name = btf_field_type_name(node_field_type);
> if (!tnum_is_const(reg->var_off)) {
> verbose(env,
> - "R%d doesn't have constant offset. bpf_list_node has to be at the constant offset\n",
> - regno);
> + "R%d doesn't have constant offset. %s has to be at the constant offset\n",
> + regno, node_type_name);
> return -EINVAL;
> }
>
> - list_node_off = reg->off + reg->var_off.value;
> - field = reg_find_field_offset(reg, list_node_off, BPF_LIST_NODE);
> - if (!field || field->offset != list_node_off) {
> - verbose(env, "bpf_list_node not found at offset=%u\n", list_node_off);
> + node_off = reg->off + reg->var_off.value;
> + field = reg_find_field_offset(reg, node_off, node_field_type);
> + if (!field || field->offset != node_off) {
> + verbose(env, "%s not found at offset=%u\n", node_type_name, node_off);
> return -EINVAL;
> }
>
> - field = meta->arg_list_head.field;
> + field = *node_field;
>
> et = btf_type_by_id(field->graph_root.btf, field->graph_root.value_btf_id);
> t = btf_type_by_id(reg->btf, reg->btf_id);
> if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, 0, field->graph_root.btf,
> field->graph_root.value_btf_id, true)) {
> - verbose(env, "operation on bpf_list_head expects arg#1 bpf_list_node at offset=%d "
> + verbose(env, "operation on %s expects arg#1 %s at offset=%d "
> "in struct %s, but arg is at offset=%d in struct %s\n",
> + btf_field_type_name(head_field_type),
> + btf_field_type_name(node_field_type),
> field->graph_root.node_offset,
> btf_name_by_offset(field->graph_root.btf, et->name_off),
> - list_node_off, btf_name_by_offset(reg->btf, t->name_off));
> + node_off, btf_name_by_offset(reg->btf, t->name_off));
> return -EINVAL;
> }
>
> - if (list_node_off != field->graph_root.node_offset) {
> - verbose(env, "arg#1 offset=%d, but expected bpf_list_node at offset=%d in struct %s\n",
> - list_node_off, field->graph_root.node_offset,
> + if (node_off != field->graph_root.node_offset) {
> + verbose(env, "arg#1 offset=%d, but expected %s at offset=%d in struct %s\n",
> + node_off, btf_field_type_name(node_field_type),
> + field->graph_root.node_offset,
> btf_name_by_offset(field->graph_root.btf, et->name_off));
> return -EINVAL;
> }
> @@ -8932,6 +9053,24 @@ static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env,
> return 0;
> }

and with suggestion in patch 2 the single __process_kf_arg_ptr_to_graph_node helper
called as:

> +static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env,
> + struct bpf_reg_state *reg, u32 regno,
> + struct bpf_kfunc_call_arg_meta *meta)
> +{
> + return __process_kf_arg_ptr_to_graph_node(env, reg, regno, meta,
> + BPF_LIST_HEAD, BPF_LIST_NODE,
> + &meta->arg_list_head.field);
> +}
> +
> +static int process_kf_arg_ptr_to_rbtree_node(struct bpf_verifier_env *env,
> + struct bpf_reg_state *reg, u32 regno,
> + struct bpf_kfunc_call_arg_meta *meta)
> +{
> + return __process_kf_arg_ptr_to_graph_node(env, reg, regno, meta,
> + BPF_RB_ROOT, BPF_RB_NODE,
> + &meta->arg_rbtree_root.field);
> +}

would convert the arg from owning to non-owning.