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/bpf_core_read.h> 6 #include "bpf_experimental.h" 7 #include "bpf_misc.h" 8 9 struct node_acquire { 10 long key; 11 long data; 12 struct bpf_rb_node node; 13 struct bpf_refcount refcount; 14 }; 15 16 struct node_refcounted { 17 long key; 18 struct bpf_list_node list; 19 struct bpf_refcount refcount; 20 }; 21 22 struct node_refcount_only { 23 long key; 24 struct bpf_refcount refcount; 25 }; 26 27 struct map_value_refcount_only { 28 struct node_refcount_only __kptr *node; 29 }; 30 31 struct rcu_graph_node { 32 struct bpf_rb_node node; 33 long data; 34 }; 35 36 struct rcu_graph_node *just_here_because_btf_bug; 37 38 struct map_value_rcu_graph { 39 struct rcu_graph_node __kptr *node; 40 }; 41 42 extern void bpf_rcu_read_lock(void) __ksym; 43 extern void bpf_rcu_read_unlock(void) __ksym; 44 45 #define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8))) 46 private(A) struct bpf_spin_lock glock; 47 private(A) struct bpf_rb_root groot __contains(node_acquire, node); 48 private(B) struct bpf_spin_lock lock; 49 private(B) struct bpf_list_head head __contains(node_refcounted, list); 50 private(C) struct bpf_spin_lock graph_lock; 51 private(C) struct bpf_rb_root graph_root __contains(rcu_graph_node, node); 52 53 struct { 54 __uint(type, BPF_MAP_TYPE_ARRAY); 55 __type(key, int); 56 __type(value, struct map_value_refcount_only); 57 __uint(max_entries, 1); 58 } stashed_refcount_only SEC(".maps"); 59 60 struct { 61 __uint(type, BPF_MAP_TYPE_ARRAY); 62 __type(key, int); 63 __type(value, struct map_value_rcu_graph); 64 __uint(max_entries, 1); 65 } stashed_rcu_graph SEC(".maps"); 66 67 static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) 68 { 69 struct node_acquire *node_a; 70 struct node_acquire *node_b; 71 72 node_a = container_of(a, struct node_acquire, node); 73 node_b = container_of(b, struct node_acquire, node); 74 75 return node_a->key < node_b->key; 76 } 77 78 SEC("?tc") 79 __failure __msg("Unreleased reference id=4 alloc_insn={{[0-9]+}}") 80 long rbtree_refcounted_node_ref_escapes(void *ctx) 81 { 82 struct node_acquire *n, *m; 83 84 n = bpf_obj_new(typeof(*n)); 85 if (!n) 86 return 1; 87 88 bpf_spin_lock(&glock); 89 bpf_rbtree_add(&groot, &n->node, less); 90 /* m becomes an owning ref but is never drop'd or added to a tree */ 91 m = bpf_refcount_acquire(n); 92 bpf_spin_unlock(&glock); 93 if (!m) 94 return 2; 95 96 m->key = 2; 97 return 0; 98 } 99 100 SEC("?tc") 101 __failure __msg("Possibly NULL pointer passed to trusted R1") 102 __msg("requires a non-NULL value of type (void *)") 103 long refcount_acquire_maybe_null(void *ctx) 104 { 105 struct node_acquire *n, *m; 106 107 n = bpf_obj_new(typeof(*n)); 108 /* Intentionally not testing !n 109 * it's MAYBE_NULL for refcount_acquire 110 */ 111 m = bpf_refcount_acquire(n); 112 if (m) 113 bpf_obj_drop(m); 114 if (n) 115 bpf_obj_drop(n); 116 117 return 0; 118 } 119 120 SEC("?tc") 121 __failure __msg("R1 is neither owning or non-owning ref") 122 __msg("expects a pointer to a BPF-managed refcounted object, but R1 is a context pointer") 123 long refcount_acquire_non_object(void *ctx) 124 { 125 return bpf_refcount_acquire(ctx) != NULL; 126 } 127 128 SEC("?syscall") 129 __failure __msg("Possibly NULL pointer passed to trusted R1") 130 long refcount_acquire_rcu_map_kptr_unchecked_drop(void *ctx) 131 { 132 struct map_value_refcount_only *mapval; 133 struct node_refcount_only *tmp, *n, *m; 134 int idx = 0; 135 136 /* Force Clang to emit complete BTF for struct node_refcount_only. */ 137 tmp = bpf_obj_new(typeof(*tmp)); 138 if (!tmp) 139 return 3; 140 bpf_obj_drop(tmp); 141 142 mapval = bpf_map_lookup_elem(&stashed_refcount_only, &idx); 143 if (!mapval) 144 return 1; 145 146 bpf_rcu_read_lock(); 147 n = mapval->node; 148 if (!n) { 149 bpf_rcu_read_unlock(); 150 return 2; 151 } 152 m = bpf_refcount_acquire(n); 153 bpf_rcu_read_unlock(); 154 155 bpf_obj_drop(m); 156 157 return 0; 158 } 159 160 SEC("?syscall") 161 __failure 162 __msg("bpf_rbtree_remove can only take non-owning or refcounted " 163 "bpf_rb_node pointer") 164 long rbtree_remove_after_rcu_unlock(void *ctx) 165 { 166 struct map_value_rcu_graph *mapval; 167 struct bpf_rb_node *rb_node; 168 struct rcu_graph_node *node; 169 int idx = 0; 170 171 mapval = bpf_map_lookup_elem(&stashed_rcu_graph, &idx); 172 if (!mapval) 173 return 0; 174 175 bpf_rcu_read_lock(); 176 node = mapval->node; 177 if (!node) { 178 bpf_rcu_read_unlock(); 179 return 0; 180 } 181 bpf_rcu_read_unlock(); 182 183 bpf_spin_lock(&graph_lock); 184 rb_node = bpf_rbtree_remove(&graph_root, &node->node); 185 bpf_spin_unlock(&graph_lock); 186 if (rb_node) 187 bpf_obj_drop(container_of(rb_node, struct rcu_graph_node, node)); 188 189 return 0; 190 } 191 192 SEC("?syscall") 193 __failure __msg("R1 is neither owning or non-owning ref") 194 long refcount_acquire_after_rcu_unlock(void *ctx) 195 { 196 struct map_value_refcount_only *mapval; 197 struct node_refcount_only *node, *ref; 198 int idx = 0; 199 200 mapval = bpf_map_lookup_elem(&stashed_refcount_only, &idx); 201 if (!mapval) 202 return 0; 203 204 bpf_rcu_read_lock(); 205 node = mapval->node; 206 if (!node) { 207 bpf_rcu_read_unlock(); 208 return 0; 209 } 210 bpf_rcu_read_unlock(); 211 212 ref = bpf_refcount_acquire(node); 213 if (ref) 214 bpf_obj_drop(ref); 215 216 return 0; 217 } 218 219 SEC("?syscall") 220 __failure __msg("invalid mem access 'scalar'") 221 long graph_kptr_after_spin_unlock(void *ctx) 222 { 223 struct map_value_rcu_graph *mapval; 224 struct rcu_graph_node *node; 225 int idx = 0; 226 227 mapval = bpf_map_lookup_elem(&stashed_rcu_graph, &idx); 228 if (!mapval) 229 return 0; 230 231 bpf_spin_lock(&graph_lock); 232 node = mapval->node; 233 if (!node) { 234 bpf_spin_unlock(&graph_lock); 235 return 0; 236 } 237 bpf_spin_unlock(&graph_lock); 238 239 return node->data; 240 } 241 242 SEC("?tc") 243 __failure __msg("Unreleased reference id=3 alloc_insn={{[0-9]+}}") 244 long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx) 245 { 246 struct node_acquire *n, *m; 247 248 n = bpf_obj_new(typeof(*n)); 249 if (!n) 250 return 1; 251 252 /* m becomes an owning ref but is never drop'd or added to a tree */ 253 m = bpf_refcount_acquire(n); 254 m->key = 2; 255 256 bpf_spin_lock(&glock); 257 bpf_rbtree_add(&groot, &n->node, less); 258 bpf_spin_unlock(&glock); 259 260 return 0; 261 } 262 263 SEC("?tc") 264 __failure __msg("dereference of modified ptr_ ptr R1") 265 long refcount_acquire_list_node_offset(void *ctx) 266 { 267 struct node_refcounted *node, *base, *ref; 268 struct bpf_list_node *list_node; 269 270 node = bpf_obj_new(typeof(*node)); 271 if (!node) 272 return 1; 273 274 bpf_spin_lock(&lock); 275 bpf_list_push_front(&head, &node->list); 276 list_node = bpf_list_pop_front(&head); 277 bpf_spin_unlock(&lock); 278 if (!list_node) 279 return 2; 280 281 base = container_of(list_node, struct node_refcounted, list); 282 ref = bpf_refcount_acquire(list_node); 283 if (ref) 284 bpf_obj_drop(ref); 285 bpf_obj_drop(base); 286 return 0; 287 } 288 289 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 290 __failure __msg("function calls are not allowed while holding a lock") 291 int BPF_PROG(rbtree_fail_sleepable_lock_across_rcu, 292 struct file *file, struct kobject *kobj, 293 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) 294 { 295 struct node_acquire *n; 296 297 n = bpf_obj_new(typeof(*n)); 298 if (!n) 299 return 0; 300 301 /* spin_{lock,unlock} are in different RCU CS */ 302 bpf_rcu_read_lock(); 303 bpf_spin_lock(&glock); 304 bpf_rbtree_add(&groot, &n->node, less); 305 bpf_rcu_read_unlock(); 306 307 bpf_rcu_read_lock(); 308 bpf_spin_unlock(&glock); 309 bpf_rcu_read_unlock(); 310 311 return 0; 312 } 313 314 char _license[] SEC("license") = "GPL"; 315