1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3 
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include "bpf_misc.h"
7 
8 char _license[] SEC("license") = "GPL";
9 
10 struct sample {
11 	int pid;
12 	int seq;
13 	long value;
14 	char comm[16];
15 };
16 
17 struct {
18 	__uint(type, BPF_MAP_TYPE_USER_RINGBUF);
19 } user_ringbuf SEC(".maps");
20 
21 struct {
22 	__uint(type, BPF_MAP_TYPE_RINGBUF);
23 	__uint(max_entries, 2);
24 } ringbuf SEC(".maps");
25 
26 static int map_value;
27 
28 static long
29 bad_access1(struct bpf_dynptr *dynptr, void *context)
30 {
31 	const struct sample *sample;
32 
33 	sample = bpf_dynptr_data(dynptr - 1, 0, sizeof(*sample));
34 	bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr - 1);
35 
36 	return 0;
37 }
38 
39 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
40  * not be able to read before the pointer.
41  */
42 SEC("?raw_tp/")
43 int user_ringbuf_callback_bad_access1(void *ctx)
44 {
45 	bpf_user_ringbuf_drain(&user_ringbuf, bad_access1, NULL, 0);
46 
47 	return 0;
48 }
49 
50 static long
51 bad_access2(struct bpf_dynptr *dynptr, void *context)
52 {
53 	const struct sample *sample;
54 
55 	sample = bpf_dynptr_data(dynptr + 1, 0, sizeof(*sample));
56 	bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr + 1);
57 
58 	return 0;
59 }
60 
61 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
62  * not be able to read past the end of the pointer.
63  */
64 SEC("?raw_tp/")
65 int user_ringbuf_callback_bad_access2(void *ctx)
66 {
67 	bpf_user_ringbuf_drain(&user_ringbuf, bad_access2, NULL, 0);
68 
69 	return 0;
70 }
71 
72 static long
73 write_forbidden(struct bpf_dynptr *dynptr, void *context)
74 {
75 	*((long *)dynptr) = 0;
76 
77 	return 0;
78 }
79 
80 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
81  * not be able to write to that pointer.
82  */
83 SEC("?raw_tp/")
84 int user_ringbuf_callback_write_forbidden(void *ctx)
85 {
86 	bpf_user_ringbuf_drain(&user_ringbuf, write_forbidden, NULL, 0);
87 
88 	return 0;
89 }
90 
91 static long
92 null_context_write(struct bpf_dynptr *dynptr, void *context)
93 {
94 	*((__u64 *)context) = 0;
95 
96 	return 0;
97 }
98 
99 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
100  * not be able to write to that pointer.
101  */
102 SEC("?raw_tp/")
103 int user_ringbuf_callback_null_context_write(void *ctx)
104 {
105 	bpf_user_ringbuf_drain(&user_ringbuf, null_context_write, NULL, 0);
106 
107 	return 0;
108 }
109 
110 static long
111 null_context_read(struct bpf_dynptr *dynptr, void *context)
112 {
113 	__u64 id = *((__u64 *)context);
114 
115 	bpf_printk("Read id %lu\n", id);
116 
117 	return 0;
118 }
119 
120 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
121  * not be able to write to that pointer.
122  */
123 SEC("?raw_tp/")
124 int user_ringbuf_callback_null_context_read(void *ctx)
125 {
126 	bpf_user_ringbuf_drain(&user_ringbuf, null_context_read, NULL, 0);
127 
128 	return 0;
129 }
130 
131 static long
132 try_discard_dynptr(struct bpf_dynptr *dynptr, void *context)
133 {
134 	bpf_ringbuf_discard_dynptr(dynptr, 0);
135 
136 	return 0;
137 }
138 
139 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
140  * not be able to read past the end of the pointer.
141  */
142 SEC("?raw_tp/")
143 int user_ringbuf_callback_discard_dynptr(void *ctx)
144 {
145 	bpf_user_ringbuf_drain(&user_ringbuf, try_discard_dynptr, NULL, 0);
146 
147 	return 0;
148 }
149 
150 static long
151 try_submit_dynptr(struct bpf_dynptr *dynptr, void *context)
152 {
153 	bpf_ringbuf_submit_dynptr(dynptr, 0);
154 
155 	return 0;
156 }
157 
158 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
159  * not be able to read past the end of the pointer.
160  */
161 SEC("?raw_tp/")
162 int user_ringbuf_callback_submit_dynptr(void *ctx)
163 {
164 	bpf_user_ringbuf_drain(&user_ringbuf, try_submit_dynptr, NULL, 0);
165 
166 	return 0;
167 }
168 
169 static long
170 invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context)
171 {
172 	return 2;
173 }
174 
175 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
176  * not be able to write to that pointer.
177  */
178 SEC("?raw_tp/")
179 int user_ringbuf_callback_invalid_return(void *ctx)
180 {
181 	bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0);
182 
183 	return 0;
184 }
185 
186 static long
187 try_reinit_dynptr_mem(struct bpf_dynptr *dynptr, void *context)
188 {
189 	bpf_dynptr_from_mem(&map_value, 4, 0, dynptr);
190 	return 0;
191 }
192 
193 static long
194 try_reinit_dynptr_ringbuf(struct bpf_dynptr *dynptr, void *context)
195 {
196 	bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, dynptr);
197 	return 0;
198 }
199 
200 SEC("?raw_tp/")
201 int user_ringbuf_callback_reinit_dynptr_mem(void *ctx)
202 {
203 	bpf_user_ringbuf_drain(&user_ringbuf, try_reinit_dynptr_mem, NULL, 0);
204 	return 0;
205 }
206 
207 SEC("?raw_tp/")
208 int user_ringbuf_callback_reinit_dynptr_ringbuf(void *ctx)
209 {
210 	bpf_user_ringbuf_drain(&user_ringbuf, try_reinit_dynptr_ringbuf, NULL, 0);
211 	return 0;
212 }
213