File Index
Files and directories
Sign in
FILE

verifier_gotox.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/progs/verifier_gotox.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2025 Isovalent */
  3
  4#include <linux/bpf.h>
  5#include <bpf/bpf_helpers.h>
  6#include "bpf_misc.h"
  7#include "../../../include/linux/filter.h"
  8
  9#if defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)
 10
 11#define DEFINE_SIMPLE_JUMP_TABLE_PROG(NAME, SRC_REG, OFF, IMM, OUTCOME)	\
 12									\
 13	SEC("socket")							\
 14	OUTCOME								\
 15	__naked void jump_table_ ## NAME(void)				\
 16	{								\
 17		asm volatile ("						\
 18		.pushsection .jumptables,\"\",@progbits;		\
 19	jt0_%=:								\
 20		.quad ret0_%= - socket;					\
 21		.quad ret1_%= - socket;					\
 22		.size jt0_%=, 16;					\
 23		.global jt0_%=;						\
 24		.popsection;						\
 25									\
 26		r0 = jt0_%= ll;						\
 27		r0 += 8;						\
 28		r0 = *(u64 *)(r0 + 0);					\
 29		.8byte %[gotox_r0];					\
 30		ret0_%=:						\
 31		r0 = 0;							\
 32		exit;							\
 33		ret1_%=:						\
 34		r0 = 1;							\
 35		exit;							\
 36	"	:							\
 37		: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, (SRC_REG), (OFF) , (IMM))) \
 38		: __clobber_all);					\
 39	}
 40
 41/*
 42 * The first program which doesn't use reserved fields
 43 * loads and works properly. The rest fail to load.
 44 */
 45DEFINE_SIMPLE_JUMP_TABLE_PROG(ok,                          BPF_REG_0, 0, 0, __success __retval(1))
 46DEFINE_SIMPLE_JUMP_TABLE_PROG(reserved_field_src_reg,      BPF_REG_1, 0, 0, __failure __msg("BPF_JA|BPF_X uses reserved fields"))
 47DEFINE_SIMPLE_JUMP_TABLE_PROG(reserved_field_non_zero_off, BPF_REG_0, 1, 0, __failure __msg("BPF_JA|BPF_X uses reserved fields"))
 48DEFINE_SIMPLE_JUMP_TABLE_PROG(reserved_field_non_zero_imm, BPF_REG_0, 0, 1, __failure __msg("BPF_JA|BPF_X uses reserved fields"))
 49
 50/*
 51 * Gotox is forbidden when there is no jump table loaded
 52 * which points to the sub-function where the gotox is used
 53 */
 54SEC("socket")
 55__failure __msg("no jump tables found for subprog starting at 0")
 56__naked void jump_table_no_jump_table(void)
 57{
 58	asm volatile ("						\
 59	.8byte %[gotox_r0];					\
 60	r0 = 1;							\
 61	exit;							\
 62"	:							\
 63	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
 64	: __clobber_all);
 65}
 66
 67/*
 68 * Incorrect type of the target register, only PTR_TO_INSN allowed
 69 */
 70SEC("socket")
 71__failure __msg("R1 has type scalar, expected PTR_TO_INSN")
 72__naked void jump_table_incorrect_dst_reg_type(void)
 73{
 74	asm volatile ("						\
 75	.pushsection .jumptables,\"\",@progbits;		\
 76jt0_%=:								\
 77	.quad ret0_%= - socket;					\
 78	.quad ret1_%= - socket;					\
 79	.size jt0_%=, 16;					\
 80	.global jt0_%=;						\
 81	.popsection;						\
 82								\
 83	r0 = jt0_%= ll;						\
 84	r0 += 8;						\
 85	r0 = *(u64 *)(r0 + 0);					\
 86	r1 = 42;						\
 87	.8byte %[gotox_r1];					\
 88	ret0_%=:						\
 89	r0 = 0;							\
 90	exit;							\
 91	ret1_%=:						\
 92	r0 = 1;							\
 93	exit;							\
 94"	:							\
 95	: __imm_insn(gotox_r1, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_1, 0, 0 , 0))
 96	: __clobber_all);
 97}
 98
 99#define DEFINE_INVALID_SIZE_PROG(READ_SIZE, OUTCOME)			\
