1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/unpriv.c */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "../../../include/linux/filter.h" 7 #include "bpf_misc.h" 8 9 extern const int bpf_prog_active __ksym; 10 11 #define BPF_SK_LOOKUP(func) \ 12 /* struct bpf_sock_tuple tuple = {} */ \ 13 "r2 = 0;" \ 14 "*(u32*)(r10 - 8) = r2;" \ 15 "*(u64*)(r10 - 16) = r2;" \ 16 "*(u64*)(r10 - 24) = r2;" \ 17 "*(u64*)(r10 - 32) = r2;" \ 18 "*(u64*)(r10 - 40) = r2;" \ 19 "*(u64*)(r10 - 48) = r2;" \ 20 /* sk = func(ctx, &tuple, sizeof tuple, 0, 0) */ \ 21 "r2 = r10;" \ 22 "r2 += -48;" \ 23 "r3 = %[sizeof_bpf_sock_tuple];"\ 24 "r4 = 0;" \ 25 "r5 = 0;" \ 26 "call %[" #func "];" 27 28 struct { 29 __uint(type, BPF_MAP_TYPE_HASH); 30 __uint(max_entries, 1); 31 __type(key, long long); 32 __type(value, long long); 33 } map_hash_8b SEC(".maps"); 34 35 void dummy_prog_42_socket(void); 36 void dummy_prog_24_socket(void); 37 void dummy_prog_loop1_socket(void); 38 39 struct { 40 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 41 __uint(max_entries, 4); 42 __uint(key_size, sizeof(int)); 43 __array(values, void (void)); 44 } map_prog1_socket SEC(".maps") = { 45 .values = { 46 [0] = (void *)&dummy_prog_42_socket, 47 [1] = (void *)&dummy_prog_loop1_socket, 48 [2] = (void *)&dummy_prog_24_socket, 49 }, 50 }; 51 52 SEC("socket") 53 __auxiliary __auxiliary_unpriv 54 __naked void dummy_prog_42_socket(void) 55 { 56 asm volatile ("r0 = 42; exit;"); 57 } 58 59 SEC("socket") 60 __auxiliary __auxiliary_unpriv 61 __naked void dummy_prog_24_socket(void) 62 { 63 asm volatile ("r0 = 24; exit;"); 64 } 65 66 SEC("socket") 67 __auxiliary __auxiliary_unpriv 68 __naked void dummy_prog_loop1_socket(void) 69 { 70 asm volatile (" \ 71 r3 = 1; \ 72 r2 = %[map_prog1_socket] ll; \ 73 call %[bpf_tail_call]; \ 74 r0 = 41; \ 75 exit; \ 76 " : 77 : __imm(bpf_tail_call), 78 __imm_addr(map_prog1_socket) 79 : __clobber_all); 80 } 81 82 SEC("socket") 83 __description("unpriv: pseudo btf id log masks address") 84 __success_unpriv 85 __msg_unpriv("0: (18) r1 = 0x0") 86 __not_msg_unpriv("0: (18) r1 = 0x{{[1-9a-f][0-9a-f]*}}") 87 __retval_unpriv(0) 88 __log_level(2) 89 __naked void pseudo_btf_id_log_masks_address(void) 90 { 91 asm volatile ("r1 = %[bpf_prog_active] ll;" 92 "r0 = 0;" 93 "exit;" 94 : 95 : __imm_addr(bpf_prog_active) 96 : __clobber_all); 97 } 98 99 SEC("socket") 100 __description("unpriv: return pointer") 101 __success __failure_unpriv __msg_unpriv("R0 leaks addr") 102 __retval(POINTER_VALUE) 103 __naked void unpriv_return_pointer(void) 104 { 105 asm volatile (" \ 106 r0 = r10; \ 107 exit; \ 108 " ::: __clobber_all); 109 } 110 111 SEC("socket") 112 __description("unpriv: add const to pointer") 113 __success __success_unpriv __retval(0) 114 __naked void unpriv_add_const_to_pointer(void) 115 { 116 asm volatile (" \ 117 r1 += 8; \ 118 r0 = 0; \ 119 exit; \ 120 " ::: __clobber_all); 121 } 122 123 SEC("socket") 124 __description("unpriv: add pointer to pointer") 125 __failure __msg("R1 pointer += pointer") 126 __failure_unpriv 127 __naked void unpriv_add_pointer_to_pointer(void) 128 { 129 asm volatile (" \ 130 r1 += r10; \ 131 r0 = 0; \ 132 exit; \ 133 " ::: __clobber_all); 134 } 135 136 SEC("socket") 137 __description("unpriv: neg pointer") 138 __success __failure_unpriv __msg_unpriv("R1 pointer arithmetic") 139 __retval(0) 140 __naked void unpriv_neg_pointer(void) 141 { 142 asm volatile (" \ 143 r1 = -r1; \ 144 r0 = 0; \ 145 exit; \ 146 " ::: __clobber_all); 147 } 148 149 SEC("socket") 150 __description("unpriv: cmp pointer with const") 151 __success __failure_unpriv __msg_unpriv("R1 pointer comparison") 152 __retval(0) 153 __naked void unpriv_cmp_pointer_with_const(void) 154 { 155 asm volatile (" \ 156 if r1 == 0 goto l0_%=; \ 157 l0_%=: r0 = 0; \ 158 exit; \ 159 " ::: __clobber_all); 160 } 161 162 SEC("socket") 163 __description("unpriv: cmp pointer with pointer") 164 __success __failure_unpriv __msg_unpriv("R10 pointer comparison") 165 __retval(0) 166 __naked void unpriv_cmp_pointer_with_pointer(void) 167 { 168 asm volatile (" \ 169 if r1 == r10 goto l0_%=; \ 170 l0_%=: r0 = 0; \ 171 exit; \ 172 " ::: __clobber_all); 173 } 174 175 SEC("tracepoint") 176 __description("unpriv: check that printk is disallowed") 177 __success 178 __naked void check_that_printk_is_disallowed(void) 179 { 180 asm volatile (" \ 181 r1 = 0; \ 182 *(u64*)(r10 - 8) = r1; \ 183 r1 = r10; \ 184 r1 += -8; \ 185 r2 = 8; \ 186 r3 = r1; \ 187 call %[bpf_trace_printk]; \ 188 r0 = 0; \ 189 exit; \ 190 " : 191 : __imm(bpf_trace_printk) 192 : __clobber_all); 193 } 194 195 SEC("socket") 196 __description("unpriv: pass pointer to helper function") 197 __success __failure_unpriv __msg_unpriv("R4 leaks addr") 198 __retval(0) 199 __naked void pass_pointer_to_helper_function(void) 200 { 201 asm volatile (" \ 202 r1 = 0; \ 203 *(u64*)(r10 - 8) = r1; \ 204 r2 = r10; \ 205 r2 += -8; \ 206 r1 = %[map_hash_8b] ll; \ 207 r3 = r2; \ 208 r4 = r2; \ 209 call %[bpf_map_update_elem]; \ 210 r0 = 0; \ 211 exit; \ 212 " : 213 : __imm(bpf_map_update_elem), 214 __imm_addr(map_hash_8b) 215 : __clobber_all); 216 } 217 218 SEC("socket") 219 __description("unpriv: indirectly pass pointer on stack to helper function") 220 __success __failure_unpriv 221 __msg_unpriv("invalid read from stack R2 off -8+0 size 8") 222 __retval(0) 223 __naked void on_stack_to_helper_function(void) 224 { 225 asm volatile (" \ 226 *(u64*)(r10 - 8) = r10; \ 227 r2 = r10; \ 228 r2 += -8; \ 229 r1 = %[map_hash_8b] ll; \ 230 call %[bpf_map_lookup_elem]; \ 231 r0 = 0; \ 232 exit; \ 233 " : 234 : __imm(bpf_map_lookup_elem), 235 __imm_addr(map_hash_8b) 236 : __clobber_all); 237 } 238 239 SEC("socket") 240 __description("unpriv: mangle pointer on stack 1") 241 __success __failure_unpriv __msg_unpriv("attempt to corrupt spilled") 242 __retval(0) 243 __naked void mangle_pointer_on_stack_1(void) 244 { 245 asm volatile (" \ 246 *(u64*)(r10 - 8) = r10; \ 247 r0 = 0; \ 248 *(u32*)(r10 - 8) = r0; \ 249 r0 = 0; \ 250 exit; \ 251 " ::: __clobber_all); 252 } 253 254 SEC("socket") 255 __description("unpriv: mangle pointer on stack 2") 256 __success __failure_unpriv __msg_unpriv("attempt to corrupt spilled") 257 __retval(0) 258 __naked void mangle_pointer_on_stack_2(void) 259 { 260 asm volatile (" \ 261 *(u64*)(r10 - 8) = r10; \ 262 r0 = 0; \ 263 *(u8*)(r10 - 1) = r0; \ 264 r0 = 0; \ 265 exit; \ 266 " ::: __clobber_all); 267 } 268 269 SEC("socket") 270 __description("unpriv: read pointer from stack in small chunks") 271 __failure __msg("invalid size") 272 __failure_unpriv 273 __naked void from_stack_in_small_chunks(void) 274 { 275 asm volatile (" \ 276 *(u64*)(r10 - 8) = r10; \ 277 r0 = *(u32*)(r10 - 8); \ 278 r0 = 0; \ 279 exit; \ 280 " ::: __clobber_all); 281 } 282 283 SEC("socket") 284 __description("unpriv: write pointer into ctx") 285 __failure __msg("invalid bpf_context access") 286 __failure_unpriv __msg_unpriv("R1 leaks addr") 287 __naked void unpriv_write_pointer_into_ctx(void) 288 { 289 asm volatile (" \ 290 *(u64*)(r1 + 0) = r1; \ 291 r0 = 0; \ 292 exit; \ 293 " ::: __clobber_all); 294 } 295 296 SEC("socket") 297 __description("unpriv: spill/fill of ctx") 298 __success __success_unpriv __retval(0) 299 __naked void unpriv_spill_fill_of_ctx(void) 300 { 301 asm volatile (" \ 302 r6 = r10; \ 303 r6 += -8; \ 304 *(u64*)(r6 + 0) = r1; \ 305 r1 = *(u64*)(r6 + 0); \ 306 r0 = 0; \ 307 exit; \ 308 " ::: __clobber_all); 309 } 310 311 SEC("tc") 312 __description("unpriv: spill/fill of ctx 2") 313 __success __retval(0) 314 __naked void spill_fill_of_ctx_2(void) 315 { 316 asm volatile (" \ 317 r6 = r10; \ 318 r6 += -8; \ 319 *(u64*)(r6 + 0) = r1; \ 320 r1 = *(u64*)(r6 + 0); \ 321 call %[bpf_get_hash_recalc]; \ 322 r0 = 0; \ 323 exit; \ 324 " : 325 : __imm(bpf_get_hash_recalc) 326 : __clobber_all); 327 } 328 329 SEC("tc") 330 __description("unpriv: spill/fill of ctx 3") 331 __failure __msg("R1 type=fp expected=ctx") 332 __naked void spill_fill_of_ctx_3(void) 333 { 334 asm volatile (" \ 335 r6 = r10; \ 336 r6 += -8; \ 337 *(u64*)(r6 + 0) = r1; \ 338 *(u64*)(r6 + 0) = r10; \ 339 r1 = *(u64*)(r6 + 0); \ 340 call %[bpf_get_hash_recalc]; \ 341 exit; \ 342 " : 343 : __imm(bpf_get_hash_recalc) 344 : __clobber_all); 345 } 346 347 SEC("tc") 348 __description("unpriv: spill/fill of ctx 4") 349 __failure __msg("R1 type=scalar expected=ctx") 350 __naked void spill_fill_of_ctx_4(void) 351 { 352 asm volatile (" \ 353 r6 = r10; \ 354 r6 += -8; \ 355 *(u64*)(r6 + 0) = r1; \ 356 r0 = 1; \ 357 lock *(u64 *)(r10 - 8) += r0; \ 358 r1 = *(u64*)(r6 + 0); \ 359 call %[bpf_get_hash_recalc]; \ 360 exit; \ 361 " : 362 : __imm(bpf_get_hash_recalc) 363 : __clobber_all); 364 } 365 366 SEC("tc") 367 __description("unpriv: spill/fill of different pointers stx") 368 __failure __msg("same insn cannot be used with different pointers") 369 __naked void fill_of_different_pointers_stx(void) 370 { 371 asm volatile (" \ 372 r3 = 42; \ 373 r6 = r10; \ 374 r6 += -8; \ 375 if r1 == 0 goto l0_%=; \ 376 r2 = r10; \ 377 r2 += -16; \ 378 *(u64*)(r6 + 0) = r2; \ 379 l0_%=: if r1 != 0 goto l1_%=; \ 380 *(u64*)(r6 + 0) = r1; \ 381 l1_%=: r1 = *(u64*)(r6 + 0); \ 382 *(u32*)(r1 + %[__sk_buff_mark]) = r3; \ 383 r0 = 0; \ 384 exit; \ 385 " : 386 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 387 : __clobber_all); 388 } 389 390 /* Same as above, but use BPF_ST_MEM to save 42 391 * instead of BPF_STX_MEM. 392 */ 393 SEC("tc") 394 __description("unpriv: spill/fill of different pointers st") 395 __failure __msg("same insn cannot be used with different pointers") 396 __naked void fill_of_different_pointers_st(void) 397 { 398 asm volatile (" \ 399 r6 = r10; \ 400 r6 += -8; \ 401 if r1 == 0 goto l0_%=; \ 402 r2 = r10; \ 403 r2 += -16; \ 404 *(u64*)(r6 + 0) = r2; \ 405 l0_%=: if r1 != 0 goto l1_%=; \ 406 *(u64*)(r6 + 0) = r1; \ 407 l1_%=: r1 = *(u64*)(r6 + 0); \ 408 .8byte %[st_mem]; \ 409 r0 = 0; \ 410 exit; \ 411 " : 412 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)), 413 __imm_insn(st_mem, 414 BPF_ST_MEM(BPF_W, BPF_REG_1, offsetof(struct __sk_buff, mark), 42)) 415 : __clobber_all); 416 } 417 418 SEC("tc") 419 __description("unpriv: spill/fill of different pointers stx - ctx and sock") 420 __failure __msg("type=ctx expected=sock") 421 __naked void pointers_stx_ctx_and_sock(void) 422 { 423 asm volatile (" \ 424 r8 = r1; \ 425 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\ 426 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp) 427 " r2 = r0; \ 428 /* u64 foo; */ \ 429 /* void *target = &foo; */ \ 430 r6 = r10; \ 431 r6 += -8; \ 432 r1 = r8; \ 433 /* if (skb == NULL) *target = sock; */ \ 434 if r1 == 0 goto l0_%=; \ 435 *(u64*)(r6 + 0) = r2; \ 436 l0_%=: /* else *target = skb; */ \ 437 if r1 != 0 goto l1_%=; \ 438 *(u64*)(r6 + 0) = r1; \ 439 l1_%=: /* struct __sk_buff *skb = *target; */ \ 440 r1 = *(u64*)(r6 + 0); \ 441 /* skb->mark = 42; */ \ 442 r3 = 42; \ 443 *(u32*)(r1 + %[__sk_buff_mark]) = r3; \ 444 /* if (sk) bpf_sk_release(sk) */ \ 445 if r1 == 0 goto l2_%=; \ 446 call %[bpf_sk_release]; \ 447 l2_%=: r0 = 0; \ 448 exit; \ 449 " : 450 : __imm(bpf_sk_lookup_tcp), 451 __imm(bpf_sk_release), 452 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)), 453 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple)) 454 : __clobber_all); 455 } 456 457 SEC("tc") 458 __description("unpriv: spill/fill of different pointers stx - leak sock") 459 __failure 460 //.errstr = "same insn cannot be used with different pointers", 461 __msg("Unreleased reference") 462 __naked void different_pointers_stx_leak_sock(void) 463 { 464 asm volatile (" \ 465 r8 = r1; \ 466 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\ 467 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp) 468 " r2 = r0; \ 469 /* u64 foo; */ \ 470 /* void *target = &foo; */ \ 471 r6 = r10; \ 472 r6 += -8; \ 473 r1 = r8; \ 474 /* if (skb == NULL) *target = sock; */ \ 475 if r1 == 0 goto l0_%=; \ 476 *(u64*)(r6 + 0) = r2; \ 477 l0_%=: /* else *target = skb; */ \ 478 if r1 != 0 goto l1_%=; \ 479 *(u64*)(r6 + 0) = r1; \ 480 l1_%=: /* struct __sk_buff *skb = *target; */ \ 481 r1 = *(u64*)(r6 + 0); \ 482 /* skb->mark = 42; */ \ 483 r3 = 42; \ 484 *(u32*)(r1 + %[__sk_buff_mark]) = r3; \ 485 exit; \ 486 " : 487 : __imm(bpf_sk_lookup_tcp), 488 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)), 489 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple)) 490 : __clobber_all); 491 } 492 493 SEC("tc") 494 __description("unpriv: spill/fill of different pointers stx - sock and ctx (read)") 495 __failure __msg("same insn cannot be used with different pointers") 496 __naked void stx_sock_and_ctx_read(void) 497 { 498 asm volatile (" \ 499 r8 = r1; \ 500 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\ 501 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp) 502 " r2 = r0; \ 503 /* u64 foo; */ \ 504 /* void *target = &foo; */ \ 505 r6 = r10; \ 506 r6 += -8; \ 507 r1 = r8; \ 508 /* if (skb) *target = skb */ \ 509 if r1 == 0 goto l0_%=; \ 510 *(u64*)(r6 + 0) = r1; \ 511 l0_%=: /* else *target = sock */ \ 512 if r1 != 0 goto l1_%=; \ 513 *(u64*)(r6 + 0) = r2; \ 514 l1_%=: /* struct bpf_sock *sk = *target; */ \ 515 r1 = *(u64*)(r6 + 0); \ 516 /* if (sk) u32 foo = sk->mark; bpf_sk_release(sk); */\ 517 if r1 == 0 goto l2_%=; \ 518 r3 = *(u32*)(r1 + %[bpf_sock_mark]); \ 519 call %[bpf_sk_release]; \ 520 l2_%=: r0 = 0; \ 521 exit; \ 522 " : 523 : __imm(bpf_sk_lookup_tcp), 524 __imm(bpf_sk_release), 525 __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)), 526 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple)) 527 : __clobber_all); 528 } 529 530 SEC("tc") 531 __description("unpriv: spill/fill of different pointers stx - sock and ctx (write)") 532 __failure 533 //.errstr = "same insn cannot be used with different pointers", 534 __msg("cannot write into sock") 535 __naked void stx_sock_and_ctx_write(void) 536 { 537 asm volatile (" \ 538 r8 = r1; \ 539 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\ 540 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp) 541 " r2 = r0; \ 542 /* u64 foo; */ \ 543 /* void *target = &foo; */ \ 544 r6 = r10; \ 545 r6 += -8; \ 546 r1 = r8; \ 547 /* if (skb) *target = skb */ \ 548 if r1 == 0 goto l0_%=; \ 549 *(u64*)(r6 + 0) = r1; \ 550 l0_%=: /* else *target = sock */ \ 551 if r1 != 0 goto l1_%=; \ 552 *(u64*)(r6 + 0) = r2; \ 553 l1_%=: /* struct bpf_sock *sk = *target; */ \ 554 r1 = *(u64*)(r6 + 0); \ 555 /* if (sk) sk->mark = 42; bpf_sk_release(sk); */\ 556 if r1 == 0 goto l2_%=; \ 557 r3 = 42; \ 558 *(u32*)(r1 + %[bpf_sock_mark]) = r3; \ 559 call %[bpf_sk_release]; \ 560 l2_%=: r0 = 0; \ 561 exit; \ 562 " : 563 : __imm(bpf_sk_lookup_tcp), 564 __imm(bpf_sk_release), 565 __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)), 566 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple)) 567 : __clobber_all); 568 } 569 570 SEC("socket") 571 __description("unpriv: write pointer into map elem value") 572 __success __failure_unpriv __msg_unpriv("R0 leaks addr") 573 __retval(0) 574 __naked void pointer_into_map_elem_value(void) 575 { 576 asm volatile (" \ 577 r1 = 0; \ 578 *(u64*)(r10 - 8) = r1; \ 579 r2 = r10; \ 580 r2 += -8; \ 581 r1 = %[map_hash_8b] ll; \ 582 call %[bpf_map_lookup_elem]; \ 583 if r0 == 0 goto l0_%=; \ 584 *(u64*)(r0 + 0) = r0; \ 585 l0_%=: exit; \ 586 " : 587 : __imm(bpf_map_lookup_elem), 588 __imm_addr(map_hash_8b) 589 : __clobber_all); 590 } 591 592 SEC("socket") 593 __description("alu32: mov u32 const") 594 __success __success_unpriv 595 __retval(0) 596 #ifdef SPEC_V1 597 __xlated_unpriv("if r0 == 0x0 goto pc+2") 598 __xlated_unpriv("nospec") /* inserted to prevent `R7 invalid mem access 'scalar'` */ 599 __xlated_unpriv("goto pc-1") /* sanitized dead code */ 600 __xlated_unpriv("exit") 601 #endif 602 __naked void alu32_mov_u32_const(void) 603 { 604 asm volatile (" \ 605 w7 = 0; \ 606 w7 ^= w7; \ 607 w0 = w7; \ 608 if r0 == 0 goto l0_%=; \ 609 r0 = *(u64*)(r7 + 0); \ 610 l0_%=: exit; \ 611 " ::: __clobber_all); 612 } 613 614 SEC("socket") 615 __description("unpriv: partial copy of pointer") 616 __success __failure_unpriv __msg_unpriv("R10 partial copy") 617 __retval(0) 618 __naked void unpriv_partial_copy_of_pointer(void) 619 { 620 asm volatile (" \ 621 w1 = w10; \ 622 r0 = 0; \ 623 exit; \ 624 " ::: __clobber_all); 625 } 626 627 SEC("socket") 628 __description("unpriv: pass pointer to tail_call") 629 __success __failure_unpriv __msg_unpriv("R3 leaks addr into helper") 630 __retval(0) 631 __naked void pass_pointer_to_tail_call(void) 632 { 633 asm volatile (" \ 634 r3 = r1; \ 635 r2 = %[map_prog1_socket] ll; \ 636 call %[bpf_tail_call]; \ 637 r0 = 0; \ 638 exit; \ 639 " : 640 : __imm(bpf_tail_call), 641 __imm_addr(map_prog1_socket) 642 : __clobber_all); 643 } 644 645 SEC("socket") 646 __description("unpriv: cmp map pointer with zero") 647 __success __success_unpriv 648 __retval(0) 649 __naked void cmp_map_pointer_with_zero(void) 650 { 651 asm volatile (" \ 652 r1 = %[map_hash_8b] ll; \ 653 if r1 == 0 goto l0_%=; \ 654 l0_%=: r0 = 0; \ 655 exit; \ 656 " : 657 : __imm_addr(map_hash_8b) 658 : __clobber_all); 659 } 660 661 SEC("socket") 662 __description("unpriv: cmp map pointer with const") 663 __success __failure_unpriv __msg_unpriv("R1 pointer comparison prohibited") 664 __retval(0) 665 __naked void cmp_map_pointer_with_const(void) 666 { 667 asm volatile (" \ 668 r1 = %[map_hash_8b] ll; \ 669 if r1 == 0x0000beef goto l0_%=; \ 670 l0_%=: r0 = 0; \ 671 exit; \ 672 " : 673 : __imm_addr(map_hash_8b) 674 : __clobber_all); 675 } 676 677 SEC("socket") 678 __description("unpriv: write into frame pointer") 679 __failure __msg("frame pointer is read only") 680 __failure_unpriv 681 __naked void unpriv_write_into_frame_pointer(void) 682 { 683 asm volatile (" \ 684 r10 = r1; \ 685 r0 = 0; \ 686 exit; \ 687 " ::: __clobber_all); 688 } 689 690 SEC("socket") 691 __description("unpriv: spill/fill frame pointer") 692 __failure __msg("frame pointer is read only") 693 __failure_unpriv 694 __naked void unpriv_spill_fill_frame_pointer(void) 695 { 696 asm volatile (" \ 697 r6 = r10; \ 698 r6 += -8; \ 699 *(u64*)(r6 + 0) = r10; \ 700 r10 = *(u64*)(r6 + 0); \ 701 r0 = 0; \ 702 exit; \ 703 " ::: __clobber_all); 704 } 705 706 SEC("socket") 707 __description("unpriv: cmp of frame pointer") 708 __success __failure_unpriv __msg_unpriv("R10 pointer comparison") 709 __retval(0) 710 __naked void unpriv_cmp_of_frame_pointer(void) 711 { 712 asm volatile (" \ 713 if r10 == 0 goto l0_%=; \ 714 l0_%=: r0 = 0; \ 715 exit; \ 716 " ::: __clobber_all); 717 } 718 719 SEC("socket") 720 __description("unpriv: adding of fp, reg") 721 __success __failure_unpriv 722 __msg_unpriv("R1 stack pointer arithmetic goes out of range") 723 __retval(0) 724 __naked void unpriv_adding_of_fp_reg(void) 725 { 726 asm volatile (" \ 727 r0 = 0; \ 728 r1 = 0; \ 729 r1 += r10; \ 730 *(u64*)(r1 - 8) = r0; \ 731 exit; \ 732 " ::: __clobber_all); 733 } 734 735 SEC("socket") 736 __description("unpriv: adding of fp, imm") 737 __success __failure_unpriv 738 __msg_unpriv("R1 stack pointer arithmetic goes out of range") 739 __retval(0) 740 __naked void unpriv_adding_of_fp_imm(void) 741 { 742 asm volatile (" \ 743 r0 = 0; \ 744 r1 = r10; \ 745 r1 += 0; \ 746 *(u64*)(r1 - 8) = r0; \ 747 exit; \ 748 " ::: __clobber_all); 749 } 750 751 SEC("socket") 752 __description("unpriv: cmp of stack pointer") 753 __success __failure_unpriv __msg_unpriv("R2 pointer comparison") 754 __retval(0) 755 __naked void unpriv_cmp_of_stack_pointer(void) 756 { 757 asm volatile (" \ 758 r2 = r10; \ 759 r2 += -8; \ 760 if r2 == 0 goto l0_%=; \ 761 l0_%=: r0 = 0; \ 762 exit; \ 763 " ::: __clobber_all); 764 } 765 766 SEC("socket") 767 __description("unpriv: Spectre v1 path-based type confusion of scalar as stack-ptr") 768 __success __success_unpriv __retval(0) 769 #ifdef SPEC_V1 770 __xlated_unpriv("if r0 != 0x1 goto pc+2") 771 /* This nospec prevents the exploit because it forces the mispredicted (not 772 * taken) `if r0 != 0x0 goto l0_%=` to resolve before using r6 as a pointer. 773 * This causes the CPU to realize that `r6 = r9` should have never executed. It 774 * ensures that r6 always contains a readable stack slot ptr when the insn after 775 * the nospec executes. 776 */ 777 __xlated_unpriv("nospec") 778 __xlated_unpriv("r9 = *(u8 *)(r6 +0)") 779 #endif 780 __naked void unpriv_spec_v1_type_confusion(void) 781 { 782 asm volatile (" \ 783 r1 = 0; \ 784 *(u64*)(r10 - 8) = r1; \ 785 r2 = r10; \ 786 r2 += -8; \ 787 r1 = %[map_hash_8b] ll; \ 788 call %[bpf_map_lookup_elem]; \ 789 if r0 == 0 goto l2_%=; \ 790 /* r0: pointer to a map array entry */ \ 791 r2 = r10; \ 792 r2 += -8; \ 793 r1 = %[map_hash_8b] ll; \ 794 /* r1, r2: prepared call args */ \ 795 r6 = r10; \ 796 r6 += -8; \ 797 /* r6: pointer to readable stack slot */ \ 798 r9 = 0xffffc900; \ 799 r9 <<= 32; \ 800 /* r9: scalar controlled by attacker */ \ 801 r0 = *(u64 *)(r0 + 0); /* cache miss */ \ 802 if r0 != 0x0 goto l0_%=; \ 803 r6 = r9; \ 804 l0_%=: if r0 != 0x1 goto l1_%=; \ 805 r9 = *(u8 *)(r6 + 0); \ 806 l1_%=: /* leak r9 */ \ 807 r9 &= 1; \ 808 r9 <<= 9; \ 809 *(u64*)(r10 - 8) = r9; \ 810 call %[bpf_map_lookup_elem]; \ 811 if r0 == 0 goto l2_%=; \ 812 /* leak secret into is_cached(map[0|512]): */ \ 813 r0 = *(u64 *)(r0 + 0); \ 814 l2_%=: \ 815 r0 = 0; \ 816 exit; \ 817 " : 818 : __imm(bpf_map_lookup_elem), 819 __imm_addr(map_hash_8b) 820 : __clobber_all); 821 } 822 823 SEC("socket") 824 __description("unpriv: ldimm64 before Spectre v4 barrier") 825 __success __success_unpriv 826 __retval(0) 827 #ifdef SPEC_V4 828 __xlated_unpriv("r1 = 0x2020200005642020") /* should not matter */ 829 __xlated_unpriv("*(u64 *)(r10 -8) = r1") 830 __xlated_unpriv("nospec") 831 #endif 832 __naked void unpriv_ldimm64_spectre_v4(void) 833 { 834 asm volatile (" \ 835 r1 = 0x2020200005642020 ll; \ 836 *(u64 *)(r10 -8) = r1; \ 837 r0 = 0; \ 838 exit; \ 839 " ::: __clobber_all); 840 } 841 842 SEC("socket") 843 __description("unpriv: Spectre v1 and v4 barrier") 844 __success __success_unpriv 845 __retval(0) 846 #ifdef SPEC_V1 847 #ifdef SPEC_V4 848 /* starts with r0 == r8 == r9 == 0 */ 849 __xlated_unpriv("if r8 != 0x0 goto pc+1") 850 __xlated_unpriv("goto pc+2") 851 __xlated_unpriv("if r9 == 0x0 goto pc+4") 852 __xlated_unpriv("r2 = r0") 853 /* Following nospec required to prevent following dangerous `*(u64 *)(NOT_FP -64) 854 * = r1` iff `if r9 == 0 goto pc+4` was mispredicted because of Spectre v1. The 855 * test therefore ensures the Spectre-v4--induced nospec does not prevent the 856 * Spectre-v1--induced speculative path from being fully analyzed. 857 */ 858 __xlated_unpriv("nospec") /* Spectre v1 */ 859 __xlated_unpriv("*(u64 *)(r2 -64) = r1") /* could be used to leak r2 */ 860 __xlated_unpriv("nospec") /* Spectre v4 */ 861 #endif 862 #endif 863 __naked void unpriv_spectre_v1_and_v4(void) 864 { 865 asm volatile (" \ 866 r1 = 0; \ 867 *(u64*)(r10 - 8) = r1; \ 868 r2 = r10; \ 869 r2 += -8; \ 870 r1 = %[map_hash_8b] ll; \ 871 call %[bpf_map_lookup_elem]; \ 872 r8 = r0; \ 873 r2 = r10; \ 874 r2 += -8; \ 875 r1 = %[map_hash_8b] ll; \ 876 call %[bpf_map_lookup_elem]; \ 877 r9 = r0; \ 878 r0 = r10; \ 879 r1 = 0; \ 880 r2 = r10; \ 881 if r8 != 0 goto l0_%=; \ 882 if r9 != 0 goto l0_%=; \ 883 r0 = 0; \ 884 l0_%=: if r8 != 0 goto l1_%=; \ 885 goto l2_%=; \ 886 l1_%=: if r9 == 0 goto l3_%=; \ 887 r2 = r0; \ 888 l2_%=: *(u64 *)(r2 -64) = r1; \ 889 l3_%=: r0 = 0; \ 890 exit; \ 891 " : 892 : __imm(bpf_map_lookup_elem), 893 __imm_addr(map_hash_8b) 894 : __clobber_all); 895 } 896 897 SEC("socket") 898 __description("unpriv: Spectre v1 and v4 barrier (simple)") 899 __success __success_unpriv 900 __retval(0) 901 #ifdef SPEC_V1 902 #ifdef SPEC_V4 903 __xlated_unpriv("if r8 != 0x0 goto pc+1") 904 __xlated_unpriv("goto pc+2") 905 __xlated_unpriv("goto pc-1") /* if r9 == 0 goto l3_%= */ 906 __xlated_unpriv("goto pc-1") /* r2 = r0 */ 907 __xlated_unpriv("nospec") 908 __xlated_unpriv("*(u64 *)(r2 -64) = r1") 909 __xlated_unpriv("nospec") 910 #endif 911 #endif 912 __naked void unpriv_spectre_v1_and_v4_simple(void) 913 { 914 asm volatile (" \ 915 r8 = 0; \ 916 r8 ^= r8; \ 917 r9 = 0; \ 918 r9 ^= r9; \ 919 r0 = r10; \ 920 r1 = 0; \ 921 r2 = r10; \ 922 if r8 != 0 goto l0_%=; \ 923 if r9 != 0 goto l0_%=; \ 924 r0 = 0; \ 925 l0_%=: if r8 != 0 goto l1_%=; \ 926 goto l2_%=; \ 927 l1_%=: if r9 == 0 goto l3_%=; \ 928 r2 = r0; \ 929 l2_%=: *(u64 *)(r2 -64) = r1; \ 930 l3_%=: r0 = 0; \ 931 exit; \ 932 " ::: __clobber_all); 933 } 934 935 SEC("socket") 936 __description("unpriv: ldimm64 before Spectre v1 and v4 barrier (simple)") 937 __success __success_unpriv 938 __retval(0) 939 #ifdef SPEC_V1 940 #ifdef SPEC_V4 941 __xlated_unpriv("if r8 != 0x0 goto pc+1") 942 __xlated_unpriv("goto pc+4") 943 __xlated_unpriv("goto pc-1") /* if r9 == 0 goto l3_%= */ 944 __xlated_unpriv("goto pc-1") /* r2 = r0 */ 945 __xlated_unpriv("goto pc-1") /* r1 = 0x2020200005642020 ll */ 946 __xlated_unpriv("goto pc-1") /* second part of ldimm64 */ 947 __xlated_unpriv("nospec") 948 __xlated_unpriv("*(u64 *)(r2 -64) = r1") 949 __xlated_unpriv("nospec") 950 #endif 951 #endif 952 __naked void unpriv_ldimm64_spectre_v1_and_v4_simple(void) 953 { 954 asm volatile (" \ 955 r8 = 0; \ 956 r8 ^= r8; \ 957 r9 = 0; \ 958 r9 ^= r9; \ 959 r0 = r10; \ 960 r1 = 0; \ 961 r2 = r10; \ 962 if r8 != 0 goto l0_%=; \ 963 if r9 != 0 goto l0_%=; \ 964 r0 = 0; \ 965 l0_%=: if r8 != 0 goto l1_%=; \ 966 goto l2_%=; \ 967 l1_%=: if r9 == 0 goto l3_%=; \ 968 r2 = r0; \ 969 r1 = 0x2020200005642020 ll; \ 970 l2_%=: *(u64 *)(r2 -64) = r1; \ 971 l3_%=: r0 = 0; \ 972 exit; \ 973 " ::: __clobber_all); 974 } 975 976 SEC("socket") 977 __description("unpriv: nospec after dead stack write in helper") 978 __success __success_unpriv 979 __retval(0) 980 /* Dead code sanitizer rewrites the call to `goto -1`. */ 981 __naked void unpriv_dead_helper_stack_write_nospec_result(void) 982 { 983 asm volatile (" \ 984 r0 = 0; \ 985 if r0 != 1 goto l0_%=; \ 986 r2 = 0; \ 987 r3 = r10; \ 988 r3 += -16; \ 989 r4 = 4; \ 990 r5 = 0; \ 991 call %[bpf_skb_load_bytes_relative]; \ 992 l0_%=: exit; \ 993 " : 994 : __imm(bpf_skb_load_bytes_relative) 995 : __clobber_all); 996 } 997 998 SEC("socket") 999 __description("unpriv: Spectre v4 stack write slot index") 1000 __success __success_unpriv 1001 __retval(0) 1002 #ifdef SPEC_V4 1003 __xlated_unpriv("r0 = 0") 1004 __xlated_unpriv("*(u32 *)(r10 -4) = r0") 1005 __xlated_unpriv("nospec") 1006 __xlated_unpriv("*(u32 *)(r10 -8) = r0") 1007 __xlated_unpriv("nospec") 1008 __xlated_unpriv("exit") 1009 #endif 1010 __naked void stack_write_nospec_slot_index(void) 1011 { 1012 asm volatile (" \ 1013 r0 = 0; \ 1014 *(u32 *)(r10 - 4) = r0; \ 1015 *(u32 *)(r10 - 8) = r0; \ 1016 exit; \ 1017 " ::: __clobber_all); 1018 } 1019 1020 char _license[] SEC("license") = "GPL"; 1021