Linux Audio

Check our new training course

Loading...
  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";