Daniel Borkmann says: ==================== pull-request: bpf 2024-06-24 We've added 12 non-merge commits during the last 10 day(s) which contain a total of 10 files changed, 412 insertions(+), 16 deletions(-). The main changes are: 1) Fix a BPF verifier issue validating may_goto with a negative offset, from Alexei Starovoitov. 2) Fix a BPF verifier validation bug with may_goto combined with jump to the first instruction, also from Alexei Starovoitov. 3) Fix a bug with overrunning reservations in BPF ring buffer, from Daniel Borkmann. 4) Fix a bug in BPF verifier due to missing proper var_off setting related to movsx instruction, from Yonghong Song. 5) Silence unnecessary syzkaller-triggered warning in __xdp_reg_mem_model(), from Daniil Dulov. * tag 'for-netdev' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: xdp: Remove WARN() from __xdp_reg_mem_model() selftests/bpf: Add tests for may_goto with negative offset. bpf: Fix may_goto with negative offset. selftests/bpf: Add more ring buffer test coverage bpf: Fix overrunning reservations in ringbuf selftests/bpf: Tests with may_goto and jumps to the 1st insn bpf: Fix the corner case with may_goto and jump to the 1st insn. bpf: Update BPF LSM maintainer list bpf: Fix remap of arena. selftests/bpf: Add a few tests to cover bpf: Add missed var_off setting in coerce_subreg_to_size_sx() bpf: Add missed var_off setting in set_sext32_default_val() ====================
Showing the changes to kernel (3 of 10 files). Show all
Unified · Split
| @@ -212,6 +212,7 @@ static u64 arena_map_mem_usage(const struct bpf_map *map) · 211 unmodified lines | ||
| 212 | 212 | struct vma_list { |
| 213 | 213 | struct vm_area_struct *vma; |
| 214 | 214 | struct list_head head; |
| 215 | + atomic_t mmap_count; | |
| 215 | 216 | }; |
| 216 | 217 | |
| 217 | 218 | static int remember_vma(struct bpf_arena *arena, struct vm_area_struct *vma) |
| @@ -221,20 +222,30 @@ static int remember_vma(struct bpf_arena *arena, struct vm_area_struct *vma) · 3 unmodified lines | ||
| 221 | 222 | vml = kmalloc(sizeof(*vml), GFP_KERNEL); |
| 222 | 223 | if (!vml) |
| 223 | 224 | return -ENOMEM; |
| 225 | + atomic_set(&vml->mmap_count, 1); | |
| 224 | 226 | vma->vm_private_data = vml; |
| 225 | 227 | vml->vma = vma; |
| 226 | 228 | list_add(&vml->head, &arena->vma_list); |
| 227 | 229 | return 0; |
| 228 | 230 | } |
| 229 | 231 | |
| 232 | +static void arena_vm_open(struct vm_area_struct *vma) | |
| 233 | +{ | |
| 234 | + struct vma_list *vml = vma->vm_private_data; | |
| 235 | + | |
| 236 | + atomic_inc(&vml->mmap_count); | |
| 237 | +} | |
| 238 | + | |
| 230 | 239 | static void arena_vm_close(struct vm_area_struct *vma) |
| 231 | 240 | { |
| 232 | 241 | struct bpf_map *map = vma->vm_file->private_data; |
| 233 | 242 | struct bpf_arena *arena = container_of(map, struct bpf_arena, map); |
| 234 | − struct vma_list *vml; | |
| 243 | + struct vma_list *vml = vma->vm_private_data; | |
| 235 | 244 | |
| 245 | + if (!atomic_dec_and_test(&vml->mmap_count)) | |
| 246 | + return; | |
| 236 | 247 | guard(mutex)(&arena->lock); |
| 237 | − vml = vma->vm_private_data; | |
| 248 | + /* update link list under lock */ | |
| 238 | 249 | list_del(&vml->head); |
| 239 | 250 | vma->vm_private_data = NULL; |
| 240 | 251 | kfree(vml); |
| @@ -287,6 +298,7 @@ out: · 46 unmodified lines | ||
| 287 | 298 | } |
| 288 | 299 | |
| 289 | 300 | static const struct vm_operations_struct arena_vm_ops = { |
| 301 | + .open = arena_vm_open, | |
| 290 | 302 | .close = arena_vm_close, |
| 291 | 303 | .fault = arena_vm_fault, |
| 292 | 304 | }; |
| @@ -51,7 +51,8 @@ struct bpf_ringbuf { · 50 unmodified lines | ||
| 51 | 51 | * This prevents a user-space application from modifying the |
| 52 | 52 | * position and ruining in-kernel tracking. The permissions of the |
| 53 | 53 | * pages depend on who is producing samples: user-space or the |
| 54 | − * kernel. | |
| 54 | + * kernel. Note that the pending counter is placed in the same | |
| 55 | + * page as the producer, so that it shares the same cache line. | |
| 55 | 56 | * |
| 56 | 57 | * Kernel-producer |
| 57 | 58 | * --------------- |
| @@ -70,6 +71,7 @@ struct bpf_ringbuf { · 12 unmodified lines | ||
| 70 | 71 | */ |
| 71 | 72 | unsigned long consumer_pos __aligned(PAGE_SIZE); |
| 72 | 73 | unsigned long producer_pos __aligned(PAGE_SIZE); |
| 74 | + unsigned long pending_pos; | |
| 73 | 75 | char data[] __aligned(PAGE_SIZE); |
| 74 | 76 | }; |
| 75 | 77 | |
| @@ -179,6 +181,7 @@ static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node) · 103 unmodified lines | ||
| 179 | 181 | rb->mask = data_sz - 1; |
| 180 | 182 | rb->consumer_pos = 0; |
| 181 | 183 | rb->producer_pos = 0; |
| 184 | + rb->pending_pos = 0; | |
| 182 | 185 | |
| 183 | 186 | return rb; |
| 184 | 187 | } |
| @@ -404,9 +407,9 @@ bpf_ringbuf_restore_from_rec(struct bpf_ringbuf_hdr *hdr) · 219 unmodified lines | ||
| 404 | 407 | |
| 405 | 408 | static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size) |
| 406 | 409 | { |
| 407 | − unsigned long cons_pos, prod_pos, new_prod_pos, flags; | |
| 408 | − u32 len, pg_off; | |
| 410 | + unsigned long cons_pos, prod_pos, new_prod_pos, pend_pos, flags; | |
| 409 | 411 | struct bpf_ringbuf_hdr *hdr; |
| 412 | + u32 len, pg_off, tmp_size, hdr_len; | |
| 410 | 413 | |
| 411 | 414 | if (unlikely(size > RINGBUF_MAX_RECORD_SZ)) |
| 412 | 415 | return NULL; |
| @@ -424,13 +427,29 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size) · 11 unmodified lines | ||
| 424 | 427 | spin_lock_irqsave(&rb->spinlock, flags); |
| 425 | 428 | } |
| 426 | 429 | |
| 430 | + pend_pos = rb->pending_pos; | |
| 427 | 431 | prod_pos = rb->producer_pos; |
| 428 | 432 | new_prod_pos = prod_pos + len; |
| 429 | 433 | |
| 430 | − /* check for out of ringbuf space by ensuring producer position | |
| 431 | − * doesn't advance more than (ringbuf_size - 1) ahead | |
| 434 | + while (pend_pos < prod_pos) { | |
| 435 | + hdr = (void *)rb->data + (pend_pos & rb->mask); | |
| 436 | + hdr_len = READ_ONCE(hdr->len); | |
| 437 | + if (hdr_len & BPF_RINGBUF_BUSY_BIT) | |
| 438 | + break; | |
| 439 | + tmp_size = hdr_len & ~BPF_RINGBUF_DISCARD_BIT; | |
| 440 | + tmp_size = round_up(tmp_size + BPF_RINGBUF_HDR_SZ, 8); | |
| 441 | + pend_pos += tmp_size; | |
| 442 | + } | |
| 443 | + rb->pending_pos = pend_pos; | |
| 444 | + | |
| 445 | + /* check for out of ringbuf space: | |
| 446 | + * - by ensuring producer position doesn't advance more than | |
| 447 | + * (ringbuf_size - 1) ahead | |
| 448 | + * - by ensuring oldest not yet committed record until newest | |
| 449 | + * record does not span more than (ringbuf_size - 1) | |
| 432 | 450 | */ |
| 433 | − if (new_prod_pos - cons_pos > rb->mask) { | |
| 451 | + if (new_prod_pos - cons_pos > rb->mask || | |
| 452 | + new_prod_pos - pend_pos > rb->mask) { | |
| 434 | 453 | spin_unlock_irqrestore(&rb->spinlock, flags); |
| 435 | 454 | return NULL; |
| 436 | 455 | } |
| @@ -6236,6 +6236,7 @@ static void set_sext32_default_val(struct bpf_reg_state *reg, int size) · 6235 unmodified lines | ||
| 6236 | 6236 | } |
| 6237 | 6237 | reg->u32_min_value = 0; |
| 6238 | 6238 | reg->u32_max_value = U32_MAX; |
| 6239 | + reg->var_off = tnum_subreg(tnum_unknown); | |
| 6239 | 6240 | } |
| 6240 | 6241 | |
| 6241 | 6242 | static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size) |
| @@ -6280,6 +6281,7 @@ static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size) · 38 unmodified lines | ||
| 6280 | 6281 | reg->s32_max_value = s32_max; |
| 6281 | 6282 | reg->u32_min_value = (u32)s32_min; |
| 6282 | 6283 | reg->u32_max_value = (u32)s32_max; |
| 6284 | + reg->var_off = tnum_subreg(tnum_range(s32_min, s32_max)); | |
| 6283 | 6285 | return; |
| 6284 | 6286 | } |
| 6285 | 6287 | |
| @@ -12719,6 +12721,16 @@ static bool signed_add32_overflows(s32 a, s32 b) · 6433 unmodified lines | ||
| 12719 | 12721 | return res < a; |
| 12720 | 12722 | } |
| 12721 | 12723 | |
| 12724 | +static bool signed_add16_overflows(s16 a, s16 b) | |
| 12725 | +{ | |
| 12726 | + /* Do the add in u16, where overflow is well-defined */ | |
| 12727 | + s16 res = (s16)((u16)a + (u16)b); | |
| 12728 | + | |
| 12729 | + if (b < 0) | |
| 12730 | + return res > a; | |
| 12731 | + return res < a; | |
| 12732 | +} | |
| 12733 | + | |
| 12722 | 12734 | static bool signed_sub_overflows(s64 a, s64 b) |
| 12723 | 12735 | { |
| 12724 | 12736 | /* Do the sub in u64, where overflow is well-defined */ |
| @@ -17448,11 +17460,11 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) · 4723 unmodified lines | ||
| 17448 | 17460 | goto skip_inf_loop_check; |
| 17449 | 17461 | } |
| 17450 | 17462 | if (is_may_goto_insn_at(env, insn_idx)) { |
| 17451 | − if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) { | |
| 17463 | + if (sl->state.may_goto_depth != cur->may_goto_depth && | |
| 17464 | + states_equal(env, &sl->state, cur, RANGE_WITHIN)) { | |
| 17452 | 17465 | update_loop_entry(cur, &sl->state); |
| 17453 | 17466 | goto hit; |
| 17454 | 17467 | } |
| 17455 | − goto skip_inf_loop_check; | |
| 17456 | 17468 | } |
| 17457 | 17469 | if (calls_callback(env, insn_idx)) { |
| 17458 | 17470 | if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) |
| @@ -18730,6 +18742,39 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of · 1271 unmodified lines | ||
| 18730 | 18742 | return new_prog; |
| 18731 | 18743 | } |
| 18732 | 18744 | |
| 18745 | +/* | |
| 18746 | + * For all jmp insns in a given 'prog' that point to 'tgt_idx' insn adjust the | |
| 18747 | + * jump offset by 'delta'. | |
| 18748 | + */ | |
| 18749 | +static int adjust_jmp_off(struct bpf_prog *prog, u32 tgt_idx, u32 delta) | |
| 18750 | +{ | |
| 18751 | + struct bpf_insn *insn = prog->insnsi; | |
| 18752 | + u32 insn_cnt = prog->len, i; | |
| 18753 | + | |
| 18754 | + for (i = 0; i < insn_cnt; i++, insn++) { | |
| 18755 | + u8 code = insn->code; | |
| 18756 | + | |
| 18757 | + if ((BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) || | |
| 18758 | + BPF_OP(code) == BPF_CALL || BPF_OP(code) == BPF_EXIT) | |
| 18759 | + continue; | |
| 18760 | + | |
| 18761 | + if (insn->code == (BPF_JMP32 | BPF_JA)) { | |
| 18762 | + if (i + 1 + insn->imm != tgt_idx) | |
| 18763 | + continue; | |
| 18764 | + if (signed_add32_overflows(insn->imm, delta)) | |
| 18765 | + return -ERANGE; | |
| 18766 | + insn->imm += delta; | |
| 18767 | + } else { | |
| 18768 | + if (i + 1 + insn->off != tgt_idx) | |
| 18769 | + continue; | |
| 18770 | + if (signed_add16_overflows(insn->imm, delta)) | |
| 18771 | + return -ERANGE; | |
| 18772 | + insn->off += delta; | |
| 18773 | + } | |
| 18774 | + } | |
| 18775 | + return 0; | |
| 18776 | +} | |
| 18777 | + | |
| 18733 | 18778 | static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env, |
| 18734 | 18779 | u32 off, u32 cnt) |
| 18735 | 18780 | { |
| @@ -20004,7 +20049,10 @@ static int do_misc_fixups(struct bpf_verifier_env *env) · 1268 unmodified lines | ||
| 20004 | 20049 | |
| 20005 | 20050 | stack_depth_extra = 8; |
| 20006 | 20051 | insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_AX, BPF_REG_10, stack_off); |
| 20007 | − insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 2); | |
| 20052 | + if (insn->off >= 0) | |
| 20053 | + insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 2); | |
| 20054 | + else | |
| 20055 | + insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off - 1); | |
| 20008 | 20056 | insn_buf[2] = BPF_ALU64_IMM(BPF_SUB, BPF_REG_AX, 1); |
| 20009 | 20057 | insn_buf[3] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_AX, stack_off); |
| 20010 | 20058 | cnt = 4; |
| @@ -20546,6 +20594,13 @@ next_insn: · 535 unmodified lines | ||
| 20546 | 20594 | if (!new_prog) |
| 20547 | 20595 | return -ENOMEM; |
| 20548 | 20596 | env->prog = prog = new_prog; |
| 20597 | + /* | |
| 20598 | + * If may_goto is a first insn of a prog there could be a jmp | |
| 20599 | + * insn that points to it, hence adjust all such jmps to point | |
| 20600 | + * to insn after BPF_ST that inits may_goto count. | |
| 20601 | + * Adjustment will succeed because bpf_patch_insn_data() didn't fail. | |
| 20602 | + */ | |
| 20603 | + WARN_ON(adjust_jmp_off(env->prog, subprog_start, 1)); | |
| 20549 | 20604 | } |
| 20550 | 20605 | |
| 20551 | 20606 | /* Since poke tab is now finalized, publish aux to tracker. */ |