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 11 struct test_val { 12 unsigned int index; 13 int foo[MAX_ENTRIES]; 14 }; 15 16 struct { 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 23 SEC("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 38 SEC("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 54 SEC("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 70 SEC("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 86 SEC("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 102 SEC("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 117 SEC("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 131 SEC("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 148 SEC("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 164 SEC("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 182 SEC("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 201 SEC("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 221 SEC("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 236 SEC("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 253 SEC("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 269 SEC("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 287 SEC("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 305 SEC("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 324 SEC("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 344 SEC("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 361 SEC("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 383 SEC("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 400 SEC("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 416 SEC("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_%=; \ 424 l0_%=: 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 440 SEC("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; \ 456 l0_%=: 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; \ 476 l1_%=: r0 = 42; \ 477 exit; \ 478 " : 479 : __imm(bpf_map_lookup_elem), 480 __imm_addr(map_array_48b) 481 : __clobber_all); 482 } 483 484 char _license[] SEC("license") = "GPL"; 485