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

bpf: Migrate bpf_rbtree_add and bpf_list_push_{front,back} to possibly fail

Consider this code snippet:

struct node {
long key;
bpf_list_node l;
bpf_rb_node r;
bpf_refcount ref;
}

int some_bpf_prog(void *ctx)
{
struct node *n = bpf_obj_new(/*...*/), *m;

bpf_spin_lock(&glock);

bpf_rbtree_add(&some_tree, &n->r, /* ... */);
m = bpf_refcount_acquire(n);
bpf_rbtree_add(&other_tree, &m->r, /* ... */);

bpf_spin_unlock(&glock);

/* ... */
}

After bpf_refcount_acquire, n and m point to the same underlying memory,
and that node's bpf_rb_node field is being used by the some_tree insert,
so overwriting it as a result of the second insert is an error. In order
to properly support refcounted nodes, the rbtree and list insert
functions must be allowed to fail. This patch adds such support.

The kfuncs bpf_rbtree_add, bpf_list_push_{front,back} are modified to
return an int indicating success/failure, with 0 -> success, nonzero ->
failure.

bpf_obj_drop on failure
=======================

Currently the only reason an insert can fail is the example above: the
bpf_{list,rb}_node is already in use. When such a failure occurs, the
insert kfuncs will bpf_obj_drop the input node. This allows the insert
operations to logically fail without changing their verifier owning ref
behavior, namely the unconditional release_reference of the input
owning ref.

With insert that always succeeds, ownership of the node is always passed
to the collection, since the node always ends up in the collection.

With a possibly-failed insert w/ bpf_obj_drop, ownership of the node
is always passed either to the collection (success), or to bpf_obj_drop
(failure). Regardless, it's correct to continue unconditionally
releasing the input owning ref, as something is always taking ownership
from the calling program on insert.

Keeping owning ref behavior unchanged results in a nice default UX for
insert functions that can fail. If the program's reaction to a failed
insert is "fine, just get rid of this owning ref for me and let me go
on with my business", then there's no reason to check for failure since
that's default behavior. e.g.:

long important_failures = 0;

int some_bpf_prog(void *ctx)
{
struct node *n, *m, *o; /* all bpf_obj_new'd */

bpf_spin_lock(&glock);
bpf_rbtree_add(&some_tree, &n->node, /* ... */);
bpf_rbtree_add(&some_tree, &m->node, /* ... */);
if (bpf_rbtree_add(&some_tree, &o->node, /* ... */)) {
important_failures++;
}
bpf_spin_unlock(&glock);
}

If we instead chose to pass ownership back to the program on failed
insert - by returning NULL on success or an owning ref on failure -
programs would always have to do something with the returned ref on
failure. The most likely action is probably "I'll just get rid of this
owning ref and go about my business", which ideally would look like:

if (n = bpf_rbtree_add(&some_tree, &n->node, /* ... */))
bpf_obj_drop(n);

But bpf_obj_drop isn't allowed in a critical section and inserts must
occur within one, so in reality error handling would become a
hard-to-parse mess.

For refcounted nodes, we can replicate the "pass ownership back to
program on failure" logic with this patch's semantics, albeit in an ugly
way:

struct node *n = bpf_obj_new(/* ... */), *m;

bpf_spin_lock(&glock);

m = bpf_refcount_acquire(n);
if (bpf_rbtree_add(&some_tree, &n->node, /* ... */)) {
/* Do something with m */
}

bpf_spin_unlock(&glock);
bpf_obj_drop(m);

bpf_refcount_acquire is used to simulate "return owning ref on failure".
This should be an uncommon occurrence, though.

Addition of two verifier-fixup'd args to collection inserts
===========================================================

The actual bpf_obj_drop kfunc is
bpf_obj_drop_impl(void *, struct btf_struct_meta *), with bpf_obj_drop
macro populating the second arg with 0 and the verifier later filling in
the arg during insn fixup.

Because bpf_rbtree_add and bpf_list_push_{front,back} now might do
bpf_obj_drop, these kfuncs need a btf_struct_meta parameter that can be
passed to bpf_obj_drop_impl.

