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_experimental.h" 6 7 struct foo { 8 struct bpf_spin_lock lock; 9 int data; 10 }; 11 12 struct array_map { 13 __uint(type, BPF_MAP_TYPE_ARRAY); 14 __type(key, int); 15 __type(value, struct foo); 16 __uint(max_entries, 1); 17 } array_map SEC(".maps"); 18 19 struct { 20 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 21 __uint(max_entries, 1); 22 __type(key, int); 23 __type(value, int); 24 __array(values, struct array_map); 25 } map_of_maps SEC(".maps") = { 26 .values = { 27 [0] = &array_map, 28 }, 29 }; 30 31 static struct bpf_spin_lock lockA SEC(".data.A"); 32 static struct bpf_spin_lock lockB SEC(".data.B"); 33 34 SEC("?tc") 35 int lock_id_kptr_preserve(void *ctx) 36 { 37 struct foo *f; 38 39 f = bpf_obj_new(typeof(*f)); 40 if (!f) 41 return 0; 42 bpf_this_cpu_ptr(f); 43 return 0; 44 } 45 46 SEC("?tc") 47 int lock_id_global_zero(void *ctx) 48 { 49 bpf_this_cpu_ptr(&lockA); 50 return 0; 51 } 52 53 SEC("?tc") 54 int lock_id_mapval_preserve(void *ctx) 55 { 56 struct foo *f; 57 int key = 0; 58 59 f = bpf_map_lookup_elem(&array_map, &key); 60 if (!f) 61 return 0; 62 bpf_this_cpu_ptr(f); 63 return 0; 64 } 65 66 SEC("?tc") 67 int lock_id_innermapval_preserve(void *ctx) 68 { 69 struct foo *f; 70 int key = 0; 71 void *map; 72 73 map = bpf_map_lookup_elem(&map_of_maps, &key); 74 if (!map) 75 return 0; 76 f = bpf_map_lookup_elem(map, &key); 77 if (!f) 78 return 0; 79 bpf_this_cpu_ptr(f); 80 return 0; 81 } 82 83 #define CHECK(test, A, B) \ 84 SEC("?tc") \ 85 int lock_id_mismatch_##test(void *ctx) \ 86 { \ 87 struct foo *f1, *f2, *v, *iv; \ 88 int key = 0; \ 89 void *map; \ 90 \ 91 map = bpf_map_lookup_elem(&map_of_maps, &key); \ 92 if (!map) \ 93 return 0; \ 94 iv = bpf_map_lookup_elem(map, &key); \ 95 if (!iv) \ 96 return 0; \ 97 v = bpf_map_lookup_elem(&array_map, &key); \ 98 if (!v) \ 99 return 0; \ 100 f1 = bpf_obj_new(typeof(*f1)); \ 101 if (!f1) \ 102 return 0; \ 103 f2 = bpf_obj_new(typeof(*f2)); \ 104 if (!f2) { \ 105 bpf_obj_drop(f1); \ 106 return 0; \ 107 } \ 108 bpf_spin_lock(A); \ 109 bpf_spin_unlock(B); \ 110 return 0; \ 111 } 112 113 CHECK(kptr_kptr, &f1->lock, &f2->lock); 114 CHECK(kptr_global, &f1->lock, &lockA); 115 CHECK(kptr_mapval, &f1->lock, &v->lock); 116 CHECK(kptr_innermapval, &f1->lock, &iv->lock); 117 118 CHECK(global_global, &lockA, &lockB); 119 CHECK(global_kptr, &lockA, &f1->lock); 120 CHECK(global_mapval, &lockA, &v->lock); 121 CHECK(global_innermapval, &lockA, &iv->lock); 122 123 SEC("?tc") 124 int lock_id_mismatch_mapval_mapval(void *ctx) 125 { 126 struct foo *f1, *f2; 127 int key = 0; 128 129 f1 = bpf_map_lookup_elem(&array_map, &key); 130 if (!f1) 131 return 0; 132 f2 = bpf_map_lookup_elem(&array_map, &key); 133 if (!f2) 134 return 0; 135 136 bpf_spin_lock(&f1->lock); 137 f1->data = 42; 138 bpf_spin_unlock(&f2->lock); 139 140 return 0; 141 } 142 143 CHECK(mapval_kptr, &v->lock, &f1->lock); 144 CHECK(mapval_global, &v->lock, &lockB); 145 CHECK(mapval_innermapval, &v->lock, &iv->lock); 146 147 SEC("?tc") 148 int lock_id_mismatch_innermapval_innermapval1(void *ctx) 149 { 150 struct foo *f1, *f2; 151 int key = 0; 152 void *map; 153 154 map = bpf_map_lookup_elem(&map_of_maps, &key); 155 if (!map) 156 return 0; 157 f1 = bpf_map_lookup_elem(map, &key); 158 if (!f1) 159 return 0; 160 f2 = bpf_map_lookup_elem(map, &key); 161 if (!f2) 162 return 0; 163 164 bpf_spin_lock(&f1->lock); 165 f1->data = 42; 166 bpf_spin_unlock(&f2->lock); 167 168 return 0; 169 } 170 171 SEC("?tc") 172 int lock_id_mismatch_innermapval_innermapval2(void *ctx) 173 { 174 struct foo *f1, *f2; 175 int key = 0; 176 void *map; 177 178 map = bpf_map_lookup_elem(&map_of_maps, &key); 179 if (!map) 180 return 0; 181 f1 = bpf_map_lookup_elem(map, &key); 182 if (!f1) 183 return 0; 184 map = bpf_map_lookup_elem(&map_of_maps, &key); 185 if (!map) 186 return 0; 187 f2 = bpf_map_lookup_elem(map, &key); 188 if (!f2) 189 return 0; 190 191 bpf_spin_lock(&f1->lock); 192 f1->data = 42; 193 bpf_spin_unlock(&f2->lock); 194 195 return 0; 196 } 197 198 CHECK(innermapval_kptr, &iv->lock, &f1->lock); 199 CHECK(innermapval_global, &iv->lock, &lockA); 200 CHECK(innermapval_mapval, &iv->lock, &v->lock); 201 202 #undef CHECK 203 204 __noinline 205 int global_subprog(struct __sk_buff *ctx) 206 { 207 volatile int ret = 0; 208 209 if (ctx->protocol) 210 ret += ctx->protocol; 211 return ret + ctx->mark; 212 } 213 214 __noinline 215 static int static_subprog_call_global(struct __sk_buff *ctx) 216 { 217 volatile int ret = 0; 218 219 if (ctx->protocol) 220 return ret; 221 return ret + ctx->len + global_subprog(ctx); 222 } 223 224 SEC("?tc") 225 int lock_global_subprog_call1(struct __sk_buff *ctx) 226 { 227 int ret = 0; 228 229 bpf_spin_lock(&lockA); 230 if (ctx->mark == 42) 231 ret = global_subprog(ctx); 232 bpf_spin_unlock(&lockA); 233 return ret; 234 } 235 236 SEC("?tc") 237 int lock_global_subprog_call2(struct __sk_buff *ctx) 238 { 239 int ret = 0; 240 241 bpf_spin_lock(&lockA); 242 if (ctx->mark == 42) 243 ret = static_subprog_call_global(ctx); 244 bpf_spin_unlock(&lockA); 245 return ret; 246 } 247 248 char _license[] SEC("license") = "GPL"; 249