1// SPDX-License-Identifier: GPL-2.0 2/* Converted from tools/testing/selftests/bpf/verifier/stack_ptr.c */ 3 4#include <linux/bpf.h> 5#include <bpf/bpf_helpers.h> 6#include <limits.h> 7#include "bpf_misc.h" 8 9#define MAX_ENTRIES 11 10 11struct test_val { 12 unsigned int index; 13 int foo[MAX_ENTRIES]; 14}; 15 16struct { 17 __uint(type, BPF_MAP_TYPE_ARRAY); 18 __uint(max_entries, 1); 19 __type(key, int); 20 __type(value, struct test_val); 21} map_array_48b SEC(".maps"); 22 23SEC("socket") 24__description("PTR_TO_STACK store/load") 25__success __success_unpriv __retval(0xfaceb00c) 26__naked void ptr_to_stack_store_load(void) 27{ 28 asm volatile (" \ 29 r1 = r10; \ 30 r1 += -10; \ 31 r0 = 0xfaceb00c; \ 32 *(u64*)(r1 + 2) = r0; \ 33 r0 = *(u64*)(r1 + 2); \ 34 exit; \ 35" ::: __clobber_all); 36} 37 38SEC("socket") 39__description("PTR_TO_STACK store/load - bad alignment on off") 40__failure __msg("misaligned stack access off 0+-8+2 size 8") 41__failure_unpriv 42__naked void load_bad_alignment_on_off(void) 43{ 44 asm volatile (" \ 45 r1 = r10; \ 46 r1 += -8; \ 47 r0 = 0xfaceb00c; \ 48 *(u64*)(r1 + 2) = r0; \ 49 r0 = *(u64*)(r1 + 2); \ 50 exit; \ 51" ::: __clobber_all); 52} 53 54SEC("socket") 55__description("PTR_TO_STACK store/load - bad alignment on reg") 56__failure __msg("misaligned stack access off 0+-10+8 size 8") 57__failure_unpriv 58__naked void load_bad_alignment_on_reg(void) 59{ 60 asm volatile (" \ 61 r1 = r10; \ 62 r1 += -10; \ 63 r0 = 0xfaceb00c; \ 64 *(u64*)(r1 + 8) = r0; \ 65 r0 = *(u64*)(r1 + 8); \ 66 exit; \ 67" ::: __clobber_all); 68} 69 70SEC("socket") 71__description("PTR_TO_STACK store/load - out of bounds low") 72__failure __msg("invalid write to stack R1 off=-79992 size=8") 73__msg_unpriv("R1 stack pointer arithmetic goes out of range") 74__naked void load_out_of_bounds_low(void) 75{ 76 asm volatile (" \ 77 r1 = r10; \ 78 r1 += -80000; \ 79 r0 = 0xfaceb00c; \ 80 *(u64*)(r1 + 8) = r0; \ 81 r0 = *(u64*)(r1 + 8); \ 82 exit; \ 83" ::: __clobber_all); 84} 85 86SEC("socket") 87__description("PTR_TO_STACK store/load - out of bounds high") 88__failure __msg("invalid write to stack R1 off=0 size=8") 89__failure_unpriv 90__naked void load_out_of_bounds_high(void) 91{ 92 asm volatile (" \ 93 r1 = r10; \ 94 r1 += -8; \ 95 r0 = 0xfaceb00c; \ 96 *(u64*)(r1 + 8) = r0; \ 97 r0 = *(u64*)(r1 + 8); \ 98 exit; \ 99" ::: __clobber_all); 100} 101 102SEC("socket") 103__description("PTR_TO_STACK check high 1") 104__success __success_unpriv __retval(42) 105__naked void to_stack_check_high_1(void) 106{ 107 asm volatile (" \ 108 r1 = r10; \ 109 r1 += -1; \ 110 r0 = 42; \ 111 *(u8*)(r1 + 0) = r0; \ 112 r0 = *(u8*)(r1 + 0); \ 113 exit; \ 114" ::: __clobber_all); 115} 116 117SEC("socket") 118__description("PTR_TO_STACK check high 2") 119__success __success_unpriv __retval(42) 120__naked void to_stack_check_high_2(void) 121{ 122 asm volatile (" \ 123 r1 = r10; \ 124 r0 = 42; \ 125 *(u8*)(r1 - 1) = r0; \ 126 r0 = *(u8*)(r1 - 1); \ 127 exit; \ 128" ::: __clobber_all); 129} 130 131SEC("socket") 132__description("PTR_TO_STACK check high 3") 133__success __failure_unpriv 134__msg_unpriv("R1 stack pointer arithmetic goes out of range") 135__retval(42) 136__naked void to_stack_check_high_3(void) 137{ 138 asm volatile (" \ 139 r1 = r10; \ 140 r1 += 0; \ 141 r0 = 42; \ 142 *(u8*)(r1 - 1) = r0; \ 143 r0 = *(u8*)(r1 - 1); \ 144 exit; \ 145" ::: __clobber_all); 146} 147 148SEC("socket") 149__description("PTR_TO_STACK check high 4") 150__failure __msg("invalid write to stack R1 off=0 size=1") 151__msg_unpriv("R1 stack pointer arithmetic goes out of range") 152__naked void to_stack_check_high_4(void) 153{ 154 asm volatile (" \ 155 r1 = r10; \ 156 r1 += 0; \ 157 r0 = 42; \ 158 *(u8*)(r1 + 0) = r0; \ 159 r0 = *(u8*)(r1 + 0); \ 160 exit; \ 161" ::: __clobber_all); 162} 163 164SEC("socket") 165__description("PTR_TO_STACK check high 5") 166__failure __msg("invalid write to stack R1") 167__msg_unpriv("R1 stack pointer arithmetic goes out of range") 168__naked void to_stack_check_high_5(void) 169{ 170 asm volatile (" \ 171 r1 = r10; \ 172 r1 += %[__imm_0]; \ 173 r0 = 42; \ 174 *(u8*)(r1 + 0) = r0; \ 175 r0 = *(u8*)(r1 + 0); \ 176 exit; \ 177" : 178 : __imm_const(__imm_0, (1 << 29) - 1) 179 : __clobber_all); 180} 181 182SEC("socket") 183__description("PTR_TO_STACK check high 6") 184__failure __msg("invalid write to stack") 185__msg_unpriv("R1 stack pointer arithmetic goes out of range") 186__naked void to_stack_check_high_6(void) 187{ 188 asm volatile (" \ 189 r1 = r10; \ 190 r1 += %[__imm_0]; \ 191 r0 = 42; \ 192 *(u8*)(r1 + %[shrt_max]) = r0; \ 193 r0 = *(u8*)(r1 + %[shrt_max]); \ 194 exit; \ 195" : 196 : __imm_const(__imm_0, (1 << 29) - 1), 197 __imm_const(shrt_max, SHRT_MAX) 198 : __clobber_all); 199} 200 201SEC("socket") 202__description("PTR_TO_STACK check high 7") 203__failure __msg("fp pointer offset") 204__msg_unpriv("R1 stack pointer arithmetic goes out of range") 205__naked void to_stack_check_high_7(void) 206{ 207 asm volatile (" \ 208 r1 = r10; \ 209 r1 += %[__imm_0]; \ 210 r1 += %[__imm_0]; \ 211 r0 = 42; \ 212 *(u8*)(r1 + %[shrt_max]) = r0; \ 213 r0 = *(u8*)(r1 + %[shrt_max]); \ 214 exit; \ 215" : 216 : __imm_const(__imm_0, (1 << 29) - 1), 217 __imm_const(shrt_max, SHRT_MAX) 218 : __clobber_all); 219} 220 221SEC("socket") 222__description("PTR_TO_STACK check low 1") 223__success __success_unpriv __retval(42) 224__naked void to_stack_check_low_1(void) 225{ 226 asm volatile (" \ 227 r1 = r10; \ 228 r1 += -512; \ 229 r0 = 42; \ 230 *(u8*)(r1 + 0) = r0; \ 231 r0 = *(u8*)(r1 + 0); \ 232 exit; \ 233" ::: __clobber_all); 234} 235 236SEC("socket") 237__description("PTR_TO_STACK check low 2") 238__success __failure_unpriv 239__msg_unpriv("R1 stack pointer arithmetic goes out of range") 240__retval(42) 241__naked void to_stack_check_low_2(void) 242{ 243 asm volatile (" \ 244 r1 = r10; \ 245 r1 += -513; \ 246 r0 = 42; \ 247 *(u8*)(r1 + 1) = r0; \ 248 r0 = *(u8*)(r1 + 1); \ 249 exit; \ 250" ::: __clobber_all); 251} 252 253SEC("socket") 254__description("PTR_TO_STACK check low 3") 255__failure __msg("invalid write to stack R1 off=-513 size=1") 256__msg_unpriv("R1 stack pointer arithmetic goes out of range") 257__naked void to_stack_check_low_3(void) 258{ 259 asm volatile (" \ 260 r1 = r10; \ 261 r1 += -513; \ 262 r0 = 42; \ 263 *(u8*)(r1 + 0) = r0; \ 264 r0 = *(u8*)(r1 + 0); \ 265 exit; \ 266" ::: __clobber_all); 267} 268 269SEC("socket") 270__description("PTR_TO_STACK check low 4") 271__failure __msg("math between fp pointer") 272__failure_unpriv 273__naked void to_stack_check_low_4(void) 274{ 275 asm volatile (" \ 276 r1 = r10; \ 277 r1 += %[int_min]; \ 278 r0 = 42; \ 279 *(u8*)(r1 + 0) = r0; \ 280 r0 = *(u8*)(r1 + 0); \ 281 exit; \ 282" : 283 : __imm_const(int_min, INT_MIN) 284 : __clobber_all); 285} 286 287SEC("socket") 288__description("PTR_TO_STACK check low 5") 289__failure __msg("invalid write to stack") 290__msg_unpriv("R1 stack pointer arithmetic goes out of range") 291__naked void to_stack_check_low_5(void) 292{ 293 asm volatile (" \ 294 r1 = r10; \ 295 r1 += %[__imm_0]; \ 296 r0 = 42; \ 297 *(u8*)(r1 + 0) = r0; \ 298 r0 = *(u8*)(r1 + 0); \ 299 exit; \ 300" : 301 : __imm_const(__imm_0, -((1 << 29) - 1)) 302 : __clobber_all); 303} 304 305SEC("socket") 306__description("PTR_TO_STACK check low 6") 307__failure __msg("invalid write to stack") 308__msg_unpriv("R1 stack pointer arithmetic goes out of range") 309__naked void to_stack_check_low_6(void) 310{ 311 asm volatile (" \ 312 r1 = r10; \ 313 r1 += %[__imm_0]; \ 314 r0 = 42; \ 315 *(u8*)(r1 %[shrt_min]) = r0; \ 316 r0 = *(u8*)(r1 %[shrt_min]); \ 317 exit; \ 318" : 319 : __imm_const(__imm_0, -((1 << 29) - 1)), 320 __imm_const(shrt_min, SHRT_MIN) 321 : __clobber_all); 322} 323 324SEC("socket") 325__description("PTR_TO_STACK check low 7") 326__failure __msg("fp pointer offset") 327__msg_unpriv("R1 stack pointer arithmetic goes out of range") 328__naked void to_stack_check_low_7(void) 329{ 330 asm volatile (" \ 331 r1 = r10; \ 332 r1 += %[__imm_0]; \ 333 r1 += %[__imm_0]; \ 334 r0 = 42; \ 335 *(u8*)(r1 %[shrt_min]) = r0; \ 336 r0 = *(u8*)(r1 %[shrt_min]); \ 337 exit; \ 338" : 339 : __imm_const(__imm_0, -((1 << 29) - 1)), 340 __imm_const(shrt_min, SHRT_MIN) 341 : __clobber_all); 342} 343 344SEC("socket") 345__description("PTR_TO_STACK mixed reg/k, 1") 346__success __success_unpriv __retval(42) 347__naked void stack_mixed_reg_k_1(void) 348{ 349 asm volatile (" \ 350 r1 = r10; \ 351 r1 += -3; \ 352 r2 = -3; \ 353 r1 += r2; \ 354 r0 = 42; \ 355 *(u8*)(r1 + 0) = r0; \ 356 r0 = *(u8*)(r1 + 0); \ 357 exit; \ 358" ::: __clobber_all); 359} 360 361SEC("socket") 362__description("PTR_TO_STACK mixed reg/k, 2") 363__success __success_unpriv __retval(42) 364__naked void stack_mixed_reg_k_2(void) 365{ 366 asm volatile (" \ 367 r0 = 0; \ 368 *(u64*)(r10 - 8) = r0; \ 369 r0 = 0; \ 370 *(u64*)(r10 - 16) = r0; \ 371 r1 = r10; \ 372 r1 += -3; \ 373 r2 = -3; \ 374 r1 += r2; \ 375 r0 = 42; \ 376 *(u8*)(r1 + 0) = r0; \ 377 r5 = r10; \ 378 r0 = *(u8*)(r5 - 6); \ 379 exit; \ 380" ::: __clobber_all); 381} 382 383SEC("socket") 384__description("PTR_TO_STACK mixed reg/k, 3") 385__success __success_unpriv __retval(-3) 386__naked void stack_mixed_reg_k_3(void) 387{ 388 asm volatile (" \ 389 r1 = r10; \ 390 r1 += -3; \ 391 r2 = -3; \ 392 r1 += r2; \ 393 r0 = 42; \ 394 *(u8*)(r1 + 0) = r0; \ 395 r0 = r2; \ 396 exit; \ 397" ::: __clobber_all); 398} 399 400SEC("socket") 401__description("PTR_TO_STACK reg") 402__success __success_unpriv __retval(42) 403__naked void ptr_to_stack_reg(void) 404{ 405 asm volatile (" \ 406 r1 = r10; \ 407 r2 = -3; \ 408 r1 += r2; \ 409 r0 = 42; \ 410 *(u8*)(r1 + 0) = r0; \ 411 r0 = *(u8*)(r1 + 0); \ 412 exit; \ 413" ::: __clobber_all); 414} 415 416SEC("socket") 417__description("stack pointer arithmetic") 418__success __success_unpriv __retval(0) 419__naked void stack_pointer_arithmetic(void) 420{ 421 asm volatile (" \ 422 r1 = 4; \ 423 goto l0_%=; \ 424l0_%=: r7 = r10; \ 425 r7 += -10; \ 426 r7 += -10; \ 427 r2 = r7; \ 428 r2 += r1; \ 429 r0 = 0; \ 430 *(u32*)(r2 + 4) = r0; \ 431 r2 = r7; \ 432 r2 += 8; \ 433 r0 = 0; \ 434 *(u32*)(r2 + 4) = r0; \ 435 r0 = 0; \ 436 exit; \ 437" ::: __clobber_all); 438} 439 440SEC("tc") 441__description("store PTR_TO_STACK in R10 to array map using BPF_B") 442__success __retval(42) 443__naked void array_map_using_bpf_b(void) 444{ 445 asm volatile (" \ 446 /* Load pointer to map. */ \ 447 r2 = r10; \ 448 r2 += -8; \ 449 r1 = 0; \ 450 *(u64*)(r2 + 0) = r1; \ 451 r1 = %[map_array_48b] ll; \ 452 call %[bpf_map_lookup_elem]; \ 453 if r0 != 0 goto l0_%=; \ 454 r0 = 2; \ 455 exit; \ 456l0_%=: r1 = r0; \ 457 /* Copy R10 to R9. */ \ 458 r9 = r10; \ 459 /* Pollute other registers with unaligned values. */\ 460 r2 = -1; \ 461 r3 = -1; \ 462 r4 = -1; \ 463 r5 = -1; \ 464 r6 = -1; \ 465 r7 = -1; \ 466 r8 = -1; \ 467 /* Store both R9 and R10 with BPF_B and read back. */\ 468 *(u8*)(r1 + 0) = r10; \ 469 r2 = *(u8*)(r1 + 0); \ 470 *(u8*)(r1 + 0) = r9; \ 471 r3 = *(u8*)(r1 + 0); \ 472 /* Should read back as same value. */ \ 473 if r2 == r3 goto l1_%=; \ 474 r0 = 1; \ 475 exit; \ 476l1_%=: r0 = 42; \ 477 exit; \ 478" : 479 : __imm(bpf_map_lookup_elem), 480 __imm_addr(map_array_48b) 481 : __clobber_all); 482} 483 484char _license[] SEC("license") = "GPL"; 485