Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2022 Facebook */
  3
  4#include <string.h>
  5#include <linux/bpf.h>
  6#include <bpf/bpf_helpers.h>
  7#include "bpf_misc.h"
  8#include "errno.h"
  9
 10char _license[] SEC("license") = "GPL";
 11
 12int pid, err, val;
 13
 14struct sample {
 15	int pid;
 16	int seq;
 17	long value;
 18	char comm[16];
 19};
 20
 21struct {
 22	__uint(type, BPF_MAP_TYPE_RINGBUF);
 23	__uint(max_entries, 4096);
 24} ringbuf SEC(".maps");
 25
 26struct {
 27	__uint(type, BPF_MAP_TYPE_ARRAY);
 28	__uint(max_entries, 1);
 29	__type(key, __u32);
 30	__type(value, __u32);
 31} array_map SEC(".maps");
 32
 33SEC("tp/syscalls/sys_enter_nanosleep")
 34int test_read_write(void *ctx)
 35{
 36	char write_data[64] = "hello there, world!!";
 37	char read_data[64] = {}, buf[64] = {};
 38	struct bpf_dynptr ptr;
 39	int i;
 40
 41	if (bpf_get_current_pid_tgid() >> 32 != pid)
 42		return 0;
 43
 44	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
 45
 46	/* Write data into the dynptr */
 47	err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
 48
 49	/* Read the data that was written into the dynptr */
 50	err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 51
 52	/* Ensure the data we read matches the data we wrote */
 53	for (i = 0; i < sizeof(read_data); i++) {
 54		if (read_data[i] != write_data[i]) {
 55			err = 1;
 56			break;
 57		}
 58	}
 59
 60	bpf_ringbuf_discard_dynptr(&ptr, 0);
 61	return 0;
 62}
 63
 64SEC("tp/syscalls/sys_enter_nanosleep")
 65int test_data_slice(void *ctx)
 66{
 67	__u32 key = 0, val = 235, *map_val;
 68	struct bpf_dynptr ptr;
 69	__u32 map_val_size;
 70	void *data;
 71
 72	map_val_size = sizeof(*map_val);
 73
 74	if (bpf_get_current_pid_tgid() >> 32 != pid)
 75		return 0;
 76
 77	bpf_map_update_elem(&array_map, &key, &val, 0);
 78
 79	map_val = bpf_map_lookup_elem(&array_map, &key);
 80	if (!map_val) {
 81		err = 1;
 82		return 0;
 83	}
 84
 85	bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr);
 86
 87	/* Try getting a data slice that is out of range */
 88	data = bpf_dynptr_data(&ptr, map_val_size + 1, 1);
 89	if (data) {
 90		err = 2;
 91		return 0;
 92	}
 93
 94	/* Try getting more bytes than available */
 95	data = bpf_dynptr_data(&ptr, 0, map_val_size + 1);
 96	if (data) {
 97		err = 3;
 98		return 0;
 99	}
100
101	data = bpf_dynptr_data(&ptr, 0, sizeof(__u32));
102	if (!data) {
103		err = 4;
104		return 0;
105	}
106
107	*(__u32 *)data = 999;
108
109	err = bpf_probe_read_kernel(&val, sizeof(val), data);
110	if (err)
111		return 0;
112
113	if (val != *(int *)data)
114		err = 5;
115
116	return 0;
117}
118
119static int ringbuf_callback(__u32 index, void *data)
120{
121	struct sample *sample;
122
123	struct bpf_dynptr *ptr = (struct bpf_dynptr *)data;
124
125	sample = bpf_dynptr_data(ptr, 0, sizeof(*sample));
126	if (!sample)
127		err = 2;
128	else
129		sample->pid += index;
130
131	return 0;
132}
133
134SEC("tp/syscalls/sys_enter_nanosleep")
135int test_ringbuf(void *ctx)
136{
137	struct bpf_dynptr ptr;
138	struct sample *sample;
139
140	if (bpf_get_current_pid_tgid() >> 32 != pid)
141		return 0;
142
143	val = 100;
144
145	/* check that you can reserve a dynamic size reservation */
146	err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
147
148	sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample));
149	if (!sample) {
150		err = 1;
151		goto done;
152	}
153
154	sample->pid = 10;
155
156	/* Can pass dynptr to callback functions */
157	bpf_loop(10, ringbuf_callback, &ptr, 0);
158
159	if (sample->pid != 55)
160		err = 2;
161
162done:
163	bpf_ringbuf_discard_dynptr(&ptr, 0);
164	return 0;
165}