100									\
101	SEC("socket")							\
102	OUTCOME								\
103	__naked void jump_table_invalid_read_size_ ## READ_SIZE(void)	\
104	{								\
105		asm volatile ("						\
106		.pushsection .jumptables,\"\",@progbits;		\
107	jt0_%=:								\
108		.quad ret0_%= - socket;					\
109		.quad ret1_%= - socket;					\
110		.size jt0_%=, 16;					\
111		.global jt0_%=;						\
112		.popsection;						\
113									\
114		r0 = jt0_%= ll;						\
115		r0 += 8;						\
116		r0 = *(" #READ_SIZE " *)(r0 + 0);			\
117		.8byte %[gotox_r0];					\
118		ret0_%=:						\
119		r0 = 0;							\
120		exit;							\
121		ret1_%=:						\
122		r0 = 1;							\
123		exit;							\
124	"	:							\
125		: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0)) \
126		: __clobber_all);					\
127	}
128
129DEFINE_INVALID_SIZE_PROG(u32, __failure __msg("Invalid read of 4 bytes from insn_array"))
130DEFINE_INVALID_SIZE_PROG(u16, __failure __msg("Invalid read of 2 bytes from insn_array"))
131DEFINE_INVALID_SIZE_PROG(u8,  __failure __msg("Invalid read of 1 bytes from insn_array"))
132
133SEC("socket")
134__failure __msg("misaligned value access off 0+1+0 size 8")
135__naked void jump_table_misaligned_access(void)
136{
137	asm volatile ("						\
138	.pushsection .jumptables,\"\",@progbits;		\
139jt0_%=:								\
140	.quad ret0_%= - socket;					\
141	.quad ret1_%= - socket;					\
142	.size jt0_%=, 16;					\
143	.global jt0_%=;						\
144	.popsection;						\
145								\
146	r0 = jt0_%= ll;						\
147	r0 += 1;						\
148	r0 = *(u64 *)(r0 + 0);					\
149	.8byte %[gotox_r0];					\
150	ret0_%=:						\
151	r0 = 0;							\
152	exit;							\
153	ret1_%=:						\
154	r0 = 1;							\
155	exit;							\
156"	:							\
157	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
158	: __clobber_all);
159}
160
161SEC("socket")
162__failure __msg("invalid access to map value, value_size=16 off=24 size=8")
163__naked void jump_table_invalid_mem_acceess_pos(void)
164{
165	asm volatile ("						\
166	.pushsection .jumptables,\"\",@progbits;		\
167jt0_%=:								\
168	.quad ret0_%= - socket;					\
169	.quad ret1_%= - socket;					\
170	.size jt0_%=, 16;					\
171	.global jt0_%=;						\
172	.popsection;						\
173								\
174	r0 = jt0_%= ll;						\
175	r0 += 24;						\
176	r0 = *(u64 *)(r0 + 0);					\
177	.8byte %[gotox_r0];					\
178	ret0_%=:						\
179	r0 = 0;							\
180	exit;							\
181	ret1_%=:						\
182	r0 = 1;							\
183	exit;							\
184"	:							\
185	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
186	: __clobber_all);
187}
188
189SEC("socket")
190__failure __msg("invalid access to map value, value_size=16 off=-24 size=8")
191__naked void jump_table_invalid_mem_acceess_neg(void)
192{
193	asm volatile ("						\
194	.pushsection .jumptables,\"\",@progbits;		\
195jt0_%=:								\
196	.quad ret0_%= - socket;					\
197	.quad ret1_%= - socket;					\
198	.size jt0_%=, 16;					\
199	.global jt0_%=;						\
200	.popsection;						\
201								\
202	r0 = jt0_%= ll;						\
203	r0 -= 24;						\
204	r0 = *(u64 *)(r0 + 0);					\
205	.8byte %[gotox_r0];					\
206	ret0_%=:						\
207	r0 = 0;							\
208	exit;							\
209	ret1_%=:						\
210	r0 = 1;							\
211	exit;							\
212"	:							\
213	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
214	: __clobber_all);
215}
216
217SEC("socket")
218__success __retval(1)
219__naked void jump_table_add_sub_ok(void)
220{
221	asm volatile ("						\
222	.pushsection .jumptables,\"\",@progbits;		\
223jt0_%=:								\
224	.quad ret0_%= - socket;					\
225	.quad ret1_%= - socket;					\
226	.size jt0_%=, 16;					\
227	.global jt0_%=;						\
228	.popsection;						\
229								\
230	r0 = jt0_%= ll;						\
231	r0 -= 24;						\
232	r0 += 32;						\
233	r0 = *(u64 *)(r0 + 0);					\
234	.8byte %[gotox_r0];					\
235	ret0_%=:						\
236	r0 = 0;							\
237	exit;							\
238	ret1_%=:						\
239	r0 = 1;							\
240	exit;							\
241"	:							\
242	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
243	: __clobber_all);
244}
245
246SEC("socket")
247__failure __msg("write into map forbidden, value_size=16 off=8 size=8")
248__naked void jump_table_no_writes(void)
249{
250	asm volatile ("						\
251	.pushsection .jumptables,\"\",@progbits;		\
252jt0_%=:								\
253	.quad ret0_%= - socket;					\
254	.quad ret1_%= - socket;					\
255	.size jt0_%=, 16;					\
256	.global jt0_%=;						\
257	.popsection;						\
258								\
259	r0 = jt0_%= ll;						\
260	r0 += 8;						\
261	r1 = 0xbeef;						\
262	*(u64 *)(r0 + 0) = r1;					\
263	.8byte %[gotox_r0];					\
264	ret0_%=:						\
265	r0 = 0;							\
266	exit;							\
267	ret1_%=:						\
268	r0 = 1;							\
269	exit;							\
270"	:							\
271	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
272	: __clobber_all);
273}
274
275#define DEFINE_JUMP_TABLE_USE_REG(REG)					\
276	SEC("socket")							\
277	__success __retval(1)						\
278	__naked void jump_table_use_reg_r ## REG(void)			\
279	{								\
280		asm volatile ("						\
281		.pushsection .jumptables,\"\",@progbits;		\
282	jt0_%=:								\
283		.quad ret0_%= - socket;					\
284		.quad ret1_%= - socket;					\
285		.size jt0_%=, 16;					\
286		.global jt0_%=;						\
287		.popsection;						\
288									\
289		r0 = jt0_%= ll;						\
290		r0 += 8;						\
291		r" #REG " = *(u64 *)(r0 + 0);				\
292		.8byte %[gotox_rX];					\
293		ret0_%=:						\
294		r0 = 0;							\
295		exit;							\
296		ret1_%=:						\
297		r0 = 1;							\
298		exit;							\
299	"	:							\
300		: __imm_insn(gotox_rX, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_ ## REG, 0, 0 , 0)) \
301		: __clobber_all);					\
302	}
303
304DEFINE_JUMP_TABLE_USE_REG(0)
305DEFINE_JUMP_TABLE_USE_REG(1)
306DEFINE_JUMP_TABLE_USE_REG(2)
307DEFINE_JUMP_TABLE_USE_REG(3)
308DEFINE_JUMP_TABLE_USE_REG(4)
309DEFINE_JUMP_TABLE_USE_REG(5)
310DEFINE_JUMP_TABLE_USE_REG(6)
311DEFINE_JUMP_TABLE_USE_REG(7)
312DEFINE_JUMP_TABLE_USE_REG(8)
313DEFINE_JUMP_TABLE_USE_REG(9)
314
315__used static int test_subprog(void)
316{
317	return 0;
318}
319
320SEC("socket")
321__failure __msg("jump table for insn 4 points outside of the subprog [0,10]")
322__naked void jump_table_outside_subprog(void)
323{
324	asm volatile ("						\
325	.pushsection .jumptables,\"\",@progbits;		\
326jt0_%=:								\
327	.quad ret0_%= - socket;					\
328	.quad ret1_%= - socket;					\
329	.quad ret_out_%= - socket;				\
330	.size jt0_%=, 24;					\
331	.global jt0_%=;						\
332	.popsection;						\
333								\
334	r0 = jt0_%= ll;						\
335	r0 += 8;						\
336	r0 = *(u64 *)(r0 + 0);					\
337	.8byte %[gotox_r0];					\
338	ret0_%=:						\
339	r0 = 0;							\
340	exit;							\
341	ret1_%=:						\
342	r0 = 1;							\
343	call test_subprog;					\
344	exit;							\
345	ret_out_%=:						\
346"	:							\
347	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
348	: __clobber_all);
349}
350
351SEC("socket")
352__success __retval(1)
353__naked void jump_table_contains_non_unique_values(void)
354{
355	asm volatile ("						\
356	.pushsection .jumptables,\"\",@progbits;		\
357jt0_%=:								\
358	.quad ret0_%= - socket;					\
359	.quad ret1_%= - socket;					\
360	.quad ret0_%= - socket;					\
361	.quad ret1_%= - socket;					\
362	.quad ret0_%= - socket;					\
363	.quad ret1_%= - socket;					\
364	.quad ret0_%= - socket;					\
365	.quad ret1_%= - socket;					\
366	.quad ret0_%= - socket;					\
367	.quad ret1_%= - socket;					\
368	.size jt0_%=, 80;					\
369	.global jt0_%=;						\
370	.popsection;						\
371								\
372	r0 = jt0_%= ll;						\
373	r0 += 8;						\
374	r0 = *(u64 *)(r0 + 0);					\
375	.8byte %[gotox_r0];					\
376	ret0_%=:						\
377	r0 = 0;							\
378	exit;							\
379	ret1_%=:						\
380	r0 = 1;							\
381	exit;							\
382"	:							\
383	: __imm_insn(gotox_r0, BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_0, 0, 0 , 0))
384	: __clobber_all);
385}
386
387#endif /* __TARGET_ARCH_x86 || __TARGET_ARCH_arm64 */
388
389char _license[] SEC("license") = "GPL";
~/ Read-only file preview.