162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <vmlinux.h>
362306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
462306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
562306a36Sopenharmony_ci#include "../bpf_testmod/bpf_testmod_kfunc.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistruct map_value {
862306a36Sopenharmony_ci	struct prog_test_ref_kfunc __kptr_untrusted *unref_ptr;
962306a36Sopenharmony_ci	struct prog_test_ref_kfunc __kptr *ref_ptr;
1062306a36Sopenharmony_ci};
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistruct array_map {
1362306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_ARRAY);
1462306a36Sopenharmony_ci	__type(key, int);
1562306a36Sopenharmony_ci	__type(value, struct map_value);
1662306a36Sopenharmony_ci	__uint(max_entries, 1);
1762306a36Sopenharmony_ci} array_map SEC(".maps");
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct pcpu_array_map {
2062306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
2162306a36Sopenharmony_ci	__type(key, int);
2262306a36Sopenharmony_ci	__type(value, struct map_value);
2362306a36Sopenharmony_ci	__uint(max_entries, 1);
2462306a36Sopenharmony_ci} pcpu_array_map SEC(".maps");
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct hash_map {
2762306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
2862306a36Sopenharmony_ci	__type(key, int);
2962306a36Sopenharmony_ci	__type(value, struct map_value);
3062306a36Sopenharmony_ci	__uint(max_entries, 1);
3162306a36Sopenharmony_ci} hash_map SEC(".maps");
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct pcpu_hash_map {
3462306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
3562306a36Sopenharmony_ci	__type(key, int);
3662306a36Sopenharmony_ci	__type(value, struct map_value);
3762306a36Sopenharmony_ci	__uint(max_entries, 1);
3862306a36Sopenharmony_ci} pcpu_hash_map SEC(".maps");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct hash_malloc_map {
4162306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
4262306a36Sopenharmony_ci	__type(key, int);
4362306a36Sopenharmony_ci	__type(value, struct map_value);
4462306a36Sopenharmony_ci	__uint(max_entries, 1);
4562306a36Sopenharmony_ci	__uint(map_flags, BPF_F_NO_PREALLOC);
4662306a36Sopenharmony_ci} hash_malloc_map SEC(".maps");
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct pcpu_hash_malloc_map {
4962306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
5062306a36Sopenharmony_ci	__type(key, int);
5162306a36Sopenharmony_ci	__type(value, struct map_value);
5262306a36Sopenharmony_ci	__uint(max_entries, 1);
5362306a36Sopenharmony_ci	__uint(map_flags, BPF_F_NO_PREALLOC);
5462306a36Sopenharmony_ci} pcpu_hash_malloc_map SEC(".maps");
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct lru_hash_map {
5762306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_LRU_HASH);
5862306a36Sopenharmony_ci	__type(key, int);
5962306a36Sopenharmony_ci	__type(value, struct map_value);
6062306a36Sopenharmony_ci	__uint(max_entries, 1);
6162306a36Sopenharmony_ci} lru_hash_map SEC(".maps");
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct lru_pcpu_hash_map {
6462306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH);
6562306a36Sopenharmony_ci	__type(key, int);
6662306a36Sopenharmony_ci	__type(value, struct map_value);
6762306a36Sopenharmony_ci	__uint(max_entries, 1);
6862306a36Sopenharmony_ci} lru_pcpu_hash_map SEC(".maps");
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistruct cgrp_ls_map {
7162306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
7262306a36Sopenharmony_ci	__uint(map_flags, BPF_F_NO_PREALLOC);
7362306a36Sopenharmony_ci	__type(key, int);
7462306a36Sopenharmony_ci	__type(value, struct map_value);
7562306a36Sopenharmony_ci} cgrp_ls_map SEC(".maps");
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct task_ls_map {
7862306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
7962306a36Sopenharmony_ci	__uint(map_flags, BPF_F_NO_PREALLOC);
8062306a36Sopenharmony_ci	__type(key, int);
8162306a36Sopenharmony_ci	__type(value, struct map_value);
8262306a36Sopenharmony_ci} task_ls_map SEC(".maps");
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct inode_ls_map {
8562306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_INODE_STORAGE);
8662306a36Sopenharmony_ci	__uint(map_flags, BPF_F_NO_PREALLOC);
8762306a36Sopenharmony_ci	__type(key, int);
8862306a36Sopenharmony_ci	__type(value, struct map_value);
8962306a36Sopenharmony_ci} inode_ls_map SEC(".maps");
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistruct sk_ls_map {
9262306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_SK_STORAGE);
9362306a36Sopenharmony_ci	__uint(map_flags, BPF_F_NO_PREALLOC);
9462306a36Sopenharmony_ci	__type(key, int);
9562306a36Sopenharmony_ci	__type(value, struct map_value);
9662306a36Sopenharmony_ci} sk_ls_map SEC(".maps");
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define DEFINE_MAP_OF_MAP(map_type, inner_map_type, name)       \
9962306a36Sopenharmony_ci	struct {                                                \
10062306a36Sopenharmony_ci		__uint(type, map_type);                         \
10162306a36Sopenharmony_ci		__uint(max_entries, 1);                         \
10262306a36Sopenharmony_ci		__uint(key_size, sizeof(int));                  \
10362306a36Sopenharmony_ci		__uint(value_size, sizeof(int));                \
10462306a36Sopenharmony_ci		__array(values, struct inner_map_type);         \
10562306a36Sopenharmony_ci	} name SEC(".maps") = {                                 \
10662306a36Sopenharmony_ci		.values = { [0] = &inner_map_type },            \
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, array_map, array_of_array_maps);
11062306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, hash_map, array_of_hash_maps);
11162306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, hash_malloc_map, array_of_hash_malloc_maps);
11262306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, lru_hash_map, array_of_lru_hash_maps);
11362306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, array_map, hash_of_array_maps);
11462306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_map, hash_of_hash_maps);
11562306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_malloc_map, hash_of_hash_malloc_maps);
11662306a36Sopenharmony_ciDEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, lru_hash_map, hash_of_lru_hash_maps);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define WRITE_ONCE(x, val) ((*(volatile typeof(x) *) &(x)) = (val))
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void test_kptr_unref(struct map_value *v)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct prog_test_ref_kfunc *p;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	p = v->unref_ptr;
12562306a36Sopenharmony_ci	/* store untrusted_ptr_or_null_ */
12662306a36Sopenharmony_ci	WRITE_ONCE(v->unref_ptr, p);
12762306a36Sopenharmony_ci	if (!p)
12862306a36Sopenharmony_ci		return;
12962306a36Sopenharmony_ci	if (p->a + p->b > 100)
13062306a36Sopenharmony_ci		return;
13162306a36Sopenharmony_ci	/* store untrusted_ptr_ */
13262306a36Sopenharmony_ci	WRITE_ONCE(v->unref_ptr, p);
13362306a36Sopenharmony_ci	/* store NULL */
13462306a36Sopenharmony_ci	WRITE_ONCE(v->unref_ptr, NULL);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void test_kptr_ref(struct map_value *v)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct prog_test_ref_kfunc *p;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	p = v->ref_ptr;
14262306a36Sopenharmony_ci	/* store ptr_or_null_ */
14362306a36Sopenharmony_ci	WRITE_ONCE(v->unref_ptr, p);
14462306a36Sopenharmony_ci	if (!p)
14562306a36Sopenharmony_ci		return;
14662306a36Sopenharmony_ci	/*
14762306a36Sopenharmony_ci	 * p is rcu_ptr_prog_test_ref_kfunc,
14862306a36Sopenharmony_ci	 * because bpf prog is non-sleepable and runs in RCU CS.
14962306a36Sopenharmony_ci	 * p can be passed to kfunc that requires KF_RCU.
15062306a36Sopenharmony_ci	 */
15162306a36Sopenharmony_ci	bpf_kfunc_call_test_ref(p);
15262306a36Sopenharmony_ci	if (p->a + p->b > 100)
15362306a36Sopenharmony_ci		return;
15462306a36Sopenharmony_ci	/* store NULL */
15562306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, NULL);
15662306a36Sopenharmony_ci	if (!p)
15762306a36Sopenharmony_ci		return;
15862306a36Sopenharmony_ci	/*
15962306a36Sopenharmony_ci	 * p is trusted_ptr_prog_test_ref_kfunc.
16062306a36Sopenharmony_ci	 * p can be passed to kfunc that requires KF_RCU.
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	bpf_kfunc_call_test_ref(p);
16362306a36Sopenharmony_ci	if (p->a + p->b > 100) {
16462306a36Sopenharmony_ci		bpf_kfunc_call_test_release(p);
16562306a36Sopenharmony_ci		return;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci	/* store ptr_ */
16862306a36Sopenharmony_ci	WRITE_ONCE(v->unref_ptr, p);
16962306a36Sopenharmony_ci	bpf_kfunc_call_test_release(p);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
17262306a36Sopenharmony_ci	if (!p)
17362306a36Sopenharmony_ci		return;
17462306a36Sopenharmony_ci	/* store ptr_ */
17562306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, p);
17662306a36Sopenharmony_ci	if (!p)
17762306a36Sopenharmony_ci		return;
17862306a36Sopenharmony_ci	if (p->a + p->b > 100) {
17962306a36Sopenharmony_ci		bpf_kfunc_call_test_release(p);
18062306a36Sopenharmony_ci		return;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	bpf_kfunc_call_test_release(p);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void test_kptr(struct map_value *v)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	test_kptr_unref(v);
18862306a36Sopenharmony_ci	test_kptr_ref(v);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciSEC("tc")
19262306a36Sopenharmony_ciint test_map_kptr(struct __sk_buff *ctx)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct map_value *v;
19562306a36Sopenharmony_ci	int key = 0;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci#define TEST(map)					\
19862306a36Sopenharmony_ci	v = bpf_map_lookup_elem(&map, &key);		\
19962306a36Sopenharmony_ci	if (!v)						\
20062306a36Sopenharmony_ci		return 0;				\
20162306a36Sopenharmony_ci	test_kptr(v)
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	TEST(array_map);
20462306a36Sopenharmony_ci	TEST(hash_map);
20562306a36Sopenharmony_ci	TEST(hash_malloc_map);
20662306a36Sopenharmony_ci	TEST(lru_hash_map);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#undef TEST
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciSEC("tp_btf/cgroup_mkdir")
21362306a36Sopenharmony_ciint BPF_PROG(test_cgrp_map_kptr, struct cgroup *cgrp, const char *path)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct map_value *v;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	v = bpf_cgrp_storage_get(&cgrp_ls_map, cgrp, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
21862306a36Sopenharmony_ci	if (v)
21962306a36Sopenharmony_ci		test_kptr(v);
22062306a36Sopenharmony_ci	return 0;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciSEC("lsm/inode_unlink")
22462306a36Sopenharmony_ciint BPF_PROG(test_task_map_kptr, struct inode *inode, struct dentry *victim)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct task_struct *task;
22762306a36Sopenharmony_ci	struct map_value *v;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	task = bpf_get_current_task_btf();
23062306a36Sopenharmony_ci	if (!task)
23162306a36Sopenharmony_ci		return 0;
23262306a36Sopenharmony_ci	v = bpf_task_storage_get(&task_ls_map, task, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
23362306a36Sopenharmony_ci	if (v)
23462306a36Sopenharmony_ci		test_kptr(v);
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ciSEC("lsm/inode_unlink")
23962306a36Sopenharmony_ciint BPF_PROG(test_inode_map_kptr, struct inode *inode, struct dentry *victim)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct map_value *v;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	v = bpf_inode_storage_get(&inode_ls_map, inode, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
24462306a36Sopenharmony_ci	if (v)
24562306a36Sopenharmony_ci		test_kptr(v);
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciSEC("tc")
25062306a36Sopenharmony_ciint test_sk_map_kptr(struct __sk_buff *ctx)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct map_value *v;
25362306a36Sopenharmony_ci	struct bpf_sock *sk;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	sk = ctx->sk;
25662306a36Sopenharmony_ci	if (!sk)
25762306a36Sopenharmony_ci		return 0;
25862306a36Sopenharmony_ci	v = bpf_sk_storage_get(&sk_ls_map, sk, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
25962306a36Sopenharmony_ci	if (v)
26062306a36Sopenharmony_ci		test_kptr(v);
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciSEC("tc")
26562306a36Sopenharmony_ciint test_map_in_map_kptr(struct __sk_buff *ctx)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct map_value *v;
26862306a36Sopenharmony_ci	int key = 0;
26962306a36Sopenharmony_ci	void *map;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci#define TEST(map_in_map)                                \
27262306a36Sopenharmony_ci	map = bpf_map_lookup_elem(&map_in_map, &key);   \
27362306a36Sopenharmony_ci	if (!map)                                       \
27462306a36Sopenharmony_ci		return 0;                               \
27562306a36Sopenharmony_ci	v = bpf_map_lookup_elem(map, &key);		\
27662306a36Sopenharmony_ci	if (!v)						\
27762306a36Sopenharmony_ci		return 0;				\
27862306a36Sopenharmony_ci	test_kptr(v)
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	TEST(array_of_array_maps);
28162306a36Sopenharmony_ci	TEST(array_of_hash_maps);
28262306a36Sopenharmony_ci	TEST(array_of_hash_malloc_maps);
28362306a36Sopenharmony_ci	TEST(array_of_lru_hash_maps);
28462306a36Sopenharmony_ci	TEST(hash_of_array_maps);
28562306a36Sopenharmony_ci	TEST(hash_of_hash_maps);
28662306a36Sopenharmony_ci	TEST(hash_of_hash_malloc_maps);
28762306a36Sopenharmony_ci	TEST(hash_of_lru_hash_maps);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci#undef TEST
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ciint ref = 1;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic __always_inline
29662306a36Sopenharmony_ciint test_map_kptr_ref_pre(struct map_value *v)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct prog_test_ref_kfunc *p, *p_st;
29962306a36Sopenharmony_ci	unsigned long arg = 0;
30062306a36Sopenharmony_ci	int ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	p = bpf_kfunc_call_test_acquire(&arg);
30362306a36Sopenharmony_ci	if (!p)
30462306a36Sopenharmony_ci		return 1;
30562306a36Sopenharmony_ci	ref++;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	p_st = p->next;
30862306a36Sopenharmony_ci	if (p_st->cnt.refs.counter != ref) {
30962306a36Sopenharmony_ci		ret = 2;
31062306a36Sopenharmony_ci		goto end;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, p);
31462306a36Sopenharmony_ci	if (p) {
31562306a36Sopenharmony_ci		ret = 3;
31662306a36Sopenharmony_ci		goto end;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci	if (p_st->cnt.refs.counter != ref)
31962306a36Sopenharmony_ci		return 4;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, NULL);
32262306a36Sopenharmony_ci	if (!p)
32362306a36Sopenharmony_ci		return 5;
32462306a36Sopenharmony_ci	bpf_kfunc_call_test_release(p);
32562306a36Sopenharmony_ci	ref--;
32662306a36Sopenharmony_ci	if (p_st->cnt.refs.counter != ref)
32762306a36Sopenharmony_ci		return 6;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	p = bpf_kfunc_call_test_acquire(&arg);
33062306a36Sopenharmony_ci	if (!p)
33162306a36Sopenharmony_ci		return 7;
33262306a36Sopenharmony_ci	ref++;
33362306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, p);
33462306a36Sopenharmony_ci	if (p) {
33562306a36Sopenharmony_ci		ret = 8;
33662306a36Sopenharmony_ci		goto end;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	if (p_st->cnt.refs.counter != ref)
33962306a36Sopenharmony_ci		return 9;
34062306a36Sopenharmony_ci	/* Leave in map */
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_ciend:
34462306a36Sopenharmony_ci	ref--;
34562306a36Sopenharmony_ci	bpf_kfunc_call_test_release(p);
34662306a36Sopenharmony_ci	return ret;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic __always_inline
35062306a36Sopenharmony_ciint test_map_kptr_ref_post(struct map_value *v)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct prog_test_ref_kfunc *p, *p_st;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	p_st = v->ref_ptr;
35562306a36Sopenharmony_ci	if (!p_st || p_st->cnt.refs.counter != ref)
35662306a36Sopenharmony_ci		return 1;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, NULL);
35962306a36Sopenharmony_ci	if (!p)
36062306a36Sopenharmony_ci		return 2;
36162306a36Sopenharmony_ci	if (p_st->cnt.refs.counter != ref) {
36262306a36Sopenharmony_ci		bpf_kfunc_call_test_release(p);
36362306a36Sopenharmony_ci		return 3;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	p = bpf_kptr_xchg(&v->ref_ptr, p);
36762306a36Sopenharmony_ci	if (p) {
36862306a36Sopenharmony_ci		bpf_kfunc_call_test_release(p);
36962306a36Sopenharmony_ci		return 4;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci	if (p_st->cnt.refs.counter != ref)
37262306a36Sopenharmony_ci		return 5;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	return 0;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci#define TEST(map)                            \
37862306a36Sopenharmony_ci	v = bpf_map_lookup_elem(&map, &key); \
37962306a36Sopenharmony_ci	if (!v)                              \
38062306a36Sopenharmony_ci		return -1;                   \
38162306a36Sopenharmony_ci	ret = test_map_kptr_ref_pre(v);      \
38262306a36Sopenharmony_ci	if (ret)                             \
38362306a36Sopenharmony_ci		return ret;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci#define TEST_PCPU(map)                                 \
38662306a36Sopenharmony_ci	v = bpf_map_lookup_percpu_elem(&map, &key, 0); \
38762306a36Sopenharmony_ci	if (!v)                                        \
38862306a36Sopenharmony_ci		return -1;                             \
38962306a36Sopenharmony_ci	ret = test_map_kptr_ref_pre(v);                \
39062306a36Sopenharmony_ci	if (ret)                                       \
39162306a36Sopenharmony_ci		return ret;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ciSEC("tc")
39462306a36Sopenharmony_ciint test_map_kptr_ref1(struct __sk_buff *ctx)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct map_value *v, val = {};
39762306a36Sopenharmony_ci	int key = 0, ret;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	bpf_map_update_elem(&hash_map, &key, &val, 0);
40062306a36Sopenharmony_ci	bpf_map_update_elem(&hash_malloc_map, &key, &val, 0);
40162306a36Sopenharmony_ci	bpf_map_update_elem(&lru_hash_map, &key, &val, 0);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	bpf_map_update_elem(&pcpu_hash_map, &key, &val, 0);
40462306a36Sopenharmony_ci	bpf_map_update_elem(&pcpu_hash_malloc_map, &key, &val, 0);
40562306a36Sopenharmony_ci	bpf_map_update_elem(&lru_pcpu_hash_map, &key, &val, 0);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	TEST(array_map);
40862306a36Sopenharmony_ci	TEST(hash_map);
40962306a36Sopenharmony_ci	TEST(hash_malloc_map);
41062306a36Sopenharmony_ci	TEST(lru_hash_map);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	TEST_PCPU(pcpu_array_map);
41362306a36Sopenharmony_ci	TEST_PCPU(pcpu_hash_map);
41462306a36Sopenharmony_ci	TEST_PCPU(pcpu_hash_malloc_map);
41562306a36Sopenharmony_ci	TEST_PCPU(lru_pcpu_hash_map);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return 0;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci#undef TEST
42162306a36Sopenharmony_ci#undef TEST_PCPU
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci#define TEST(map)                            \
42462306a36Sopenharmony_ci	v = bpf_map_lookup_elem(&map, &key); \
42562306a36Sopenharmony_ci	if (!v)                              \
42662306a36Sopenharmony_ci		return -1;                   \
42762306a36Sopenharmony_ci	ret = test_map_kptr_ref_post(v);     \
42862306a36Sopenharmony_ci	if (ret)                             \
42962306a36Sopenharmony_ci		return ret;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci#define TEST_PCPU(map)                                 \
43262306a36Sopenharmony_ci	v = bpf_map_lookup_percpu_elem(&map, &key, 0); \
43362306a36Sopenharmony_ci	if (!v)                                        \
43462306a36Sopenharmony_ci		return -1;                             \
43562306a36Sopenharmony_ci	ret = test_map_kptr_ref_post(v);               \
43662306a36Sopenharmony_ci	if (ret)                                       \
43762306a36Sopenharmony_ci		return ret;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ciSEC("tc")
44062306a36Sopenharmony_ciint test_map_kptr_ref2(struct __sk_buff *ctx)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct map_value *v;
44362306a36Sopenharmony_ci	int key = 0, ret;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	TEST(array_map);
44662306a36Sopenharmony_ci	TEST(hash_map);
44762306a36Sopenharmony_ci	TEST(hash_malloc_map);
44862306a36Sopenharmony_ci	TEST(lru_hash_map);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	TEST_PCPU(pcpu_array_map);
45162306a36Sopenharmony_ci	TEST_PCPU(pcpu_hash_map);
45262306a36Sopenharmony_ci	TEST_PCPU(pcpu_hash_malloc_map);
45362306a36Sopenharmony_ci	TEST_PCPU(lru_pcpu_hash_map);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci#undef TEST
45962306a36Sopenharmony_ci#undef TEST_PCPU
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ciSEC("tc")
46262306a36Sopenharmony_ciint test_map_kptr_ref3(struct __sk_buff *ctx)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct prog_test_ref_kfunc *p;
46562306a36Sopenharmony_ci	unsigned long sp = 0;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	p = bpf_kfunc_call_test_acquire(&sp);
46862306a36Sopenharmony_ci	if (!p)
46962306a36Sopenharmony_ci		return 1;
47062306a36Sopenharmony_ci	ref++;
47162306a36Sopenharmony_ci	if (p->cnt.refs.counter != ref) {
47262306a36Sopenharmony_ci		bpf_kfunc_call_test_release(p);
47362306a36Sopenharmony_ci		return 2;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	bpf_kfunc_call_test_release(p);
47662306a36Sopenharmony_ci	ref--;
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ciSEC("syscall")
48162306a36Sopenharmony_ciint test_ls_map_kptr_ref1(void *ctx)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct task_struct *current;
48462306a36Sopenharmony_ci	struct map_value *v;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	current = bpf_get_current_task_btf();
48762306a36Sopenharmony_ci	if (!current)
48862306a36Sopenharmony_ci		return 100;
48962306a36Sopenharmony_ci	v = bpf_task_storage_get(&task_ls_map, current, NULL, 0);
49062306a36Sopenharmony_ci	if (v)
49162306a36Sopenharmony_ci		return 150;
49262306a36Sopenharmony_ci	v = bpf_task_storage_get(&task_ls_map, current, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
49362306a36Sopenharmony_ci	if (!v)
49462306a36Sopenharmony_ci		return 200;
49562306a36Sopenharmony_ci	return test_map_kptr_ref_pre(v);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciSEC("syscall")
49962306a36Sopenharmony_ciint test_ls_map_kptr_ref2(void *ctx)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct task_struct *current;
50262306a36Sopenharmony_ci	struct map_value *v;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	current = bpf_get_current_task_btf();
50562306a36Sopenharmony_ci	if (!current)
50662306a36Sopenharmony_ci		return 100;
50762306a36Sopenharmony_ci	v = bpf_task_storage_get(&task_ls_map, current, NULL, 0);
50862306a36Sopenharmony_ci	if (!v)
50962306a36Sopenharmony_ci		return 200;
51062306a36Sopenharmony_ci	return test_map_kptr_ref_post(v);
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ciSEC("syscall")
51462306a36Sopenharmony_ciint test_ls_map_kptr_ref_del(void *ctx)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct task_struct *current;
51762306a36Sopenharmony_ci	struct map_value *v;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	current = bpf_get_current_task_btf();
52062306a36Sopenharmony_ci	if (!current)
52162306a36Sopenharmony_ci		return 100;
52262306a36Sopenharmony_ci	v = bpf_task_storage_get(&task_ls_map, current, NULL, 0);
52362306a36Sopenharmony_ci	if (!v)
52462306a36Sopenharmony_ci		return 200;
52562306a36Sopenharmony_ci	if (!v->ref_ptr)
52662306a36Sopenharmony_ci		return 300;
52762306a36Sopenharmony_ci	return bpf_task_storage_delete(&task_ls_map, current);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
531