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.

Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Pull bpf fixes from Alexei Starovoitov:

- Fix u32/s32 bounds when ranges cross min/max boundary (Eduard
Zingerman)

- Fix precision backtracking with linked registers (Eduard Zingerman)

- Fix linker flags detection for resolve_btfids (Ihor Solodrai)

- Fix race in update_ftrace_direct_add/del (Jiri Olsa)

- Fix UAF in bpf_trampoline_link_cgroup_shim (Lang Xu)

* tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf:
resolve_btfids: Fix linker flags detection
selftests/bpf: add reproducer for spurious precision propagation through calls
bpf: collect only live registers in linked regs
Revert "selftests/bpf: Update reg_bound range refinement logic"
selftests/bpf: test refining u32/s32 bounds when ranges cross min/max boundary
bpf: Fix u32/s32 bounds when ranges cross min/max boundary
bpf: Fix a UAF issue in bpf_trampoline_link_cgroup_shim
ftrace: Add missing ftrace_lock to update_ftrace_direct_add/del

+268 -62
+1 -3
kernel/bpf/trampoline.c
··· 1002 1002 mutex_lock(&tr->mutex); 1003 1003 1004 1004 shim_link = cgroup_shim_find(tr, bpf_func); 1005 - if (shim_link) { 1005 + if (shim_link && !IS_ERR(bpf_link_inc_not_zero(&shim_link->link.link))) { 1006 1006 /* Reusing existing shim attached by the other program. */ 1007 - bpf_link_inc(&shim_link->link.link); 1008 - 1009 1007 mutex_unlock(&tr->mutex); 1010 1008 bpf_trampoline_put(tr); /* bpf_trampoline_get above */ 1011 1009 return 0;
+34 -3
kernel/bpf/verifier.c
··· 2511 2511 if ((u32)reg->s32_min_value <= (u32)reg->s32_max_value) { 2512 2512 reg->u32_min_value = max_t(u32, reg->s32_min_value, reg->u32_min_value); 2513 2513 reg->u32_max_value = min_t(u32, reg->s32_max_value, reg->u32_max_value); 2514 + } else { 2515 + if (reg->u32_max_value < (u32)reg->s32_min_value) { 2516 + /* See __reg64_deduce_bounds() for detailed explanation. 2517 + * Refine ranges in the following situation: 2518 + * 2519 + * 0 U32_MAX 2520 + * | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | 2521 + * |----------------------------|----------------------------| 2522 + * |xxxxx s32 range xxxxxxxxx] [xxxxxxx| 2523 + * 0 S32_MAX S32_MIN -1 2524 + */ 2525 + reg->s32_min_value = (s32)reg->u32_min_value; 2526 + reg->u32_max_value = min_t(u32, reg->u32_max_value, reg->s32_max_value); 2527 + } else if ((u32)reg->s32_max_value < reg->u32_min_value) { 2528 + /* 2529 + * 0 U32_MAX 2530 + * | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | 2531 + * |----------------------------|----------------------------| 2532 + * |xxxxxxxxx] [xxxxxxxxxxxx s32 range | 2533 + * 0 S32_MAX S32_MIN -1 2534 + */ 2535 + reg->s32_max_value = (s32)reg->u32_max_value; 2536 + reg->u32_min_value = max_t(u32, reg->u32_min_value, reg->s32_min_value); 2537 + } 2514 2538 } 2515 2539 } 2516 2540 ··· 17359 17335 * in verifier state, save R in linked_regs if R->id == id. 17360 17336 * If there are too many Rs sharing same id, reset id for leftover Rs. 17361 17337 */ 17362 - static void collect_linked_regs(struct bpf_verifier_state *vstate, u32 id, 17338 + static void collect_linked_regs(struct bpf_verifier_env *env, 17339 + struct bpf_verifier_state *vstate, 17340 + u32 id, 17363 17341 struct linked_regs *linked_regs) 17364 17342 { 17343 + struct bpf_insn_aux_data *aux = env->insn_aux_data; 17365 17344 struct bpf_func_state *func; 17366 17345 struct bpf_reg_state *reg; 17346 + u16 live_regs; 17367 17347 int i, j; 17368 17348 17369 17349 id = id & ~BPF_ADD_CONST; 17370 17350 for (i = vstate->curframe; i >= 0; i--) { 17351 + live_regs = aux[frame_insn_idx(vstate, i)].live_regs_before; 17371 17352 func = vstate->frame[i]; 17372 17353 for (j = 0; j < BPF_REG_FP; j++) { 17354 + if (!(live_regs & BIT(j))) 17355 + continue; 17373 17356 reg = &func->regs[j]; 17374 17357 __collect_linked_regs(linked_regs, reg, id, i, j, true); 17375 17358 } ··· 17591 17560 * if parent state is created. 17592 17561 */ 17593 17562 if (BPF_SRC(insn->code) == BPF_X && src_reg->type == SCALAR_VALUE && src_reg->id) 17594 - collect_linked_regs(this_branch, src_reg->id, &linked_regs); 17563 + collect_linked_regs(env, this_branch, src_reg->id, &linked_regs); 17595 17564 if (dst_reg->type == SCALAR_VALUE && dst_reg->id) 17596 - collect_linked_regs(this_branch, dst_reg->id, &linked_regs); 17565 + collect_linked_regs(env, this_branch, dst_reg->id, &linked_regs); 17597 17566 if (linked_regs.cnt > 1) { 17598 17567 err = push_jmp_history(env, this_branch, 0, linked_regs_pack(&linked_regs)); 17599 17568 if (err)
+2
kernel/trace/ftrace.c
··· 6404 6404 new_filter_hash = old_filter_hash; 6405 6405 } 6406 6406 } else { 6407 + guard(mutex)(&ftrace_lock); 6407 6408 err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH); 6408 6409 /* 6409 6410 * new_filter_hash is dup-ed, so we need to release it anyway, ··· 6531 6530 ops->func_hash->filter_hash = NULL; 6532 6531 } 6533 6532 } else { 6533 + guard(mutex)(&ftrace_lock); 6534 6534 err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH); 6535 6535 /* 6536 6536 * new_filter_hash is dup-ed, so we need to release it anyway,
+7 -2
tools/bpf/resolve_btfids/Makefile
··· 23 23 HOSTCC ?= gcc 24 24 HOSTLD ?= ld 25 25 HOSTAR ?= ar 26 + HOSTPKG_CONFIG ?= pkg-config 26 27 CROSS_COMPILE = 27 28 28 29 OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/ ··· 64 63 $(abspath $@) install_headers 65 64 66 65 LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null) 66 + 67 + ifneq ($(filter -static,$(EXTRA_LDFLAGS)),) 68 + LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs --static 2>/dev/null || echo -lelf -lzstd) 69 + else 67 70 LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf) 71 + endif 68 72 69 73 ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz) 70 - ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd) 71 74 72 75 HOSTCFLAGS_resolve_btfids += -g \ 73 76 -I$(srctree)/tools/include \ ··· 81 76 $(LIBELF_FLAGS) \ 82 77 -Wall -Werror 83 78 84 - LIBS = $(LIBELF_LIBS) $(ZLIB_LIBS) $(ZSTD_LIBS) 79 + LIBS = $(LIBELF_LIBS) $(ZLIB_LIBS) 85 80 86 81 export srctree OUTPUT HOSTCFLAGS_resolve_btfids Q HOSTCC HOSTLD HOSTAR 87 82 include $(srctree)/tools/build/Makefile.include
+1
tools/testing/selftests/bpf/Makefile
··· 409 409 CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" \ 410 410 LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \ 411 411 EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \ 412 + HOSTPKG_CONFIG=$(PKG_CONFIG) \ 412 413 OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ) 413 414 414 415 # Get Clang's default includes on this system, as opposed to those seen by
+58 -18
tools/testing/selftests/bpf/prog_tests/reg_bounds.c
··· 422 422 } 423 423 } 424 424 425 - static struct range range_improve(enum num_t t, struct range old, struct range new) 425 + static struct range range_intersection(enum num_t t, struct range old, struct range new) 426 426 { 427 427 return range(t, max_t(t, old.a, new.a), min_t(t, old.b, new.b)); 428 + } 429 + 430 + /* 431 + * Result is precise when 'x' and 'y' overlap or form a continuous range, 432 + * result is an over-approximation if 'x' and 'y' do not overlap. 433 + */ 434 + static struct range range_union(enum num_t t, struct range x, struct range y) 435 + { 436 + if (!is_valid_range(t, x)) 437 + return y; 438 + if (!is_valid_range(t, y)) 439 + return x; 440 + return range(t, min_t(t, x.a, y.a), max_t(t, x.b, y.b)); 441 + } 442 + 443 + /* 444 + * This function attempts to improve x range intersecting it with y. 445 + * range_cast(... to_t ...) looses precision for ranges that pass to_t 446 + * min/max boundaries. To avoid such precision loses this function 447 + * splits both x and y into halves corresponding to non-overflowing 448 + * sub-ranges: [0, smin] and [smax, -1]. 449 + * Final result is computed as follows: 450 + * 451 + * ((x ∩ [0, smax]) ∩ (y ∩ [0, smax])) ∪ 452 + * ((x ∩ [smin,-1]) ∩ (y ∩ [smin,-1])) 453 + * 454 + * Precision might still be lost if final union is not a continuous range. 455 + */ 456 + static struct range range_refine_in_halves(enum num_t x_t, struct range x, 457 + enum num_t y_t, struct range y) 458 + { 459 + struct range x_pos, x_neg, y_pos, y_neg, r_pos, r_neg; 460 + u64 smax, smin, neg_one; 461 + 462 + if (t_is_32(x_t)) { 463 + smax = (u64)(u32)S32_MAX; 464 + smin = (u64)(u32)S32_MIN; 465 + neg_one = (u64)(u32)(s32)(-1); 466 + } else { 467 + smax = (u64)S64_MAX; 468 + smin = (u64)S64_MIN; 469 + neg_one = U64_MAX; 470 + } 471 + x_pos = range_intersection(x_t, x, range(x_t, 0, smax)); 472 + x_neg = range_intersection(x_t, x, range(x_t, smin, neg_one)); 473 + y_pos = range_intersection(y_t, y, range(x_t, 0, smax)); 474 + y_neg = range_intersection(y_t, y, range(y_t, smin, neg_one)); 475 + r_pos = range_intersection(x_t, x_pos, range_cast(y_t, x_t, y_pos)); 476 + r_neg = range_intersection(x_t, x_neg, range_cast(y_t, x_t, y_neg)); 477 + return range_union(x_t, r_pos, r_neg); 478 + 428 479 } 429 480 430 481 static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t, struct range y) 431 482 { 432 483 struct range y_cast; 484 + 485 + if (t_is_32(x_t) == t_is_32(y_t)) 486 + x = range_refine_in_halves(x_t, x, y_t, y); 433 487 434 488 y_cast = range_cast(y_t, x_t, y); 435 489 ··· 498 444 */ 499 445 if (x_t == S64 && y_t == S32 && y_cast.a <= S32_MAX && y_cast.b <= S32_MAX && 500 446 (s64)x.a >= S32_MIN && (s64)x.b <= S32_MAX) 501 - return range_improve(x_t, x, y_cast); 447 + return range_intersection(x_t, x, y_cast); 502 448 503 449 /* the case when new range knowledge, *y*, is a 32-bit subregister 504 450 * range, while previous range knowledge, *x*, is a full register ··· 516 462 x_swap = range(x_t, swap_low32(x.a, y_cast.a), swap_low32(x.b, y_cast.b)); 517 463 if (!is_valid_range(x_t, x_swap)) 518 464 return x; 519 - return range_improve(x_t, x, x_swap); 520 - } 521 - 522 - if (!t_is_32(x_t) && !t_is_32(y_t) && x_t != y_t) { 523 - if (x_t == S64 && x.a > x.b) { 524 - if (x.b < y.a && x.a <= y.b) 525 - return range(x_t, x.a, y.b); 526 - if (x.a > y.b && x.b >= y.a) 527 - return range(x_t, y.a, x.b); 528 - } else if (x_t == U64 && y.a > y.b) { 529 - if (y.b < x.a && y.a <= x.b) 530 - return range(x_t, y.a, x.b); 531 - if (y.a > x.b && y.b >= x.a) 532 - return range(x_t, x.a, y.b); 533 - } 465 + return range_intersection(x_t, x, x_swap); 534 466 } 535 467 536 468 /* otherwise, plain range cast and intersection works */ 537 - return range_improve(x_t, x, y_cast); 469 + return range_intersection(x_t, x, y_cast); 538 470 } 539 471 540 472 /* =======================
+17 -17
tools/testing/selftests/bpf/progs/exceptions_assert.c
··· 18 18 return *(u64 *)num; \ 19 19 } 20 20 21 - __msg(": R0=0xffffffff80000000") 21 + __msg("R{{.}}=0xffffffff80000000") 22 22 check_assert(s64, ==, eq_int_min, INT_MIN); 23 - __msg(": R0=0x7fffffff") 23 + __msg("R{{.}}=0x7fffffff") 24 24 check_assert(s64, ==, eq_int_max, INT_MAX); 25 - __msg(": R0=0") 25 + __msg("R{{.}}=0") 26 26 check_assert(s64, ==, eq_zero, 0); 27 - __msg(": R0=0x8000000000000000 R1=0x8000000000000000") 27 + __msg("R{{.}}=0x8000000000000000") 28 28 check_assert(s64, ==, eq_llong_min, LLONG_MIN); 29 - __msg(": R0=0x7fffffffffffffff R1=0x7fffffffffffffff") 29 + __msg("R{{.}}=0x7fffffffffffffff") 30 30 check_assert(s64, ==, eq_llong_max, LLONG_MAX); 31 31 32 - __msg(": R0=scalar(id=1,smax=0x7ffffffe)") 32 + __msg("R{{.}}=scalar(id=1,smax=0x7ffffffe)") 33 33 check_assert(s64, <, lt_pos, INT_MAX); 34 - __msg(": R0=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 34 + __msg("R{{.}}=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 35 35 check_assert(s64, <, lt_zero, 0); 36 - __msg(": R0=scalar(id=1,smax=0xffffffff7fffffff") 36 + __msg("R{{.}}=scalar(id=1,smax=0xffffffff7fffffff") 37 37 check_assert(s64, <, lt_neg, INT_MIN); 38 38 39 - __msg(": R0=scalar(id=1,smax=0x7fffffff)") 39 + __msg("R{{.}}=scalar(id=1,smax=0x7fffffff)") 40 40 check_assert(s64, <=, le_pos, INT_MAX); 41 - __msg(": R0=scalar(id=1,smax=0)") 41 + __msg("R{{.}}=scalar(id=1,smax=0)") 42 42 check_assert(s64, <=, le_zero, 0); 43 - __msg(": R0=scalar(id=1,smax=0xffffffff80000000") 43 + __msg("R{{.}}=scalar(id=1,smax=0xffffffff80000000") 44 44 check_assert(s64, <=, le_neg, INT_MIN); 45 45 46 - __msg(": R0=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 46 + __msg("R{{.}}=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 47 47 check_assert(s64, >, gt_pos, INT_MAX); 48 - __msg(": R0=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 48 + __msg("R{{.}}=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 49 49 check_assert(s64, >, gt_zero, 0); 50 - __msg(": R0=scalar(id=1,smin=0xffffffff80000001") 50 + __msg("R{{.}}=scalar(id=1,smin=0xffffffff80000001") 51 51 check_assert(s64, >, gt_neg, INT_MIN); 52 52 53 - __msg(": R0=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 53 + __msg("R{{.}}=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 54 54 check_assert(s64, >=, ge_pos, INT_MAX); 55 - __msg(": R0=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 55 + __msg("R{{.}}=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 56 56 check_assert(s64, >=, ge_zero, 0); 57 - __msg(": R0=scalar(id=1,smin=0xffffffff80000000") 57 + __msg("R{{.}}=scalar(id=1,smin=0xffffffff80000000") 58 58 check_assert(s64, >=, ge_neg, INT_MIN); 59 59 60 60 SEC("?tc")
+38 -1
tools/testing/selftests/bpf/progs/verifier_bounds.c
··· 1148 1148 SEC("xdp") 1149 1149 __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary") 1150 1150 __success __retval(0) 1151 - __flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ 1151 + __flag(BPF_F_TEST_REG_INVARIANTS) 1152 1152 __naked void crossing_32_bit_signed_boundary_2(void) 1153 1153 { 1154 1154 asm volatile (" \ ··· 1995 1995 if r0 == 0x10 goto +1; \ 1996 1996 r10 = 0; \ 1997 1997 exit; \ 1998 + " : 1999 + : __imm(bpf_get_prandom_u32) 2000 + : __clobber_all); 2001 + } 2002 + 2003 + SEC("socket") 2004 + __success 2005 + __flag(BPF_F_TEST_REG_INVARIANTS) 2006 + __naked void signed_unsigned_intersection32_case1(void *ctx) 2007 + { 2008 + asm volatile(" \ 2009 + call %[bpf_get_prandom_u32]; \ 2010 + w0 &= 0xffffffff; \ 2011 + if w0 < 0x3 goto 1f; /* on fall-through u32 range [3..U32_MAX] */ \ 2012 + if w0 s> 0x1 goto 1f; /* on fall-through s32 range [S32_MIN..1] */ \ 2013 + if w0 s< 0x0 goto 1f; /* range can be narrowed to [S32_MIN..-1] */ \ 2014 + r10 = 0; /* thus predicting the jump. */ \ 2015 + 1: exit; \ 2016 + " : 2017 + : __imm(bpf_get_prandom_u32) 2018 + : __clobber_all); 2019 + } 2020 + 2021 + SEC("socket") 2022 + __success 2023 + __flag(BPF_F_TEST_REG_INVARIANTS) 2024 + __naked void signed_unsigned_intersection32_case2(void *ctx) 2025 + { 2026 + asm volatile(" \ 2027 + call %[bpf_get_prandom_u32]; \ 2028 + w0 &= 0xffffffff; \ 2029 + if w0 > 0x80000003 goto 1f; /* on fall-through u32 range [0..S32_MIN+3] */ \ 2030 + if w0 s< -3 goto 1f; /* on fall-through s32 range [-3..S32_MAX] */ \ 2031 + if w0 s> 5 goto 1f; /* on fall-through s32 range [-3..5] */ \ 2032 + if w0 <= 5 goto 1f; /* range can be narrowed to [0..5] */ \ 2033 + r10 = 0; /* thus predicting the jump */ \ 2034 + 1: exit; \ 1998 2035 " : 1999 2036 : __imm(bpf_get_prandom_u32) 2000 2037 : __clobber_all);
+64
tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
··· 363 363 __sink(path[0]); 364 364 } 365 365 366 + void dummy_calls(void) 367 + { 368 + bpf_iter_num_new(0, 0, 0); 369 + bpf_iter_num_next(0); 370 + bpf_iter_num_destroy(0); 371 + } 372 + 373 + SEC("socket") 374 + __success 375 + __flag(BPF_F_TEST_STATE_FREQ) 376 + int spurious_precision_marks(void *ctx) 377 + { 378 + struct bpf_iter_num iter; 379 + 380 + asm volatile( 381 + "r1 = %[iter];" 382 + "r2 = 0;" 383 + "r3 = 10;" 384 + "call %[bpf_iter_num_new];" 385 + "1:" 386 + "r1 = %[iter];" 387 + "call %[bpf_iter_num_next];" 388 + "if r0 == 0 goto 4f;" 389 + "r7 = *(u32 *)(r0 + 0);" 390 + "r8 = *(u32 *)(r0 + 0);" 391 + /* This jump can't be predicted and does not change r7 or r8 state. */ 392 + "if r7 > r8 goto 2f;" 393 + /* Branch explored first ties r2 and r7 as having the same id. */ 394 + "r2 = r7;" 395 + "goto 3f;" 396 + "2:" 397 + /* Branch explored second does not tie r2 and r7 but has a function call. */ 398 + "call %[bpf_get_prandom_u32];" 399 + "3:" 400 + /* 401 + * A checkpoint. 402 + * When first branch is explored, this would inject linked registers 403 + * r2 and r7 into the jump history. 404 + * When second branch is explored, this would be a cache hit point, 405 + * triggering propagate_precision(). 406 + */ 407 + "if r7 <= 42 goto +0;" 408 + /* 409 + * Mark r7 as precise using an if condition that is always true. 410 + * When reached via the second branch, this triggered a bug in the backtrack_insn() 411 + * because r2 (tied to r7) was propagated as precise to a call. 412 + */ 413 + "if r7 <= 0xffffFFFF goto +0;" 414 + "goto 1b;" 415 + "4:" 416 + "r1 = %[iter];" 417 + "call %[bpf_iter_num_destroy];" 418 + : 419 + : __imm_ptr(iter), 420 + __imm(bpf_iter_num_new), 421 + __imm(bpf_iter_num_next), 422 + __imm(bpf_iter_num_destroy), 423 + __imm(bpf_get_prandom_u32) 424 + : __clobber_common, "r7", "r8" 425 + ); 426 + 427 + return 0; 428 + } 429 + 366 430 char _license[] SEC("license") = "GPL";
+42 -14
tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
··· 40 40 */ 41 41 "r3 = r10;" 42 42 "r3 += r0;" 43 + /* Mark r1 and r2 as alive. */ 44 + "r1 = r1;" 45 + "r2 = r2;" 43 46 "r0 = 0;" 44 47 "exit;" 45 48 : ··· 76 73 */ 77 74 "r4 = r10;" 78 75 "r4 += r0;" 76 + /* Mark r1 and r2 as alive. */ 77 + "r1 = r1;" 78 + "r2 = r2;" 79 79 "r0 = 0;" 80 80 "exit;" 81 81 : ··· 112 106 */ 113 107 "r4 = r10;" 114 108 "r4 += r3;" 109 + /* Mark r1 and r2 as alive. */ 110 + "r0 = r0;" 111 + "r1 = r1;" 112 + "r2 = r2;" 115 113 "r0 = 0;" 116 114 "exit;" 117 115 : ··· 153 143 */ 154 144 "r3 = r10;" 155 145 "r3 += r0;" 146 + /* Mark r1 and r2 as alive. */ 147 + "r1 = r1;" 148 + "r2 = r2;" 156 149 "r0 = 0;" 157 150 "exit;" 158 151 : ··· 169 156 */ 170 157 SEC("socket") 171 158 __success __log_level(2) 172 - __msg("12: (0f) r2 += r1") 159 + __msg("17: (0f) r2 += r1") 173 160 /* Current state */ 174 - __msg("frame2: last_idx 12 first_idx 11 subseq_idx -1 ") 175 - __msg("frame2: regs=r1 stack= before 11: (bf) r2 = r10") 161 + __msg("frame2: last_idx 17 first_idx 14 subseq_idx -1 ") 162 + __msg("frame2: regs=r1 stack= before 16: (bf) r2 = r10") 176 163 __msg("frame2: parent state regs=r1 stack=") 177 164 __msg("frame1: parent state regs= stack=") 178 165 __msg("frame0: parent state regs= stack=") 179 166 /* Parent state */ 180 - __msg("frame2: last_idx 10 first_idx 10 subseq_idx 11 ") 181 - __msg("frame2: regs=r1 stack= before 10: (25) if r1 > 0x7 goto pc+0") 167 + __msg("frame2: last_idx 13 first_idx 13 subseq_idx 14 ") 168 + __msg("frame2: regs=r1 stack= before 13: (25) if r1 > 0x7 goto pc+0") 182 169 __msg("frame2: parent state regs=r1 stack=") 183 170 /* frame1.r{6,7} are marked because mark_precise_scalar_ids() 184 171 * looks for all registers with frame2.r1.id in the current state ··· 186 173 __msg("frame1: parent state regs=r6,r7 stack=") 187 174 __msg("frame0: parent state regs=r6 stack=") 188 175 /* Parent state */ 189 - __msg("frame2: last_idx 8 first_idx 8 subseq_idx 10") 190 - __msg("frame2: regs=r1 stack= before 8: (85) call pc+1") 176 + __msg("frame2: last_idx 9 first_idx 9 subseq_idx 13") 177 + __msg("frame2: regs=r1 stack= before 9: (85) call pc+3") 191 178 /* frame1.r1 is marked because of backtracking of call instruction */ 192 179 __msg("frame1: parent state regs=r1,r6,r7 stack=") 193 180 __msg("frame0: parent state regs=r6 stack=") 194 181 /* Parent state */ 195 - __msg("frame1: last_idx 7 first_idx 6 subseq_idx 8") 196 - __msg("frame1: regs=r1,r6,r7 stack= before 7: (bf) r7 = r1") 197 - __msg("frame1: regs=r1,r6 stack= before 6: (bf) r6 = r1") 182 + __msg("frame1: last_idx 8 first_idx 7 subseq_idx 9") 183 + __msg("frame1: regs=r1,r6,r7 stack= before 8: (bf) r7 = r1") 184 + __msg("frame1: regs=r1,r6 stack= before 7: (bf) r6 = r1") 198 185 __msg("frame1: parent state regs=r1 stack=") 199 186 __msg("frame0: parent state regs=r6 stack=") 200 187 /* Parent state */ 201 - __msg("frame1: last_idx 4 first_idx 4 subseq_idx 6") 202 - __msg("frame1: regs=r1 stack= before 4: (85) call pc+1") 188 + __msg("frame1: last_idx 4 first_idx 4 subseq_idx 7") 189 + __msg("frame1: regs=r1 stack= before 4: (85) call pc+2") 203 190 __msg("frame0: parent state regs=r1,r6 stack=") 204 191 /* Parent state */ 205 192 __msg("frame0: last_idx 3 first_idx 1 subseq_idx 4") ··· 217 204 "r1 = r0;" 218 205 "r6 = r0;" 219 206 "call precision_many_frames__foo;" 207 + "r6 = r6;" /* mark r6 as live */ 220 208 "exit;" 221 209 : 222 210 : __imm(bpf_ktime_get_ns) ··· 234 220 "r6 = r1;" 235 221 "r7 = r1;" 236 222 "call precision_many_frames__bar;" 223 + "r6 = r6;" /* mark r6 as live */ 224 + "r7 = r7;" /* mark r7 as live */ 237 225 "exit" 238 226 ::: __clobber_all); 239 227 } ··· 245 229 { 246 230 asm volatile ( 247 231 "if r1 > 7 goto +0;" 232 + "r6 = 0;" /* mark r6 as live */ 233 + "r7 = 0;" /* mark r7 as live */ 248 234 /* force r1 to be precise, this eventually marks: 249 235 * - bar frame r1 250 236 * - foo frame r{1,6,7} ··· 358 340 "r3 += r7;" 359 341 /* force r9 to be precise, this also marks r8 */ 360 342 "r3 += r9;" 343 + "r6 = r6;" /* mark r6 as live */ 344 + "r8 = r8;" /* mark r8 as live */ 361 345 "exit;" 362 346 : 363 347 : __imm(bpf_ktime_get_ns) ··· 373 353 * collect_linked_regs() can't tie more than 6 registers for a single insn. 374 354 */ 375 355 __msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1") 376 - __msg("9: (bf) r6 = r6 ; R6=scalar(id=2") 356 + __msg("14: (bf) r6 = r6 ; R6=scalar(id=2") 377 357 /* check that r{0-5} are marked precise after 'if' */ 378 358 __msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0") 379 359 __msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:") ··· 392 372 "r6 = r0;" 393 373 /* propagate range for r{0-6} */ 394 374 "if r0 > 7 goto +0;" 375 + /* keep r{1-5} live */ 376 + "r1 = r1;" 377 + "r2 = r2;" 378 + "r3 = r3;" 379 + "r4 = r4;" 380 + "r5 = r5;" 395 381 /* make r6 appear in the log */ 396 382 "r6 = r6;" 397 383 /* force r0 to be precise, ··· 543 517 "*(u64*)(r10 - 8) = r1;" 544 518 /* r9 = pointer to stack */ 545 519 "r9 = r10;" 546 - "r9 += -8;" 520 + "r9 += -16;" 547 521 /* r8 = ktime_get_ns() */ 548 522 "call %[bpf_ktime_get_ns];" 549 523 "r8 = r0;" ··· 564 538 "if r7 > 4 goto l2_%=;" 565 539 /* Access memory at r9[r6] */ 566 540 "r9 += r6;" 541 + "r9 += r7;" 542 + "r9 += r8;" 567 543 "r0 = *(u8*)(r9 + 0);" 568 544 "l2_%=:" 569 545 "r0 = 0;"
+4 -4
tools/testing/selftests/bpf/verifier/precise.c
··· 44 44 mark_precise: frame0: regs=r2 stack= before 23\ 45 45 mark_precise: frame0: regs=r2 stack= before 22\ 46 46 mark_precise: frame0: regs=r2 stack= before 20\ 47 - mark_precise: frame0: parent state regs=r2,r9 stack=:\ 47 + mark_precise: frame0: parent state regs=r2 stack=:\ 48 48 mark_precise: frame0: last_idx 19 first_idx 10\ 49 - mark_precise: frame0: regs=r2,r9 stack= before 19\ 49 + mark_precise: frame0: regs=r2 stack= before 19\ 50 50 mark_precise: frame0: regs=r9 stack= before 18\ 51 51 mark_precise: frame0: regs=r8,r9 stack= before 17\ 52 52 mark_precise: frame0: regs=r0,r9 stack= before 15\ ··· 107 107 mark_precise: frame0: parent state regs=r2 stack=:\ 108 108 mark_precise: frame0: last_idx 20 first_idx 20\ 109 109 mark_precise: frame0: regs=r2 stack= before 20\ 110 - mark_precise: frame0: parent state regs=r2,r9 stack=:\ 110 + mark_precise: frame0: parent state regs=r2 stack=:\ 111 111 mark_precise: frame0: last_idx 19 first_idx 17\ 112 - mark_precise: frame0: regs=r2,r9 stack= before 19\ 112 + mark_precise: frame0: regs=r2 stack= before 19\ 113 113 mark_precise: frame0: regs=r9 stack= before 18\ 114 114 mark_precise: frame0: regs=r8,r9 stack= before 17\ 115 115 mark_precise: frame0: parent state regs= stack=:",