Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 389 lines 10 kB view raw
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) || defined(__TARGET_ARCH_powerpc) 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 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("R0 min value is negative") 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 || __TARGET_ARCH_powerpc*/ 388 389char _license[] SEC("license") = "GPL";