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 static long
22 bad_access1(struct bpf_dynptr *dynptr, void *context)
23 {
24 	const struct sample *sample;
25 
26 	sample = bpf_dynptr_data(dynptr - 1, 0, sizeof(*sample));
27 	bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr - 1);
28 
29 	return 0;
30 }
31 
32 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
33  * not be able to read before the pointer.
34  */
35 SEC("?raw_tp/sys_nanosleep")
36 int user_ringbuf_callback_bad_access1(void *ctx)
37 {
38 	bpf_user_ringbuf_drain(&user_ringbuf, bad_access1, NULL, 0);
39 
40 	return 0;
41 }
42 
43 static long
44 bad_access2(struct bpf_dynptr *dynptr, void *context)
45 {
46 	const struct sample *sample;
47 
48 	sample = bpf_dynptr_data(dynptr + 1, 0, sizeof(*sample));
49 	bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr + 1);
50 
51 	return 0;
52 }
53 
54 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
55  * not be able to read past the end of the pointer.
56  */
57 SEC("?raw_tp/sys_nanosleep")
58 int user_ringbuf_callback_bad_access2(void *ctx)
59 {
60 	bpf_user_ringbuf_drain(&user_ringbuf, bad_access2, NULL, 0);
61 
62 	return 0;
63 }
64 
65 static long
66 write_forbidden(struct bpf_dynptr *dynptr, void *context)
67 {
68 	*((long *)dynptr) = 0;
69 
70 	return 0;
71 }
72 
73 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
74  * not be able to write to that pointer.
75  */
76 SEC("?raw_tp/sys_nanosleep")
77 int user_ringbuf_callback_write_forbidden(void *ctx)
78 {
79 	bpf_user_ringbuf_drain(&user_ringbuf, write_forbidden, NULL, 0);
80 
81 	return 0;
82 }
83 
84 static long
85 null_context_write(struct bpf_dynptr *dynptr, void *context)
86 {
87 	*((__u64 *)context) = 0;
88 
89 	return 0;
90 }
91 
92 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
93  * not be able to write to that pointer.
94  */
95 SEC("?raw_tp/sys_nanosleep")
96 int user_ringbuf_callback_null_context_write(void *ctx)
97 {
98 	bpf_user_ringbuf_drain(&user_ringbuf, null_context_write, NULL, 0);
99 
100 	return 0;
101 }
102 
103 static long
104 null_context_read(struct bpf_dynptr *dynptr, void *context)
105 {
106 	__u64 id = *((__u64 *)context);
107 
108 	bpf_printk("Read id %lu\n", id);
109 
110 	return 0;
111 }
112 
113 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
114  * not be able to write to that pointer.
115  */
116 SEC("?raw_tp/sys_nanosleep")
117 int user_ringbuf_callback_null_context_read(void *ctx)
118 {
119 	bpf_user_ringbuf_drain(&user_ringbuf, null_context_read, NULL, 0);
120 
121 	return 0;
122 }
123 
124 static long
125 try_discard_dynptr(struct bpf_dynptr *dynptr, void *context)
126 {
127 	bpf_ringbuf_discard_dynptr(dynptr, 0);
128 
129 	return 0;
130 }
131 
132 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
133  * not be able to read past the end of the pointer.
134  */
135 SEC("?raw_tp/sys_nanosleep")
136 int user_ringbuf_callback_discard_dynptr(void *ctx)
137 {
138 	bpf_user_ringbuf_drain(&user_ringbuf, try_discard_dynptr, NULL, 0);
139 
140 	return 0;
141 }
142 
143 static long
144 try_submit_dynptr(struct bpf_dynptr *dynptr, void *context)
145 {
146 	bpf_ringbuf_submit_dynptr(dynptr, 0);
147 
148 	return 0;
149 }
150 
151 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
152  * not be able to read past the end of the pointer.
153  */
154 SEC("?raw_tp/sys_nanosleep")
155 int user_ringbuf_callback_submit_dynptr(void *ctx)
156 {
157 	bpf_user_ringbuf_drain(&user_ringbuf, try_submit_dynptr, NULL, 0);
158 
159 	return 0;
160 }
161 
162 static long
163 invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context)
164 {
165 	return 2;
166 }
167 
168 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should
169  * not be able to write to that pointer.
170  */
171 SEC("?raw_tp/sys_nanosleep")
172 int user_ringbuf_callback_invalid_return(void *ctx)
173 {
174 	bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0);
175 
176 	return 0;
177 }
178