xref: /linux/tools/testing/selftests/bpf/progs/verifier_ctx.c (revision a6923c06a3b2e2c534ae28c53a7531e76cc95cfa)
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