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
9struct node_acquire {
10 long key;
11 long data;
12 struct bpf_rb_node node;
13 struct bpf_refcount refcount;
14};
15
16extern void bpf_rcu_read_lock(void) __ksym;
17extern void bpf_rcu_read_unlock(void) __ksym;
18
19#define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8)))
20private(A) struct bpf_spin_lock glock;
21private(A) struct bpf_rb_root groot __contains(node_acquire, node);
22
23static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
24{
25 struct node_acquire *node_a;
26 struct node_acquire *node_b;
27
28 node_a = container_of(a, struct node_acquire, node);
29 node_b = container_of(b, struct node_acquire, node);
30
31 return node_a->key < node_b->key;
32}
33
34SEC("?tc")
35__failure __msg("Unreleased reference id=4 alloc_insn=21")
36long rbtree_refcounted_node_ref_escapes(void *ctx)
37{
38 struct node_acquire *n, *m;
39
40 n = bpf_obj_new(typeof(*n));
41 if (!n)
42 return 1;
43
44 bpf_spin_lock(&glock);
45 bpf_rbtree_add(&groot, &n->node, less);
46 /* m becomes an owning ref but is never drop'd or added to a tree */
47 m = bpf_refcount_acquire(n);
48 bpf_spin_unlock(&glock);
49 if (!m)
50 return 2;
51
52 m->key = 2;
53 return 0;
54}
55
56SEC("?tc")
57__failure __msg("Possibly NULL pointer passed to trusted arg0")
58long refcount_acquire_maybe_null(void *ctx)
59{
60 struct node_acquire *n, *m;
61
62 n = bpf_obj_new(typeof(*n));
63 /* Intentionally not testing !n
64 * it's MAYBE_NULL for refcount_acquire
65 */
66 m = bpf_refcount_acquire(n);
67 if (m)
68 bpf_obj_drop(m);
69 if (n)
70 bpf_obj_drop(n);
71
72 return 0;
73}
74
75SEC("?tc")
76__failure __msg("Unreleased reference id=3 alloc_insn=9")
77long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)
78{
79 struct node_acquire *n, *m;
80
81 n = bpf_obj_new(typeof(*n));
82 if (!n)
83 return 1;
84
85 /* m becomes an owning ref but is never drop'd or added to a tree */
86 m = bpf_refcount_acquire(n);
87 m->key = 2;
88
89 bpf_spin_lock(&glock);
90 bpf_rbtree_add(&groot, &n->node, less);
91 bpf_spin_unlock(&glock);
92
93 return 0;
94}
95
96SEC("?fentry.s/bpf_testmod_test_read")
97__failure __msg("function calls are not allowed while holding a lock")
98int BPF_PROG(rbtree_fail_sleepable_lock_across_rcu,
99 struct file *file, struct kobject *kobj,
100 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len)
101{
102 struct node_acquire *n;
103
104 n = bpf_obj_new(typeof(*n));
105 if (!n)
106 return 0;
107
108 /* spin_{lock,unlock} are in different RCU CS */
109 bpf_rcu_read_lock();
110 bpf_spin_lock(&glock);
111 bpf_rbtree_add(&groot, &n->node, less);
112 bpf_rcu_read_unlock();
113
114 bpf_rcu_read_lock();
115 bpf_spin_unlock(&glock);
116 bpf_rcu_read_unlock();
117
118 return 0;
119}
120
121char _license[] SEC("license") = "GPL";
122

source code of linux/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c