xref: /linux/tools/testing/selftests/bpf/progs/kfunc_call_fail.c (revision 9d19ca5d0e8b4a3f4b2eaa14e86a25f1c93ff35b)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2021 Facebook */
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include "../test_kmods/bpf_testmod_kfunc.h"
6 
7 static struct bpf_spin_lock kfunc_call_lock SEC(".data.A");
8 
9 SEC("?tc")
10 int kfunc_call_test_spin_lock_unsafe(struct __sk_buff *skb)
11 {
12 	bpf_spin_lock(&kfunc_call_lock);
13 	bpf_kfunc_trigger_ctx_check();
14 	bpf_spin_unlock(&kfunc_call_lock);
15 
16 	return 0;
17 }
18 
19 struct syscall_test_args {
20 	__u8 data[16];
21 	size_t size;
22 };
23 
24 SEC("?syscall")
25 int kfunc_syscall_test_fail(struct syscall_test_args *args)
26 {
27 	bpf_kfunc_call_test_mem_len_pass1(&args->data, sizeof(*args) + 1);
28 
29 	return 0;
30 }
31 
32 SEC("?syscall")
33 int kfunc_syscall_test_null_fail(struct syscall_test_args *args)
34 {
35 	/* Must be called with args as a NULL pointer
36 	 * we do not check for it to have the verifier consider that
37 	 * the pointer might not be null, and so we can load it.
38 	 *
39 	 * So the following can not be added:
40 	 *
41 	 * if (args)
42 	 *      return -22;
43 	 */
44 
45 	bpf_kfunc_call_test_mem_len_pass1(args, sizeof(*args));
46 
47 	return 0;
48 }
49 
50 SEC("?tc")
51 int kfunc_call_test_get_mem_fail_rdonly(struct __sk_buff *skb)
52 {
53 	struct prog_test_ref_kfunc *pt;
54 	unsigned long s = 0;
55 	int *p = NULL;
56 	int ret = 0;
57 
58 	pt = bpf_kfunc_call_test_acquire(&s);
59 	if (pt) {
60 		p = bpf_kfunc_call_test_get_rdonly_mem(pt, 2 * sizeof(int));
61 		if (p)
62 			p[0] = 42; /* this is a read-only buffer, so -EACCES */
63 		else
64 			ret = -1;
65 
66 		bpf_kfunc_call_test_release(pt);
67 	}
68 	return ret;
69 }
70 
71 SEC("?tc")
72 int kfunc_call_test_get_mem_fail_use_after_free(struct __sk_buff *skb)
73 {
74 	struct prog_test_ref_kfunc *pt;
75 	unsigned long s = 0;
76 	int *p = NULL;
77 	int ret = 0;
78 
79 	pt = bpf_kfunc_call_test_acquire(&s);
80 	if (pt) {
81 		p = bpf_kfunc_call_test_get_rdwr_mem(pt, 2 * sizeof(int));
82 		if (p) {
83 			p[0] = 42;
84 			ret = p[1]; /* 108 */
85 		} else {
86 			ret = -1;
87 		}
88 
89 		bpf_kfunc_call_test_release(pt);
90 	}
91 	if (p)
92 		ret = p[0]; /* p is not valid anymore */
93 
94 	return ret;
95 }
96 
97 SEC("?tc")
98 int kfunc_call_test_get_mem_fail_oob(struct __sk_buff *skb)
99 {
100 	struct prog_test_ref_kfunc *pt;
101 	unsigned long s = 0;
102 	int *p = NULL;
103 	int ret = 0;
104 
105 	pt = bpf_kfunc_call_test_acquire(&s);
106 	if (pt) {
107 		p = bpf_kfunc_call_test_get_rdonly_mem(pt, 2 * sizeof(int));
108 		if (p)
109 			ret = p[2 * sizeof(int)]; /* oob access, so -EACCES */
110 		else
111 			ret = -1;
112 
113 		bpf_kfunc_call_test_release(pt);
114 	}
115 	return ret;
116 }
117 
118 SEC("?tc")
119 int kfunc_call_test_get_mem_fail_zero_size(struct __sk_buff *skb)
120 {
121 	struct prog_test_ref_kfunc *pt;
122 	unsigned long s = 0;
123 	int *p = NULL;
124 	int ret = 0;
125 
126 	pt = bpf_kfunc_call_test_acquire(&s);
127 	if (pt) {
128 		/*
129 		 * An explicit rdwr_buf_size of 0 gives R0 a zero-sized buffer,
130 		 * so any access is out of bounds, hence -EACCES. Previously the
131 		 * verifier treated a zero size as "no size argument" and sized
132 		 * R0 after the pointed-to return type, wrongly allowing the read.
133 		 */
134 		p = bpf_kfunc_call_test_get_rdwr_mem(pt, 0);
135 		if (p)
136 			ret = p[0];
137 		else
138 			ret = -1;
139 
140 		bpf_kfunc_call_test_release(pt);
141 	}
142 	return ret;
143 }
144 
145 SEC("?tc")
146 int kfunc_call_test_get_mem_fail_oversized(struct __sk_buff *skb)
147 {
148 	struct prog_test_ref_kfunc *pt;
149 	unsigned long s = 0;
150 	int *p = NULL;
151 	int ret = 0;
152 
153 	pt = bpf_kfunc_call_test_acquire(&s);
154 	if (pt) {
155 		/*
156 		 * rdwr_buf_size is a const int, so a C literal is narrowed to
157 		 * 32 bits before the call. Force the full 64-bit value 2^64 - 192
158 		 * (0xffffffffffffff40, > U32_MAX) into the argument register with
159 		 * a 64-bit immediate load. The verifier records r0_size from the
160 		 * full register value and must reject it before that value is
161 		 * truncated into R0's u32 mem_size.
162 		 */
163 		asm volatile (
164 			"r1 = %[pt];"
165 			"r2 = %[oversized] ll;"
166 			"call %[get_rdwr_mem];"
167 			"%[p] = r0;"
168 			: [p] "=r"(p)
169 			: [pt] "r"(pt),
170 			  [oversized] "i"(0xffffffffffffff40LL),
171 			  [get_rdwr_mem] "i"(bpf_kfunc_call_test_get_rdwr_mem)
172 			: "r0", "r1", "r2", "r3", "r4", "r5");
173 		bpf_kfunc_call_test_release(pt);
174 	}
175 	return ret;
176 }
177 
178 int not_const_size = 2 * sizeof(int);
179 
180 SEC("?tc")
181 int kfunc_call_test_get_mem_fail_not_const(struct __sk_buff *skb)
182 {
183 	struct prog_test_ref_kfunc *pt;
184 	unsigned long s = 0;
185 	int *p = NULL;
186 	int ret = 0;
187 
188 	pt = bpf_kfunc_call_test_acquire(&s);
189 	if (pt) {
190 		p = bpf_kfunc_call_test_get_rdonly_mem(pt, not_const_size); /* non const size, -EINVAL */
191 		if (p)
192 			ret = p[0];
193 		else
194 			ret = -1;
195 
196 		bpf_kfunc_call_test_release(pt);
197 	}
198 	return ret;
199 }
200 
201 SEC("?tc")
202 int kfunc_call_test_mem_acquire_fail(struct __sk_buff *skb)
203 {
204 	struct prog_test_ref_kfunc *pt;
205 	unsigned long s = 0;
206 	int *p = NULL;
207 	int ret = 0;
208 
209 	pt = bpf_kfunc_call_test_acquire(&s);
210 	if (pt) {
211 		/* we are failing on this one, because we are not acquiring a PTR_TO_BTF_ID (a struct ptr) */
212 		p = bpf_kfunc_call_test_acq_rdonly_mem(pt, 2 * sizeof(int));
213 		if (p)
214 			ret = p[0];
215 		else
216 			ret = -1;
217 
218 		bpf_kfunc_call_int_mem_release(p);
219 
220 		bpf_kfunc_call_test_release(pt);
221 	}
222 	return ret;
223 }
224 
225 SEC("?tc")
226 int kfunc_call_test_pointer_arg_type_mismatch(struct __sk_buff *skb)
227 {
228 	bpf_kfunc_call_test_pass_ctx((void *)10);
229 	return 0;
230 }
231 
232 char _license[] SEC("license") = "GPL";
233