1*2939d7b3SKumar Kartikeya Dwivedi // SPDX-License-Identifier: GPL-2.0
2*2939d7b3SKumar Kartikeya Dwivedi /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3*2939d7b3SKumar Kartikeya Dwivedi #include <vmlinux.h>
4*2939d7b3SKumar Kartikeya Dwivedi #include <bpf/bpf_helpers.h>
5*2939d7b3SKumar Kartikeya Dwivedi #include <bpf/bpf_tracing.h>
6*2939d7b3SKumar Kartikeya Dwivedi #include "../test_kmods/bpf_testmod_kfunc.h"
7*2939d7b3SKumar Kartikeya Dwivedi
8*2939d7b3SKumar Kartikeya Dwivedi struct map_value {
9*2939d7b3SKumar Kartikeya Dwivedi struct prog_test_ref_kfunc __kptr *ref_ptr;
10*2939d7b3SKumar Kartikeya Dwivedi };
11*2939d7b3SKumar Kartikeya Dwivedi
12*2939d7b3SKumar Kartikeya Dwivedi struct {
13*2939d7b3SKumar Kartikeya Dwivedi __uint(type, BPF_MAP_TYPE_HASH);
14*2939d7b3SKumar Kartikeya Dwivedi __uint(map_flags, BPF_F_NO_PREALLOC);
15*2939d7b3SKumar Kartikeya Dwivedi __type(key, int);
16*2939d7b3SKumar Kartikeya Dwivedi __type(value, struct map_value);
17*2939d7b3SKumar Kartikeya Dwivedi __uint(max_entries, 1);
18*2939d7b3SKumar Kartikeya Dwivedi } race_hash_map SEC(".maps");
19*2939d7b3SKumar Kartikeya Dwivedi
20*2939d7b3SKumar Kartikeya Dwivedi struct {
21*2939d7b3SKumar Kartikeya Dwivedi __uint(type, BPF_MAP_TYPE_PERCPU_HASH);
22*2939d7b3SKumar Kartikeya Dwivedi __uint(map_flags, BPF_F_NO_PREALLOC);
23*2939d7b3SKumar Kartikeya Dwivedi __type(key, int);
24*2939d7b3SKumar Kartikeya Dwivedi __type(value, struct map_value);
25*2939d7b3SKumar Kartikeya Dwivedi __uint(max_entries, 1);
26*2939d7b3SKumar Kartikeya Dwivedi } race_percpu_hash_map SEC(".maps");
27*2939d7b3SKumar Kartikeya Dwivedi
28*2939d7b3SKumar Kartikeya Dwivedi struct {
29*2939d7b3SKumar Kartikeya Dwivedi __uint(type, BPF_MAP_TYPE_SK_STORAGE);
30*2939d7b3SKumar Kartikeya Dwivedi __uint(map_flags, BPF_F_NO_PREALLOC);
31*2939d7b3SKumar Kartikeya Dwivedi __type(key, int);
32*2939d7b3SKumar Kartikeya Dwivedi __type(value, struct map_value);
33*2939d7b3SKumar Kartikeya Dwivedi } race_sk_ls_map SEC(".maps");
34*2939d7b3SKumar Kartikeya Dwivedi
35*2939d7b3SKumar Kartikeya Dwivedi int num_of_refs;
36*2939d7b3SKumar Kartikeya Dwivedi int sk_ls_leak_done;
37*2939d7b3SKumar Kartikeya Dwivedi int target_map_id;
38*2939d7b3SKumar Kartikeya Dwivedi int map_freed;
39*2939d7b3SKumar Kartikeya Dwivedi const volatile int nr_cpus;
40*2939d7b3SKumar Kartikeya Dwivedi
41*2939d7b3SKumar Kartikeya Dwivedi SEC("tc")
test_htab_leak(struct __sk_buff * skb)42*2939d7b3SKumar Kartikeya Dwivedi int test_htab_leak(struct __sk_buff *skb)
43*2939d7b3SKumar Kartikeya Dwivedi {
44*2939d7b3SKumar Kartikeya Dwivedi struct prog_test_ref_kfunc *p, *old;
45*2939d7b3SKumar Kartikeya Dwivedi struct map_value val = {};
46*2939d7b3SKumar Kartikeya Dwivedi struct map_value *v;
47*2939d7b3SKumar Kartikeya Dwivedi int key = 0;
48*2939d7b3SKumar Kartikeya Dwivedi
49*2939d7b3SKumar Kartikeya Dwivedi if (bpf_map_update_elem(&race_hash_map, &key, &val, BPF_ANY))
50*2939d7b3SKumar Kartikeya Dwivedi return 1;
51*2939d7b3SKumar Kartikeya Dwivedi
52*2939d7b3SKumar Kartikeya Dwivedi v = bpf_map_lookup_elem(&race_hash_map, &key);
53*2939d7b3SKumar Kartikeya Dwivedi if (!v)
54*2939d7b3SKumar Kartikeya Dwivedi return 2;
55*2939d7b3SKumar Kartikeya Dwivedi
56*2939d7b3SKumar Kartikeya Dwivedi p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
57*2939d7b3SKumar Kartikeya Dwivedi if (!p)
58*2939d7b3SKumar Kartikeya Dwivedi return 3;
59*2939d7b3SKumar Kartikeya Dwivedi old = bpf_kptr_xchg(&v->ref_ptr, p);
60*2939d7b3SKumar Kartikeya Dwivedi if (old)
61*2939d7b3SKumar Kartikeya Dwivedi bpf_kfunc_call_test_release(old);
62*2939d7b3SKumar Kartikeya Dwivedi
63*2939d7b3SKumar Kartikeya Dwivedi bpf_map_delete_elem(&race_hash_map, &key);
64*2939d7b3SKumar Kartikeya Dwivedi
65*2939d7b3SKumar Kartikeya Dwivedi p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
66*2939d7b3SKumar Kartikeya Dwivedi if (!p)
67*2939d7b3SKumar Kartikeya Dwivedi return 4;
68*2939d7b3SKumar Kartikeya Dwivedi old = bpf_kptr_xchg(&v->ref_ptr, p);
69*2939d7b3SKumar Kartikeya Dwivedi if (old)
70*2939d7b3SKumar Kartikeya Dwivedi bpf_kfunc_call_test_release(old);
71*2939d7b3SKumar Kartikeya Dwivedi
72*2939d7b3SKumar Kartikeya Dwivedi return 0;
73*2939d7b3SKumar Kartikeya Dwivedi }
74*2939d7b3SKumar Kartikeya Dwivedi
fill_percpu_kptr(struct map_value * v)75*2939d7b3SKumar Kartikeya Dwivedi static int fill_percpu_kptr(struct map_value *v)
76*2939d7b3SKumar Kartikeya Dwivedi {
77*2939d7b3SKumar Kartikeya Dwivedi struct prog_test_ref_kfunc *p, *old;
78*2939d7b3SKumar Kartikeya Dwivedi
79*2939d7b3SKumar Kartikeya Dwivedi p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
80*2939d7b3SKumar Kartikeya Dwivedi if (!p)
81*2939d7b3SKumar Kartikeya Dwivedi return 1;
82*2939d7b3SKumar Kartikeya Dwivedi old = bpf_kptr_xchg(&v->ref_ptr, p);
83*2939d7b3SKumar Kartikeya Dwivedi if (old)
84*2939d7b3SKumar Kartikeya Dwivedi bpf_kfunc_call_test_release(old);
85*2939d7b3SKumar Kartikeya Dwivedi return 0;
86*2939d7b3SKumar Kartikeya Dwivedi }
87*2939d7b3SKumar Kartikeya Dwivedi
88*2939d7b3SKumar Kartikeya Dwivedi SEC("tc")
test_percpu_htab_leak(struct __sk_buff * skb)89*2939d7b3SKumar Kartikeya Dwivedi int test_percpu_htab_leak(struct __sk_buff *skb)
90*2939d7b3SKumar Kartikeya Dwivedi {
91*2939d7b3SKumar Kartikeya Dwivedi struct map_value *v, *arr[16] = {};
92*2939d7b3SKumar Kartikeya Dwivedi struct map_value val = {};
93*2939d7b3SKumar Kartikeya Dwivedi int key = 0;
94*2939d7b3SKumar Kartikeya Dwivedi int err = 0;
95*2939d7b3SKumar Kartikeya Dwivedi
96*2939d7b3SKumar Kartikeya Dwivedi if (bpf_map_update_elem(&race_percpu_hash_map, &key, &val, BPF_ANY))
97*2939d7b3SKumar Kartikeya Dwivedi return 1;
98*2939d7b3SKumar Kartikeya Dwivedi
99*2939d7b3SKumar Kartikeya Dwivedi for (int i = 0; i < nr_cpus; i++) {
100*2939d7b3SKumar Kartikeya Dwivedi v = bpf_map_lookup_percpu_elem(&race_percpu_hash_map, &key, i);
101*2939d7b3SKumar Kartikeya Dwivedi if (!v)
102*2939d7b3SKumar Kartikeya Dwivedi return 2;
103*2939d7b3SKumar Kartikeya Dwivedi arr[i] = v;
104*2939d7b3SKumar Kartikeya Dwivedi }
105*2939d7b3SKumar Kartikeya Dwivedi
106*2939d7b3SKumar Kartikeya Dwivedi bpf_map_delete_elem(&race_percpu_hash_map, &key);
107*2939d7b3SKumar Kartikeya Dwivedi
108*2939d7b3SKumar Kartikeya Dwivedi for (int i = 0; i < nr_cpus; i++) {
109*2939d7b3SKumar Kartikeya Dwivedi v = arr[i];
110*2939d7b3SKumar Kartikeya Dwivedi err = fill_percpu_kptr(v);
111*2939d7b3SKumar Kartikeya Dwivedi if (err)
112*2939d7b3SKumar Kartikeya Dwivedi return 3;
113*2939d7b3SKumar Kartikeya Dwivedi }
114*2939d7b3SKumar Kartikeya Dwivedi
115*2939d7b3SKumar Kartikeya Dwivedi return 0;
116*2939d7b3SKumar Kartikeya Dwivedi }
117*2939d7b3SKumar Kartikeya Dwivedi
118*2939d7b3SKumar Kartikeya Dwivedi SEC("tp_btf/inet_sock_set_state")
BPF_PROG(test_sk_ls_leak,struct sock * sk,int oldstate,int newstate)119*2939d7b3SKumar Kartikeya Dwivedi int BPF_PROG(test_sk_ls_leak, struct sock *sk, int oldstate, int newstate)
120*2939d7b3SKumar Kartikeya Dwivedi {
121*2939d7b3SKumar Kartikeya Dwivedi struct prog_test_ref_kfunc *p, *old;
122*2939d7b3SKumar Kartikeya Dwivedi struct map_value *v;
123*2939d7b3SKumar Kartikeya Dwivedi
124*2939d7b3SKumar Kartikeya Dwivedi if (newstate != BPF_TCP_SYN_SENT)
125*2939d7b3SKumar Kartikeya Dwivedi return 0;
126*2939d7b3SKumar Kartikeya Dwivedi
127*2939d7b3SKumar Kartikeya Dwivedi if (sk_ls_leak_done)
128*2939d7b3SKumar Kartikeya Dwivedi return 0;
129*2939d7b3SKumar Kartikeya Dwivedi
130*2939d7b3SKumar Kartikeya Dwivedi v = bpf_sk_storage_get(&race_sk_ls_map, sk, NULL,
131*2939d7b3SKumar Kartikeya Dwivedi BPF_SK_STORAGE_GET_F_CREATE);
132*2939d7b3SKumar Kartikeya Dwivedi if (!v)
133*2939d7b3SKumar Kartikeya Dwivedi return 0;
134*2939d7b3SKumar Kartikeya Dwivedi
135*2939d7b3SKumar Kartikeya Dwivedi p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
136*2939d7b3SKumar Kartikeya Dwivedi if (!p)
137*2939d7b3SKumar Kartikeya Dwivedi return 0;
138*2939d7b3SKumar Kartikeya Dwivedi old = bpf_kptr_xchg(&v->ref_ptr, p);
139*2939d7b3SKumar Kartikeya Dwivedi if (old)
140*2939d7b3SKumar Kartikeya Dwivedi bpf_kfunc_call_test_release(old);
141*2939d7b3SKumar Kartikeya Dwivedi
142*2939d7b3SKumar Kartikeya Dwivedi bpf_sk_storage_delete(&race_sk_ls_map, sk);
143*2939d7b3SKumar Kartikeya Dwivedi
144*2939d7b3SKumar Kartikeya Dwivedi p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
145*2939d7b3SKumar Kartikeya Dwivedi if (!p)
146*2939d7b3SKumar Kartikeya Dwivedi return 0;
147*2939d7b3SKumar Kartikeya Dwivedi old = bpf_kptr_xchg(&v->ref_ptr, p);
148*2939d7b3SKumar Kartikeya Dwivedi if (old)
149*2939d7b3SKumar Kartikeya Dwivedi bpf_kfunc_call_test_release(old);
150*2939d7b3SKumar Kartikeya Dwivedi
151*2939d7b3SKumar Kartikeya Dwivedi sk_ls_leak_done = 1;
152*2939d7b3SKumar Kartikeya Dwivedi return 0;
153*2939d7b3SKumar Kartikeya Dwivedi }
154*2939d7b3SKumar Kartikeya Dwivedi
155*2939d7b3SKumar Kartikeya Dwivedi long target_map_ptr;
156*2939d7b3SKumar Kartikeya Dwivedi
157*2939d7b3SKumar Kartikeya Dwivedi SEC("fentry/bpf_map_put")
BPF_PROG(map_put,struct bpf_map * map)158*2939d7b3SKumar Kartikeya Dwivedi int BPF_PROG(map_put, struct bpf_map *map)
159*2939d7b3SKumar Kartikeya Dwivedi {
160*2939d7b3SKumar Kartikeya Dwivedi if (target_map_id && map->id == (u32)target_map_id)
161*2939d7b3SKumar Kartikeya Dwivedi target_map_ptr = (long)map;
162*2939d7b3SKumar Kartikeya Dwivedi return 0;
163*2939d7b3SKumar Kartikeya Dwivedi }
164*2939d7b3SKumar Kartikeya Dwivedi
165*2939d7b3SKumar Kartikeya Dwivedi SEC("fexit/htab_map_free")
BPF_PROG(htab_map_free,struct bpf_map * map)166*2939d7b3SKumar Kartikeya Dwivedi int BPF_PROG(htab_map_free, struct bpf_map *map)
167*2939d7b3SKumar Kartikeya Dwivedi {
168*2939d7b3SKumar Kartikeya Dwivedi if (target_map_ptr && (long)map == target_map_ptr)
169*2939d7b3SKumar Kartikeya Dwivedi map_freed = 1;
170*2939d7b3SKumar Kartikeya Dwivedi return 0;
171*2939d7b3SKumar Kartikeya Dwivedi }
172*2939d7b3SKumar Kartikeya Dwivedi
173*2939d7b3SKumar Kartikeya Dwivedi SEC("fexit/bpf_sk_storage_map_free")
BPF_PROG(sk_map_free,struct bpf_map * map)174*2939d7b3SKumar Kartikeya Dwivedi int BPF_PROG(sk_map_free, struct bpf_map *map)
175*2939d7b3SKumar Kartikeya Dwivedi {
176*2939d7b3SKumar Kartikeya Dwivedi if (target_map_ptr && (long)map == target_map_ptr)
177*2939d7b3SKumar Kartikeya Dwivedi map_freed = 1;
178*2939d7b3SKumar Kartikeya Dwivedi return 0;
179*2939d7b3SKumar Kartikeya Dwivedi }
180*2939d7b3SKumar Kartikeya Dwivedi
181*2939d7b3SKumar Kartikeya Dwivedi SEC("syscall")
count_ref(void * ctx)182*2939d7b3SKumar Kartikeya Dwivedi int count_ref(void *ctx)
183*2939d7b3SKumar Kartikeya Dwivedi {
184*2939d7b3SKumar Kartikeya Dwivedi struct prog_test_ref_kfunc *p;
185*2939d7b3SKumar Kartikeya Dwivedi unsigned long arg = 0;
186*2939d7b3SKumar Kartikeya Dwivedi
187*2939d7b3SKumar Kartikeya Dwivedi p = bpf_kfunc_call_test_acquire(&arg);
188*2939d7b3SKumar Kartikeya Dwivedi if (!p)
189*2939d7b3SKumar Kartikeya Dwivedi return 1;
190*2939d7b3SKumar Kartikeya Dwivedi
191*2939d7b3SKumar Kartikeya Dwivedi num_of_refs = p->cnt.refs.counter;
192*2939d7b3SKumar Kartikeya Dwivedi
193*2939d7b3SKumar Kartikeya Dwivedi bpf_kfunc_call_test_release(p);
194*2939d7b3SKumar Kartikeya Dwivedi return 0;
195*2939d7b3SKumar Kartikeya Dwivedi }
196*2939d7b3SKumar Kartikeya Dwivedi
197*2939d7b3SKumar Kartikeya Dwivedi char _license[] SEC("license") = "GPL";
198