Similarly, because the 'node' param to those insert functions is the
bpf_{list,rb}_node within the node type, and bpf_obj_drop expects a
pointer to the beginning of the node, the insert functions need to be
able to find the beginning of the node struct. A second
verifier-populated param is necessary: the offset of {list,rb}_node within the
node type.

These two new params allow the insert kfuncs to correctly call
__bpf_obj_drop_impl:

beginning_of_node = bpf_rb_node_ptr - offset
if (already_inserted)
__bpf_obj_drop_impl(beginning_of_node, btf_struct_meta->record);

Similarly to other kfuncs with "hidden" verifier-populated params, the
insert functions are renamed with _impl prefix and a macro is provided
for common usage. For example, bpf_rbtree_add kfunc is now
bpf_rbtree_add_impl and bpf_rbtree_add is now a macro which sets
"hidden" args to 0.

Due to the two new args BPF progs will need to be recompiled to work
with the new _impl kfuncs.

This patch also rewrites the "hidden argument" explanation to more
directly say why the BPF program writer doesn't need to populate the
arguments with anything meaningful.

How does this new logic affect non-owning references?
=====================================================

Currently, non-owning refs are valid until the end of the critical
section in which they're created. We can make this guarantee because, if
a non-owning ref exists, the referent was added to some collection. The
collection will drop() its nodes when it goes away, but it can't go away
while our program is accessing it, so that's not a problem. If the
referent is removed from the collection in the same CS that it was added
in, it can't be bpf_obj_drop'd until after CS end. Those are the only
two ways to free the referent's memory and neither can happen until
after the non-owning ref's lifetime ends.

On first glance, having these collection insert functions potentially
bpf_obj_drop their input seems like it breaks the "can't be
bpf_obj_drop'd until after CS end" line of reasoning. But we care about
the memory not being _freed_ until end of CS end, and a previous patch
in the series modified bpf_obj_drop such that it doesn't free refcounted
nodes until refcount == 0. So the statement can be more accurately
rewritten as "can't be free'd until after CS end".

We can prove that this rewritten statement holds for any non-owning
reference produced by collection insert functions:

* If the input to the insert function is _not_ refcounted
* We have an owning reference to the input, and can conclude it isn't
in any collection
* Inserting a node in a collection turns owning refs into
non-owning, and since our input type isn't refcounted, there's no
way to obtain additional owning refs to the same underlying
memory
* Because our node isn't in any collection, the insert operation
cannot fail, so bpf_obj_drop will not execute
* If bpf_obj_drop is guaranteed not to execute, there's no risk of
memory being free'd

* Otherwise, the input to the insert function is refcounted
* If the insert operation fails due to the node's list_head or rb_root
already being in some collection, there was some previous successful
insert which passed refcount to the collection
* We have an owning reference to the input, it must have been
acquired via bpf_refcount_acquire, which bumped the refcount
* refcount must be >= 2 since there's a valid owning reference and the
node is already in a collection
* Insert triggering bpf_obj_drop will decr refcount to >= 1, never
resulting in a free

So although we may do bpf_obj_drop during the critical section, this
will never result in memory being free'd, and no changes to non-owning
ref logic are needed in this patch.

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Link: https://lore.kernel.org/r/20230415201811.343116-6-davemarchevsky@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Dave Marchevsky and committed by
Alexei Starovoitov
d2dcc67d 7c50b1cb

