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 return 0; 37 } 38 39 static __always_inline int cb2(void *map, void *key, void *value, void *ctx) 40 { 41 unsigned long sl = 0; 42 43 *(void **)ctx = bpf_kfunc_call_test_acquire(&sl); 44 /* Without the fix this would leak memory */ 45 return 0; 46 } 47 48 SEC("?tc") 49 int leak_prog(void *ctx) 50 { 51 struct prog_test_ref_kfunc *p; 52 struct map_value *v; 53 54 v = bpf_map_lookup_elem(&array_map, &(int){0}); 55 if (!v) 56 return 0; 57 58 p = NULL; 59 bpf_for_each_map_elem(&array_map, cb2, &p, 0); 60 p = bpf_kptr_xchg(&v->ptr, p); 61 if (p) 62 bpf_kfunc_call_test_release(p); 63 return 0; 64 } 65 66 static __always_inline int cb(void *map, void *key, void *value, void *ctx) 67 { 68 return 0; 69 } 70 71 static __always_inline int cb3(void *map, void *key, void *value, void *ctx) 72 { 73 unsigned long sl = 0; 74 void *p; 75 76 bpf_kfunc_call_test_acquire(&sl); 77 bpf_for_each_map_elem(&array_map, cb, &p, 0); 78 /* It should only complain here, not in cb. This is why we need 79 * callback_ref to be set to frameno. 80 */ 81 return 0; 82 } 83 84 SEC("?tc") 85 int nested_cb(void *ctx) 86 { 87 struct prog_test_ref_kfunc *p; 88 unsigned long sl = 0; 89 int sp = 0; 90 91 p = bpf_kfunc_call_test_acquire(&sl); 92 if (!p) 93 return 0; 94 bpf_for_each_map_elem(&array_map, cb3, &sp, 0); 95 bpf_kfunc_call_test_release(p); 96 return 0; 97 } 98 99 SEC("?tc") 100 int non_cb_transfer_ref(void *ctx) 101 { 102 struct prog_test_ref_kfunc *p; 103 unsigned long sl = 0; 104 105 p = bpf_kfunc_call_test_acquire(&sl); 106 if (!p) 107 return 0; 108 cb1(NULL, NULL, NULL, &p); 109 bpf_kfunc_call_test_acquire(&sl); 110 return 0; 111 } 112 113 char _license[] SEC("license") = "GPL"; 114