BPF List
 help / color / mirror / Atom feed
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: Dave Marchevsky <davemarchevsky@fb.com>
Cc: bpf@vger.kernel.org, Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Kernel Team <kernel-team@fb.com>, Tejun Heo <tj@kernel.org>
Subject: Re: [PATCH v4 bpf-next 04/11] bpf: Add basic bpf_rb_{root,node} support
Date: Fri, 10 Feb 2023 15:18:17 +0100	[thread overview]
Message-ID: <20230210141817.idcbotzn4uof4yfu@apollo> (raw)
In-Reply-To: <20230209174144.3280955-5-davemarchevsky@fb.com>

On Thu, Feb 09, 2023 at 06:41:37PM CET, Dave Marchevsky wrote:
> This patch adds special BPF_RB_{ROOT,NODE} btf_field_types similar to
> BPF_LIST_{HEAD,NODE}, adds the necessary plumbing to detect the new
> types, and adds bpf_rb_root_free function for freeing bpf_rb_root in
> map_values.
>
> structs bpf_rb_root and bpf_rb_node are opaque types meant to
> obscure structs rb_root_cached rb_node, respectively.
>
> btf_struct_access will prevent BPF programs from touching these special
> fields automatically now that they're recognized.
>
> btf_check_and_fixup_fields now groups list_head and rb_root together as
> "graph root" fields and {list,rb}_node as "graph node", and does same
> ownership cycle checking as before. Note that this function does _not_
> prevent ownership type mixups (e.g. rb_root owning list_node) - that's
> handled by btf_parse_graph_root.
>
> After this patch, a bpf program can have a struct bpf_rb_root in a
> map_value, but not add anything to nor do anything useful with it.
>
> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
> ---
> [...]
> +#define GRAPH_ROOT_MASK (BPF_LIST_HEAD | BPF_RB_ROOT)
> +#define GRAPH_NODE_MASK (BPF_LIST_NODE | BPF_RB_NODE)
> +
>  int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec)
>  {
>  	int i;
>
> -	/* There are two owning types, kptr_ref and bpf_list_head. The former
> -	 * only supports storing kernel types, which can never store references
> -	 * to program allocated local types, atleast not yet. Hence we only need
> -	 * to ensure that bpf_list_head ownership does not form cycles.
> +	/* There are three types that signify ownership of some other type:
> +	 *  kptr_ref, bpf_list_head, bpf_rb_root.
> +	 * kptr_ref only supports storing kernel types, which can't store
> +	 * references to program allocated local types.
> +	 *
> +	 * Hence we only need to ensure that bpf_{list_head,rb_root} ownership
> +	 * does not form cycles.
>  	 */
> -	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & BPF_LIST_HEAD))
> +	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & GRAPH_ROOT_MASK))
>  		return 0;
>  	for (i = 0; i < rec->cnt; i++) {
>  		struct btf_struct_meta *meta;
>  		u32 btf_id;
>
> -		if (!(rec->fields[i].type & BPF_LIST_HEAD))
> +		if (!(rec->fields[i].type & GRAPH_ROOT_MASK))
>  			continue;
>  		btf_id = rec->fields[i].graph_root.value_btf_id;
>  		meta = btf_find_struct_meta(btf, btf_id);
> @@ -3762,39 +3803,47 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec)
>  			return -EFAULT;
>  		rec->fields[i].graph_root.value_rec = meta->record;
>
> -		if (!(rec->field_mask & BPF_LIST_NODE))
> +		/* We need to set value_rec for all root types, but no need
> +		 * to check ownership cycle for a type unless it's also a
> +		 * node type.
> +		 */
> +		if (!(rec->field_mask & GRAPH_NODE_MASK))
>  			continue;
>
>  		/* We need to ensure ownership acyclicity among all types. The
>  		 * proper way to do it would be to topologically sort all BTF
>  		 * IDs based on the ownership edges, since there can be multiple
> -		 * bpf_list_head in a type. Instead, we use the following
> -		 * reasoning:
> +		 * bpf_{list_head,rb_node} in a type. Instead, we use the
> +		 * following resaoning:
>  		 *
>  		 * - A type can only be owned by another type in user BTF if it
> -		 *   has a bpf_list_node.
> +		 *   has a bpf_{list,rb}_node. Let's call these node types.
>  		 * - A type can only _own_ another type in user BTF if it has a
> -		 *   bpf_list_head.
> +		 *   bpf_{list_head,rb_root}. Let's call these root types.
>  		 *
> -		 * We ensure that if a type has both bpf_list_head and
> -		 * bpf_list_node, its element types cannot be owning types.
> +		 * We ensure that if a type is both a root and node, its
> +		 * element types cannot be root types.
>  		 *
>  		 * To ensure acyclicity:
>  		 *
> -		 * When A only has bpf_list_head, ownership chain can be:
> +		 * When A is an root type but not a node, its ownership
> +		 * chain can be:
>  		 *	A -> B -> C
>  		 * Where:
> -		 * - B has both bpf_list_head and bpf_list_node.
> -		 * - C only has bpf_list_node.
> +		 * - A is an root, e.g. has bpf_rb_root.
> +		 * - B is both a root and node, e.g. has bpf_rb_node and
> +		 *   bpf_list_head.
> +		 * - C is only an root, e.g. has bpf_list_node
>  		 *
> -		 * When A has both bpf_list_head and bpf_list_node, some other
> -		 * type already owns it in the BTF domain, hence it can not own
> -		 * another owning type through any of the bpf_list_head edges.
> +		 * When A is both a root and node, some other type already
> +		 * owns it in the BTF domain, hence it can not own
> +		 * another root type through any of the ownership edges.
>  		 *	A -> B
>  		 * Where:
> -		 * - B only has bpf_list_node.
> +		 * - A is both an root and node.
> +		 * - B is only an node.
>  		 */
> -		if (meta->record->field_mask & BPF_LIST_HEAD)
> +		if (meta->record->field_mask & GRAPH_ROOT_MASK)
>  			return -ELOOP;

