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 
10 char _license[] SEC("license") = "GPL";
11 
12 int pid, err, val;
13 
14 struct sample {
15 	int pid;
16 	int seq;
17 	long value;
18 	char comm[16];
19 };
20 
21 struct {
22 	__uint(type, BPF_MAP_TYPE_RINGBUF);
23 	__uint(max_entries, 4096);
24 } ringbuf SEC(".maps");
25 
26 struct {
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 
33 SEC("tp/syscalls/sys_enter_nanosleep")
34 int 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 
64 SEC("tp/syscalls/sys_enter_nanosleep")
65 int 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 
119 static 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 
134 SEC("tp/syscalls/sys_enter_nanosleep")
135 int 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 
162 done:
163 	bpf_ringbuf_discard_dynptr(&ptr, 0);
164 	return 0;
165 }
166