+148 -51
+6 -1
include/linux/bpf_verifier.h
··· 464 464 */ 465 465 struct bpf_loop_inline_state loop_inline_state; 466 466 }; 467 - u64 obj_new_size; /* remember the size of type passed to bpf_obj_new to rewrite R1 */ 467 + union { 468 + /* remember the size of type passed to bpf_obj_new to rewrite R1 */ 469 + u64 obj_new_size; 470 + /* remember the offset of node field within type to rewrite */ 471 + u64 insert_off; 472 + }; 468 473 struct btf_struct_meta *kptr_struct_meta; 469 474 u64 map_key_state; /* constant (32 bit) key tracking for maps */ 470 475 int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
+48 -17
kernel/bpf/helpers.c
··· 1931 1931 return (void *)p__refcounted_kptr; 1932 1932 } 1933 1933 1934 - static void __bpf_list_add(struct bpf_list_node *node, struct bpf_list_head *head, bool tail) 1934 + static int __bpf_list_add(struct bpf_list_node *node, struct bpf_list_head *head, 1935 + bool tail, struct btf_record *rec, u64 off) 1935 1936 { 1936 1937 struct list_head *n = (void *)node, *h = (void *)head; 1937 1938 ··· 1940 1939 INIT_LIST_HEAD(h); 1941 1940 if (unlikely(!n->next)) 1942 1941 INIT_LIST_HEAD(n); 1942 + if (!list_empty(n)) { 1943 + /* Only called from BPF prog, no need to migrate_disable */ 1944 + __bpf_obj_drop_impl(n - off, rec); 1945 + return -EINVAL; 1946 + } 1947 + 1943 1948 tail ? list_add_tail(n, h) : list_add(n, h); 1949 + 1950 + return 0; 1944 1951 } 1945 1952 1946 - __bpf_kfunc void bpf_list_push_front(struct bpf_list_head *head, struct bpf_list_node *node) 1953 + __bpf_kfunc int bpf_list_push_front_impl(struct bpf_list_head *head, 1954 + struct bpf_list_node *node, 1955 + void *meta__ign, u64 off) 1947 1956 { 1948 - return __bpf_list_add(node, head, false); 1957 + struct btf_struct_meta *meta = meta__ign; 1958 + 1959 + return __bpf_list_add(node, head, false, 1960 + meta ? meta->record : NULL, off); 1949 1961 } 1950 1962 1951 - __bpf_kfunc void bpf_list_push_back(struct bpf_list_head *head, struct bpf_list_node *node) 1963 + __bpf_kfunc int bpf_list_push_back_impl(struct bpf_list_head *head, 1964 + struct bpf_list_node *node, 1965 + void *meta__ign, u64 off) 1952 1966 { 1953 - return __bpf_list_add(node, head, true); 1967 + struct btf_struct_meta *meta = meta__ign; 1968 + 1969 + return __bpf_list_add(node, head, true, 1970 + meta ? meta->record : NULL, off); 1954 1971 } 1955 1972 1956 1973 static struct bpf_list_node *__bpf_list_del(struct bpf_list_head *head, bool tail) ··· 2008 1989 /* Need to copy rbtree_add_cached's logic here because our 'less' is a BPF 2009 1990 * program 2010 1991 */ 2011 - static void __bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node, 2012 - void *less) 1992 + static int __bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node, 1993 + void *less, struct btf_record *rec, u64 off) 2013 1994 { 2014 1995 struct rb_node **link = &((struct rb_root_cached *)root)->rb_root.rb_node; 1996 + struct rb_node *parent = NULL, *n = (struct rb_node *)node; 2015 1997 bpf_callback_t cb = (bpf_callback_t)less; 2016 - struct rb_node *parent = NULL; 2017 1998 bool leftmost = true; 1999 + 2000 + if (!n->__rb_parent_color) 2001 + RB_CLEAR_NODE(n); 2002 + 2003 + if (!RB_EMPTY_NODE(n)) { 2004 + /* Only called from BPF prog, no need to migrate_disable */ 2005 + __bpf_obj_drop_impl(n - off, rec); 2006 + return -EINVAL; 2007 + } 2018 2008 2019 2009 while (*link) { 2020 2010 parent = *link; ··· 2035 2007 } 2036 2008 } 2037 2009 2038 - rb_link_node((struct rb_node *)node, parent, link); 2039 - rb_insert_color_cached((struct rb_node *)node, 2040 - (struct rb_root_cached *)root, leftmost); 2010 + rb_link_node(n, parent, link); 2011 + rb_insert_color_cached(n, (struct rb_root_cached *)root, leftmost); 2012 + return 0; 2041 2013 } 2042 2014 2043 - __bpf_kfunc void bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node, 2044 - bool (less)(struct bpf_rb_node *a, const struct bpf_rb_node *b)) 2015 + __bpf_kfunc int bpf_rbtree_add_impl(struct bpf_rb_root *root, struct bpf_rb_node *node, 2016 + bool (less)(struct bpf_rb_node *a, const struct bpf_rb_node *b), 2017 + void *meta__ign, u64 off) 2045 2018 { 2046 - __bpf_rbtree_add(root, node, (void *)less); 2019 + struct btf_struct_meta *meta = meta__ign; 2020 + 2021 + return __bpf_rbtree_add(root, node, (void *)less, meta ? meta->record : NULL, off); 2047 2022 } 2048 2023 2049 2024 __bpf_kfunc struct bpf_rb_node *bpf_rbtree_first(struct bpf_rb_root *root) ··· 2322 2291 BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) 2323 2292 BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) 2324 2293 BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE) 2325 - BTF_ID_FLAGS(func, bpf_list_push_front) 2326 - BTF_ID_FLAGS(func, bpf_list_push_back) 2294 + BTF_ID_FLAGS(func, bpf_list_push_front_impl) 2295 + BTF_ID_FLAGS(func, bpf_list_push_back_impl) 2327 2296 BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) 2328 2297 BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL) 2329 2298 BTF_ID_FLAGS(func, bpf_task_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) 2330 2299 BTF_ID_FLAGS(func, bpf_task_release, KF_RELEASE) 2331 2300 BTF_ID_FLAGS(func, bpf_rbtree_remove, KF_ACQUIRE) 2332 - BTF_ID_FLAGS(func, bpf_rbtree_add) 2301 + BTF_ID_FLAGS(func, bpf_rbtree_add_impl) 2333 2302 BTF_ID_FLAGS(func, bpf_rbtree_first, KF_RET_NULL) 2334 2303 2335 2304 #ifdef CONFIG_CGROUPS
+55 -23
kernel/bpf/verifier.c
··· 8500 8500 struct bpf_func_state *callee, 8501 8501 int insn_idx) 8502 8502 { 8503 - /* void bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node, 8503 + /* void bpf_rbtree_add_impl(struct bpf_rb_root *root, struct bpf_rb_node *node, 8504 8504 * bool (less)(struct bpf_rb_node *a, const struct bpf_rb_node *b)); 8505 8505 * 8506 - * 'struct bpf_rb_node *node' arg to bpf_rbtree_add is the same PTR_TO_BTF_ID w/ offset 8506 + * 'struct bpf_rb_node *node' arg to bpf_rbtree_add_impl is the same PTR_TO_BTF_ID w/ offset 8507 8507 * that 'less' callback args will be receiving. However, 'node' arg was release_reference'd 8508 8508 * by this point, so look at 'root' 8509 8509 */ ··· 9571 9571 KF_bpf_obj_new_impl, 9572 9572 KF_bpf_obj_drop_impl, 9573 9573 KF_bpf_refcount_acquire_impl, 9574 - KF_bpf_list_push_front, 9575 - KF_bpf_list_push_back, 9574 + KF_bpf_list_push_front_impl, 9575 + KF_bpf_list_push_back_impl, 9576 9576 KF_bpf_list_pop_front, 9577 9577 KF_bpf_list_pop_back, 9578 9578 KF_bpf_cast_to_kern_ctx, ··· 9580 9580 KF_bpf_rcu_read_lock, 9581 9581 KF_bpf_rcu_read_unlock, 9582 9582 KF_bpf_rbtree_remove, 9583 - KF_bpf_rbtree_add, 9583 + KF_bpf_rbtree_add_impl, 9584 9584 KF_bpf_rbtree_first, 9585 9585 KF_bpf_dynptr_from_skb, 9586 9586 KF_bpf_dynptr_from_xdp, ··· 9592 9592 BTF_ID(func, bpf_obj_new_impl) 9593 9593 BTF_ID(func, bpf_obj_drop_impl) 9594 9594 BTF_ID(func, bpf_refcount_acquire_impl) 9595 - BTF_ID(func, bpf_list_push_front) 9596 - BTF_ID(func, bpf_list_push_back) 9595 + BTF_ID(func, bpf_list_push_front_impl) 9596 + BTF_ID(func, bpf_list_push_back_impl) 9597 9597 BTF_ID(func, bpf_list_pop_front) 9598 9598 BTF_ID(func, bpf_list_pop_back) 9599 9599 BTF_ID(func, bpf_cast_to_kern_ctx) 9600 9600 BTF_ID(func, bpf_rdonly_cast) 9601 9601 BTF_ID(func, bpf_rbtree_remove) 9602 - BTF_ID(func, bpf_rbtree_add) 9602 + BTF_ID(func, bpf_rbtree_add_impl) 9603 9603 BTF_ID(func, bpf_rbtree_first) 9604 9604 BTF_ID(func, bpf_dynptr_from_skb) 9605 9605 BTF_ID(func, bpf_dynptr_from_xdp) ··· 9611 9611 BTF_ID(func, bpf_obj_new_impl) 9612 9612 BTF_ID(func, bpf_obj_drop_impl) 9613 9613 BTF_ID(func, bpf_refcount_acquire_impl) 9614 - BTF_ID(func, bpf_list_push_front) 9615 - BTF_ID(func, bpf_list_push_back) 9614 + BTF_ID(func, bpf_list_push_front_impl) 9615 + BTF_ID(func, bpf_list_push_back_impl) 9616 9616 BTF_ID(func, bpf_list_pop_front) 9617 9617 BTF_ID(func, bpf_list_pop_back) 9618 9618 BTF_ID(func, bpf_cast_to_kern_ctx) ··· 9620 9620 BTF_ID(func, bpf_rcu_read_lock) 9621 9621 BTF_ID(func, bpf_rcu_read_unlock) 9622 9622 BTF_ID(func, bpf_rbtree_remove) 9623 - BTF_ID(func, bpf_rbtree_add) 9623 + BTF_ID(func, bpf_rbtree_add_impl) 9624 9624 BTF_ID(func, bpf_rbtree_first) 9625 9625 BTF_ID(func, bpf_dynptr_from_skb) 9626 9626 BTF_ID(func, bpf_dynptr_from_xdp) ··· 9954 9954 9955 9955 static bool is_bpf_list_api_kfunc(u32 btf_id) 9956 9956 { 9957 - return btf_id == special_kfunc_list[KF_bpf_list_push_front] || 9958 - btf_id == special_kfunc_list[KF_bpf_list_push_back] || 9957 + return btf_id == special_kfunc_list[KF_bpf_list_push_front_impl] || 9958 + btf_id == special_kfunc_list[KF_bpf_list_push_back_impl] || 9959 9959 btf_id == special_kfunc_list[KF_bpf_list_pop_front] || 9960 9960 btf_id == special_kfunc_list[KF_bpf_list_pop_back]; 9961 9961 } 9962 9962 9963 9963 static bool is_bpf_rbtree_api_kfunc(u32 btf_id) 9964 9964 { 9965 - return btf_id == special_kfunc_list[KF_bpf_rbtree_add] || 9965 + return btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl] || 9966 9966 btf_id == special_kfunc_list[KF_bpf_rbtree_remove] || 9967 9967 btf_id == special_kfunc_list[KF_bpf_rbtree_first]; 9968 9968 } ··· 9975 9975 9976 9976 static bool is_callback_calling_kfunc(u32 btf_id) 9977 9977 { 9978 - return btf_id == special_kfunc_list[KF_bpf_rbtree_add]; 9978 + return btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl]; 9979 9979 } 9980 9980 9981 9981 static bool is_rbtree_lock_required_kfunc(u32 btf_id) ··· 10016 10016 10017 10017 switch (node_field_type) { 10018 10018 case BPF_LIST_NODE: 10019 - ret = (kfunc_btf_id == special_kfunc_list[KF_bpf_list_push_front] || 10020 - kfunc_btf_id == special_kfunc_list[KF_bpf_list_push_back]); 10019 + ret = (kfunc_btf_id == special_kfunc_list[KF_bpf_list_push_front_impl] || 10020 + kfunc_btf_id == special_kfunc_list[KF_bpf_list_push_back_impl]); 10021 10021 break; 10022 10022 case BPF_RB_NODE: 10023 10023 ret = (kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_remove] || 10024 - kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_add]); 10024 + kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl]); 10025 10025 break; 10026 10026 default: 10027 10027 verbose(env, "verifier internal error: unexpected graph node argument type %s\n", ··· 10702 10702 } 10703 10703 } 10704 10704 10705 - if (meta.func_id == special_kfunc_list[KF_bpf_list_push_front] || 10706 - meta.func_id == special_kfunc_list[KF_bpf_list_push_back] || 10707 - meta.func_id == special_kfunc_list[KF_bpf_rbtree_add]) { 10705 + if (meta.func_id == special_kfunc_list[KF_bpf_list_push_front_impl] || 10706 + meta.func_id == special_kfunc_list[KF_bpf_list_push_back_impl] || 10707 + meta.func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { 10708 10708 release_ref_obj_id = regs[BPF_REG_2].ref_obj_id; 10709 + insn_aux->insert_off = regs[BPF_REG_2].off; 10709 10710 err = ref_convert_owning_non_owning(env, release_ref_obj_id); 10710 10711 if (err) { 10711 10712 verbose(env, "kfunc %s#%d conversion of owning ref to non-owning failed\n", ··· 10722 10721 } 10723 10722 } 10724 10723 10725 - if (meta.func_id == special_kfunc_list[KF_bpf_rbtree_add]) { 10724 + if (meta.func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { 10726 10725 err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, 10727 10726 set_rbtree_add_callback_state); 10728 10727 if (err) { ··· 14765 14764 const struct bpf_reg_state *rcur, 14766 14765 struct bpf_id_pair *idmap) 14767 14766 { 14768 - return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && 14767 + return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && 14769 14768 check_ids(rold->id, rcur->id, idmap) && 14770 14769 check_ids(rold->ref_obj_id, rcur->ref_obj_id, idmap); 14771 14770 } ··· 17408 17407 } 17409 17408 } 17410 17409 17410 + static void __fixup_collection_insert_kfunc(struct bpf_insn_aux_data *insn_aux, 17411 + u16 struct_meta_reg, 17412 + u16 node_offset_reg, 17413 + struct bpf_insn *insn, 17414 + struct bpf_insn *insn_buf, 17415 + int *cnt) 17416 + { 17417 + struct btf_struct_meta *kptr_struct_meta = insn_aux->kptr_struct_meta; 17418 + struct bpf_insn addr[2] = { BPF_LD_IMM64(struct_meta_reg, (long)kptr_struct_meta) }; 17419 + 17420 + insn_buf[0] = addr[0]; 17421 + insn_buf[1] = addr[1]; 17422 + insn_buf[2] = BPF_MOV64_IMM(node_offset_reg, insn_aux->insert_off); 17423 + insn_buf[3] = *insn; 17424 + *cnt = 4; 17425 + } 17426 + 17411 17427 static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, 17412 17428 struct bpf_insn *insn_buf, int insn_idx, int *cnt) 17413 17429 { ··· 17471 17453 insn_buf[1] = addr[1]; 17472 17454 insn_buf[2] = *insn; 17473 17455 *cnt = 3; 17456 + } else if (desc->func_id == special_kfunc_list[KF_bpf_list_push_back_impl] || 17457 + desc->func_id == special_kfunc_list[KF_bpf_list_push_front_impl] || 17458 + desc->func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { 17459 + int struct_meta_reg = BPF_REG_3; 17460 + int node_offset_reg = BPF_REG_4; 17461 + 17462 + /* rbtree_add has extra 'less' arg, so args-to-fixup are in diff regs */ 17463 + if (desc->func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { 17464 + struct_meta_reg = BPF_REG_4; 17465 + node_offset_reg = BPF_REG_5; 17466 + } 17467 + 17468 + __fixup_collection_insert_kfunc(&env->insn_aux_data[insn_idx], struct_meta_reg, 17469 + node_offset_reg, insn, insn_buf, cnt); 17474 17470 } else if (desc->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] || 17475 17471 desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) { 17476 17472 insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
+39 -10
tools/testing/selftests/bpf/bpf_experimental.h
··· 14 14 * type ID of a struct in program BTF. 15 15 * 16 16 * The 'local_type_id' parameter must be a known constant. 17 - * The 'meta' parameter is a hidden argument that is ignored. 17 + * The 'meta' parameter is rewritten by the verifier, no need for BPF 18 + * program to set it. 18 19 * Returns 19 20 * A pointer to an object of the type corresponding to the passed in 20 21 * 'local_type_id', or NULL on failure. ··· 29 28 * Free an allocated object. All fields of the object that require 30 29 * destruction will be destructed before the storage is freed. 31 30 * 32 - * The 'meta' parameter is a hidden argument that is ignored. 31 + * The 'meta' parameter is rewritten by the verifier, no need for BPF 32 + * program to set it. 33 33 * Returns 34 34 * Void. 35 35 */ ··· 43 41 * Increment the refcount on a refcounted local kptr, turning the 44 42 * non-owning reference input into an owning reference in the process. 45 43 * 46 - * The 'meta' parameter is a hidden argument that is ignored. 44 + * The 'meta' parameter is rewritten by the verifier, no need for BPF 45 + * program to set it. 47 46 * Returns 48 47 * An owning reference to the object pointed to by 'kptr' 49 48 */ ··· 55 52 56 53 /* Description 57 54 * Add a new entry to the beginning of the BPF linked list. 55 + * 56 + * The 'meta' and 'off' parameters are rewritten by the verifier, no need 57 + * for BPF programs to set them 58 58 * Returns 59 - * Void. 59 + * 0 if the node was successfully added 60 + * -EINVAL if the node wasn't added because it's already in a list 60 61 */ 61 - extern void bpf_list_push_front(struct bpf_list_head *head, struct bpf_list_node *node) __ksym; 62 + extern int bpf_list_push_front_impl(struct bpf_list_head *head, 63 + struct bpf_list_node *node, 64 + void *meta, __u64 off) __ksym; 65 + 66 + /* Convenience macro to wrap over bpf_list_push_front_impl */ 67 + #define bpf_list_push_front(head, node) bpf_list_push_front_impl(head, node, NULL, 0) 62 68 63 69 /* Description 64 70 * Add a new entry to the end of the BPF linked list. 71 + * 72 + * The 'meta' and 'off' parameters are rewritten by the verifier, no need 73 + * for BPF programs to set them 65 74 * Returns 66 - * Void. 75 + * 0 if the node was successfully added 76 + * -EINVAL if the node wasn't added because it's already in a list 67 77 */ 68 - extern void bpf_list_push_back(struct bpf_list_head *head, struct bpf_list_node *node) __ksym; 78 + extern int bpf_list_push_back_impl(struct bpf_list_head *head, 79 + struct bpf_list_node *node, 80 + void *meta, __u64 off) __ksym; 81 + 82 + /* Convenience macro to wrap over bpf_list_push_back_impl */ 83 + #define bpf_list_push_back(head, node) bpf_list_push_back_impl(head, node, NULL, 0) 69 84 70 85 /* Description 71 86 * Remove the entry at the beginning of the BPF linked list. ··· 109 88 110 89 /* Description 111 90 * Add 'node' to rbtree with root 'root' using comparator 'less' 91 + * 92 + * The 'meta' and 'off' parameters are rewritten by the verifier, no need 93 + * for BPF programs to set them 112 94 * Returns 113 - * Nothing 95 + * 0 if the node was successfully added 96 + * -EINVAL if the node wasn't added because it's already in a tree 114 97 */ 115 - extern void bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node, 116 - bool (less)(struct bpf_rb_node *a, const struct bpf_rb_node *b)) __ksym; 98 + extern int bpf_rbtree_add_impl(struct bpf_rb_root *root, struct bpf_rb_node *node, 99 + bool (less)(struct bpf_rb_node *a, const struct bpf_rb_node *b), 100 + void *meta, __u64 off) __ksym; 101 + 102 + /* Convenience macro to wrap over bpf_rbtree_add_impl */ 103 + #define bpf_rbtree_add(head, node, less) bpf_rbtree_add_impl(head, node, less, NULL, 0) 117 104 118 105 /* Description 119 106 * Return the first (leftmost) node in input tree