While you are at it, can you include BTF selftests (similar to what linked list
tests are doing in test_btf) to ensure all of this being correctly rejected for
rbtree and mixed rbtree + list cases?

  reply	other threads:[~2023-02-10 14:18 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-09 17:41 [PATCH v4 bpf-next 00/11] BPF rbtree next-gen datastructure Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 01/11] bpf: Migrate release_on_unlock logic to non-owning ref semantics Dave Marchevsky
2023-02-10 13:24   ` Kumar Kartikeya Dwivedi
2023-02-10 17:13     ` Alexei Starovoitov
2023-02-09 17:41 ` [PATCH v4 bpf-next 02/11] bpf: Improve bpf_reg_state space usage for non-owning ref lock Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 03/11] selftests/bpf: Update linked_list tests for non-owning ref semantics Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 04/11] bpf: Add basic bpf_rb_{root,node} support Dave Marchevsky
2023-02-10 14:18   ` Kumar Kartikeya Dwivedi [this message]
2023-02-09 17:41 ` [PATCH v4 bpf-next 05/11] bpf: Add bpf_rbtree_{add,remove,first} kfuncs Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 06/11] bpf: Add support for bpf_rb_root and bpf_rb_node in kfunc args Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 07/11] bpf: Add callback validation to kfunc verifier logic Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 08/11] bpf: Special verifier handling for bpf_rbtree_{remove, first} Dave Marchevsky
2023-02-10  3:11   ` Alexei Starovoitov
2023-02-10  8:22     ` Dave Marchevsky
2023-02-10 17:30       ` Alexei Starovoitov
2023-02-10 14:15     ` Kumar Kartikeya Dwivedi
2023-02-10 13:55   ` Kumar Kartikeya Dwivedi
2023-02-10 17:21     ` Alexei Starovoitov
2023-02-10 18:03       ` Kumar Kartikeya Dwivedi
2023-02-10 18:58         ` Alexei Starovoitov
2023-02-10 19:38           ` Kumar Kartikeya Dwivedi
2023-02-10 20:01             ` Alexei Starovoitov
2023-02-10 19:01     ` Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 09/11] bpf: Add bpf_rbtree_{add,remove,first} decls to bpf_experimental.h Dave Marchevsky
2023-02-09 17:41 ` [PATCH v4 bpf-next 10/11] selftests/bpf: Add rbtree selftests Dave Marchevsky
2023-02-10  2:52   ` Alexei Starovoitov
2023-02-09 17:41 ` [PATCH v4 bpf-next 11/11] bpf, documentation: Add graph documentation for non-owning refs Dave Marchevsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230210141817.idcbotzn4uof4yfu@apollo \
    --to=memxor@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davemarchevsky@fb.com \
    --cc=kernel-team@fb.com \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox