1 // SPDX-License-Identifier: GPL-2.0 2 #include <vmlinux.h> 3 #include <bpf/bpf_tracing.h> 4 #include <bpf/bpf_helpers.h> 5 #include "../bpf_testmod/bpf_testmod_kfunc.h" 6 7 struct map_value { 8 struct prog_test_ref_kfunc __kptr *ptr; 9 }; 10 11 struct { 12 __uint(type, BPF_MAP_TYPE_ARRAY); 13 __type(key, int); 14 __type(value, struct map_value); 15 __uint(max_entries, 16); 16 } array_map SEC(".maps"); 17 18 static __noinline int cb1(void *map, void *key, void *value, void *ctx) 19 { 20 void *p = *(void **)ctx; 21 bpf_kfunc_call_test_release(p); 22 /* Without the fix this would cause underflow */ 23 return 0; 24 } 25 26 SEC("?tc") 27 int underflow_prog(void *ctx) 28 { 29 struct prog_test_ref_kfunc *p; 30 unsigned long sl = 0; 31 32 p = bpf_kfunc_call_test_acquire(&sl); 33 if (!p) 34 return 0; 35 bpf_for_each_map_elem(&array_map, cb1, &p, 0); 36 bpf_kfunc_call_test_release(p); 37 return 0; 38 } 39 40 static __always_inline int cb2(void *map, void *key, void *value, void *ctx) 41 { 42 unsigned long sl = 0; 43 44 *(void **)ctx = bpf_kfunc_call_test_acquire(&sl); 45 /* Without the fix this would leak memory */ 46 return 0; 47 } 48 49 SEC("?tc") 50 int leak_prog(void *ctx) 51 { 52 struct prog_test_ref_kfunc *p; 53 struct map_value *v; 54 55 v = bpf_map_lookup_elem(&array_map, &(int){0}); 56 if (!v) 57 return 0; 58 59 p = NULL; 60 bpf_for_each_map_elem(&array_map, cb2, &p, 0); 61 p = bpf_kptr_xchg(&v->ptr, p); 62 if (p) 63 bpf_kfunc_call_test_release(p); 64 return 0; 65 } 66 67 static __always_inline int cb(void *map, void *key, void *value, void *ctx) 68 { 69 return 0; 70 } 71 72 static __always_inline int cb3(void *map, void *key, void *value, void *ctx) 73 { 74 unsigned long sl = 0; 75 void *p; 76 77 bpf_kfunc_call_test_acquire(&sl); 78 bpf_for_each_map_elem(&array_map, cb, &p, 0); 79 /* It should only complain here, not in cb. This is why we need 80 * callback_ref to be set to frameno. 81 */ 82 return 0; 83 } 84 85 SEC("?tc") 86 int nested_cb(void *ctx) 87 { 88 struct prog_test_ref_kfunc *p; 89 unsigned long sl = 0; 90 int sp = 0; 91 92 p = bpf_kfunc_call_test_acquire(&sl); 93 if (!p) 94 return 0; 95 bpf_for_each_map_elem(&array_map, cb3, &sp, 0); 96 bpf_kfunc_call_test_release(p); 97 return 0; 98 } 99 100 SEC("?tc") 101 int non_cb_transfer_ref(void *ctx) 102 { 103 struct prog_test_ref_kfunc *p; 104 unsigned long sl = 0; 105 106 p = bpf_kfunc_call_test_acquire(&sl); 107 if (!p) 108 return 0; 109 cb1(NULL, NULL, NULL, &p); 110 bpf_kfunc_call_test_acquire(&sl); 111 return 0; 112 } 113 114 char _license[] SEC("license") = "GPL"; 115