1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/ctx.c */
3
4 #include "vmlinux.h"
5 #include <bpf/bpf_helpers.h>
6 #include "bpf_misc.h"
7
8 #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
9
10 SEC("tc")
11 __description("context stores via BPF_ATOMIC")
12 __failure __msg("BPF_ATOMIC stores into R1 ctx is not allowed")
context_stores_via_bpf_atomic(void)13 __naked void context_stores_via_bpf_atomic(void)
14 {
15 asm volatile (" \
16 r0 = 0; \
17 lock *(u32 *)(r1 + %[__sk_buff_mark]) += w0; \
18 exit; \
19 " :
20 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
21 : __clobber_all);
22 }
23
24 SEC("tc")
25 __description("arithmetic ops make PTR_TO_CTX unusable")
26 __failure __msg("dereference of modified ctx ptr")
make_ptr_to_ctx_unusable(void)27 __naked void make_ptr_to_ctx_unusable(void)
28 {
29 asm volatile (" \
30 r1 += %[__imm_0]; \
31 r0 = *(u32*)(r1 + %[__sk_buff_mark]); \
32 exit; \
33 " :
34 : __imm_const(__imm_0,
35 offsetof(struct __sk_buff, data) - offsetof(struct __sk_buff, mark)),
36 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
37 : __clobber_all);
38 }
39
40 SEC("tc")
41 __description("pass unmodified ctx pointer to helper")
42 __success __retval(0)
unmodified_ctx_pointer_to_helper(void)43 __naked void unmodified_ctx_pointer_to_helper(void)
44 {
45 asm volatile (" \
46 r2 = 0; \
47 call %[bpf_csum_update]; \
48 r0 = 0; \
49 exit; \
50 " :
51 : __imm(bpf_csum_update)
52 : __clobber_all);
53 }
54
55 SEC("tc")
56 __description("pass modified ctx pointer to helper, 1")
57 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed")
ctx_pointer_to_helper_1(void)58 __naked void ctx_pointer_to_helper_1(void)
59 {
60 asm volatile (" \
61 r1 += -612; \
62 r2 = 0; \
63 call %[bpf_csum_update]; \
64 r0 = 0; \
65 exit; \
66 " :
67 : __imm(bpf_csum_update)
68 : __clobber_all);
69 }
70
71 SEC("socket")
72 __description("pass modified ctx pointer to helper, 2")
73 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed")
74 __failure_unpriv __msg_unpriv("negative offset ctx ptr R1 off=-612 disallowed")
ctx_pointer_to_helper_2(void)75 __naked void ctx_pointer_to_helper_2(void)
76 {
77 asm volatile (" \
78 r1 += -612; \
79 call %[bpf_get_socket_cookie]; \
80 r0 = 0; \
81 exit; \
82 " :
83 : __imm(bpf_get_socket_cookie)
84 : __clobber_all);
85 }
86
87 SEC("tc")
88 __description("pass modified ctx pointer to helper, 3")
89 __failure __msg("variable ctx access var_off=(0x0; 0x4)")
ctx_pointer_to_helper_3(void)90 __naked void ctx_pointer_to_helper_3(void)
91 {
92 asm volatile (" \
93 r3 = *(u32*)(r1 + 0); \
94 r3 &= 4; \
95 r1 += r3; \
96 r2 = 0; \
97 call %[bpf_csum_update]; \
98 r0 = 0; \
99 exit; \
100 " :
101 : __imm(bpf_csum_update)
102 : __clobber_all);
103 }
104
105 SEC("cgroup/sendmsg6")
106 __description("pass ctx or null check, 1: ctx")
107 __success
or_null_check_1_ctx(void)108 __naked void or_null_check_1_ctx(void)
109 {
110 asm volatile (" \
111 call %[bpf_get_netns_cookie]; \
112 r0 = 0; \
113 exit; \
114 " :
115 : __imm(bpf_get_netns_cookie)
116 : __clobber_all);
117 }
118
119 SEC("cgroup/sendmsg6")
120 __description("pass ctx or null check, 2: null")
121 __success
or_null_check_2_null(void)122 __naked void or_null_check_2_null(void)
123 {
124 asm volatile (" \
125 r1 = 0; \
126 call %[bpf_get_netns_cookie]; \
127 r0 = 0; \
128 exit; \
129 " :
130 : __imm(bpf_get_netns_cookie)
131 : __clobber_all);
132 }
133
134 SEC("cgroup/sendmsg6")
135 __description("pass ctx or null check, 3: 1")
136 __failure __msg("R1 type=scalar expected=ctx")
or_null_check_3_1(void)137 __naked void or_null_check_3_1(void)
138 {
139 asm volatile (" \
140 r1 = 1; \
141 call %[bpf_get_netns_cookie]; \
142 r0 = 0; \
143 exit; \
144 " :
145 : __imm(bpf_get_netns_cookie)
146 : __clobber_all);
147 }
148
149 SEC("cgroup/sendmsg6")
150 __description("pass ctx or null check, 4: ctx - const")
151 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed")
null_check_4_ctx_const(void)152 __naked void null_check_4_ctx_const(void)
153 {
154 asm volatile (" \
155 r1 += -612; \
156 call %[bpf_get_netns_cookie]; \
157 r0 = 0; \
158 exit; \
159 " :
160 : __imm(bpf_get_netns_cookie)
161 : __clobber_all);
162 }
163
164 SEC("cgroup/connect4")
165 __description("pass ctx or null check, 5: null (connect)")
166 __success
null_check_5_null_connect(void)167 __naked void null_check_5_null_connect(void)
168 {
169 asm volatile (" \
170 r1 = 0; \
171 call %[bpf_get_netns_cookie]; \
172 r0 = 0; \
173 exit; \
174 " :
175 : __imm(bpf_get_netns_cookie)
176 : __clobber_all);
177 }
178
179 SEC("cgroup/post_bind4")
180 __description("pass ctx or null check, 6: null (bind)")
181 __success
null_check_6_null_bind(void)182 __naked void null_check_6_null_bind(void)
183 {
184 asm volatile (" \
185 r1 = 0; \
186 call %[bpf_get_netns_cookie]; \
187 r0 = 0; \
188 exit; \
189 " :
190 : __imm(bpf_get_netns_cookie)
191 : __clobber_all);
192 }
193
194 SEC("cgroup/post_bind4")
195 __description("pass ctx or null check, 7: ctx (bind)")
196 __success
null_check_7_ctx_bind(void)197 __naked void null_check_7_ctx_bind(void)
198 {
199 asm volatile (" \
200 call %[bpf_get_socket_cookie]; \
201 r0 = 0; \
202 exit; \
203 " :
204 : __imm(bpf_get_socket_cookie)
205 : __clobber_all);
206 }
207
208 SEC("cgroup/post_bind4")
209 __description("pass ctx or null check, 8: null (bind)")
210 __failure __msg("R1 type=scalar expected=ctx")
null_check_8_null_bind(void)211 __naked void null_check_8_null_bind(void)
212 {
213 asm volatile (" \
214 r1 = 0; \
215 call %[bpf_get_socket_cookie]; \
216 r0 = 0; \
217 exit; \
218 " :
219 : __imm(bpf_get_socket_cookie)
220 : __clobber_all);
221 }
222
223 #define narrow_load(type, ctx, field) \
224 SEC(type) \
225 __description("narrow load on field " #field " of " #ctx) \
226 __failure __msg("invalid bpf_context access") \
227 __naked void invalid_narrow_load##ctx##field(void) \
228 { \
229 asm volatile (" \
230 r1 = *(u32 *)(r1 + %[off]); \
231 r0 = 0; \
232 exit;" \
233 : \
234 : __imm_const(off, offsetof(struct ctx, field) + 4) \
235 : __clobber_all); \
236 }
237
238 narrow_load("cgroup/getsockopt", bpf_sockopt, sk);
239 narrow_load("cgroup/getsockopt", bpf_sockopt, optval);
240 narrow_load("cgroup/getsockopt", bpf_sockopt, optval_end);
241 narrow_load("tc", __sk_buff, sk);
242 narrow_load("cgroup/bind4", bpf_sock_addr, sk);
243 narrow_load("sockops", bpf_sock_ops, sk);
244 narrow_load("sockops", bpf_sock_ops, skb_data);
245 narrow_load("sockops", bpf_sock_ops, skb_data_end);
246 narrow_load("sockops", bpf_sock_ops, skb_hwtstamp);
247
248 #define unaligned_access(type, ctx, field) \
249 SEC(type) \
250 __description("unaligned access on field " #field " of " #ctx) \
251 __failure __msg("invalid bpf_context access") \
252 __naked void unaligned_ctx_access_##ctx##field(void) \
253 { \
254 asm volatile (" \
255 r1 = *(u%[size] *)(r1 + %[off]); \
256 r0 = 0; \
257 exit;" \
258 : \
259 : __imm_const(size, sizeof_field(struct ctx, field) * 8), \
260 __imm_const(off, offsetof(struct ctx, field) + 1) \
261 : __clobber_all); \
262 }
263
264 unaligned_access("flow_dissector", __sk_buff, data);
265 unaligned_access("netfilter", bpf_nf_ctx, skb);
266
267 char _license[] SEC("license") = "GPL";
268