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
bad_access1(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_bad_access1(void * ctx)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
bad_access2(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_bad_access2(void * ctx)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
write_forbidden(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_write_forbidden(void * ctx)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
null_context_write(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_null_context_write(void * ctx)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
null_context_read(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_null_context_read(void * ctx)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
try_discard_dynptr(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_discard_dynptr(void * ctx)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
try_submit_dynptr(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_submit_dynptr(void * ctx)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
invalid_drain_callback_return(struct bpf_dynptr * dynptr,void * context)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")
user_ringbuf_callback_invalid_return(void * ctx)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