Pull BPF fixes from Daniel Borkmann: - Fix BPF verifier to preserve full pointer state for commuted scalar += pointer arithmetic (Yiyang Chen, Eduard Zingerman) - Fix a use-after-free of request sockets in the BPF TCP iterator batching (Jose Fernandez) - Fix a use-after-free of sk_redir in the BPF sockmap send verdict path (Chengfeng Ye) - Fix a netns reference imbalance in the BPF conntrack kfuncs (Chengfeng Ye) - Fix bpf_get_fsverity_digest() dynptr assumptions and silent digest truncation (Eric Biggers) - Fix bpf_tcp_{gen,check}_syncookie to check sk_state before sk_protocol to make sure it is a full socket (Luxiao Xu) - Fix rqspinlock to reset the tail when preserving the queue on deadlock (Kumar Kartikeya Dwivedi) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: rqspinlock: Reset tail when preserving queue on deadlock bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie fsverity: Fix silent truncation in bpf_get_fsverity_digest() fsverity: Fix bpf_get_fsverity_digest() dynptr assumptions bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch() bpf: Fix netns reference imbalance in conntrack kfuncs bpf, sockmap: Fix sk_redir use-after-free in send verdict selftests/bpf: Cover commuted pointer state propagation bpf: Propagate untrusted pointer state in commuted arithmetic bpf: Preserve pointer state for commuted arithmetic bpf: Simplify sanitize_err() signature
Showing the changes to kernel (2 of 10 files). Show all
Unified · Split
| @@ -572,9 +572,10 @@ queue: · 571 unmodified lines | |||
| 572 | 572 | ||
| 573 | /* Disable queue destruction when we detect deadlocks. */ | 573 | /* Disable queue destruction when we detect deadlocks. */ |
| 574 | if (ret == -EDEADLK) { | 574 | if (ret == -EDEADLK) { |
| 575 | if (!next) | 575 | if (!try_cmpxchg_tail(lock, tail, 0)) { |
| 576 | next = smp_cond_load_relaxed(&node->next, (VAL)); | 576 | next = smp_cond_load_relaxed(&node->next, (VAL)); |
| 577 | arch_mcs_spin_unlock_contended(&next->locked); | 577 | arch_mcs_spin_unlock_contended(&next->locked); |
| 578 | } | ||
| 578 | goto err_release_node; | 579 | goto err_release_node; |
| 579 | } | 580 | } |
| 580 | 581 | ||
| @@ -13557,23 +13557,21 @@ static void sanitize_mark_insn_seen(struct bpf_verifier_env *env) · 13556 unmodified lines | |||
| 13557 | env->insn_aux_data[env->insn_idx].seen = env->pass_cnt; | 13557 | env->insn_aux_data[env->insn_idx].seen = env->pass_cnt; |
| 13558 | } | 13558 | } |
| 13559 | 13559 | ||
| 13560 | static int sanitize_err(struct bpf_verifier_env *env, | 13560 | static int sanitize_err(struct bpf_verifier_env *env, const struct bpf_insn *insn, int reason) |
| 13561 | const struct bpf_insn *insn, int reason, | ||
| 13562 | const struct bpf_reg_state *off_reg, | ||
| 13563 | const struct bpf_reg_state *dst_reg) | ||
| 13564 | { | 13561 | { |
| 13565 | static const char *err = "pointer arithmetic with it prohibited for !root"; | 13562 | static const char *err = "pointer arithmetic with it prohibited for !root"; |
| 13566 | const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub"; | 13563 | const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub"; |
| 13567 | u32 dst = insn->dst_reg, src = insn->src_reg; | 13564 | u32 dst = insn->dst_reg, src = insn->src_reg; |
| 13565 | struct bpf_reg_state *regs = cur_regs(env); | ||
| 13568 | 13566 | ||
| 13569 | switch (reason) { | 13567 | switch (reason) { |
| 13570 | case REASON_BOUNDS: | 13568 | case REASON_BOUNDS: |
| 13571 | verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n", | 13569 | verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n", |
| 13572 | off_reg == dst_reg ? dst : src, err); | 13570 | regs[src].type == SCALAR_VALUE ? src : dst, err); |
| 13573 | break; | 13571 | break; |
| 13574 | case REASON_TYPE: | 13572 | case REASON_TYPE: |
| 13575 | verbose(env, "R%d has pointer with unsupported alu operation, %s\n", | 13573 | verbose(env, "R%d has pointer with unsupported alu operation, %s\n", |
| 13576 | off_reg == dst_reg ? src : dst, err); | 13574 | regs[src].type == SCALAR_VALUE ? dst : src, err); |
| 13577 | break; | 13575 | break; |
| 13578 | case REASON_PATHS: | 13576 | case REASON_PATHS: |
| 13579 | verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n", | 13577 | verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n", |
| @@ -13709,13 +13707,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 129 unmodified lines | |||
| 13709 | return -EACCES; | 13707 | return -EACCES; |
| 13710 | } | 13708 | } |
| 13711 | 13709 | ||
| 13712 | /* | ||
| 13713 | * Accesses to untrusted PTR_TO_MEM are done through probe | ||
| 13714 | * instructions, hence no need to track offsets. | ||
| 13715 | */ | ||
| 13716 | if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED)) | ||
| 13717 | return 0; | ||
| 13718 | |||
| 13719 | switch (base_type(ptr_reg->type)) { | 13710 | switch (base_type(ptr_reg->type)) { |
| 13720 | case PTR_TO_CTX: | 13711 | case PTR_TO_CTX: |
| 13721 | case PTR_TO_MAP_VALUE: | 13712 | case PTR_TO_MAP_VALUE: |
| @@ -13745,11 +13736,19 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 23 unmodified lines | |||
| 13745 | return -EACCES; | 13736 | return -EACCES; |
| 13746 | } | 13737 | } |
| 13747 | 13738 | ||
| 13748 | /* In case of 'scalar += pointer', dst_reg inherits pointer type and id. | 13739 | /* For 'scalar += pointer', dst_reg inherits the complete pointer |
| 13749 | * The id may be overwritten later if we create a new variable offset. | 13740 | * register state. Individual fields may be adjusted later by pointer |
| 13741 | * arithmetic. Callers guarantee that below does not overwrite off_reg. | ||
| 13750 | */ | 13742 | */ |
| 13751 | dst_reg->type = ptr_reg->type; | 13743 | if (dst_reg != ptr_reg) |
| 13752 | dst_reg->id = ptr_reg->id; | 13744 | *dst_reg = *ptr_reg; |
| 13745 | |||
| 13746 | /* | ||
| 13747 | * Accesses to untrusted PTR_TO_MEM are done through probe | ||
| 13748 | * instructions, hence no need to track offsets. | ||
| 13749 | */ | ||
| 13750 | if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED)) | ||
| 13751 | return 0; | ||
| 13753 | 13752 | ||
| 13754 | if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) || | 13753 | if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) || |
| 13755 | !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type)) | 13754 | !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type)) |
| @@ -13762,7 +13761,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 6 unmodified lines | |||
| 13762 | ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg, | 13761 | ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg, |
| 13763 | &info, false); | 13762 | &info, false); |
| 13764 | if (ret < 0) | 13763 | if (ret < 0) |
| 13765 | return sanitize_err(env, insn, ret, off_reg, dst_reg); | 13764 | return sanitize_err(env, insn, ret); |
| 13766 | } | 13765 | } |
| 13767 | 13766 | ||
| 13768 | switch (opcode) { | 13767 | switch (opcode) { |
| @@ -13792,7 +13791,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 23 unmodified lines | |||
| 13792 | } | 13791 | } |
| 13793 | break; | 13792 | break; |
| 13794 | case BPF_SUB: | 13793 | case BPF_SUB: |
| 13795 | if (dst_reg == off_reg) { | 13794 | if (dst_reg != ptr_reg) { |
| 13796 | /* scalar -= pointer. Creates an unknown scalar */ | 13795 | /* scalar -= pointer. Creates an unknown scalar */ |
| 13797 | verbose(env, "R%d tried to subtract pointer from scalar\n", | 13796 | verbose(env, "R%d tried to subtract pointer from scalar\n", |
| 13798 | dst); | 13797 | dst); |
| @@ -13855,7 +13854,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 56 unmodified lines | |||
| 13855 | return -EFAULT; | 13854 | return -EFAULT; |
| 13856 | } | 13855 | } |
| 13857 | if (ret < 0) | 13856 | if (ret < 0) |
| 13858 | return sanitize_err(env, insn, ret, off_reg, dst_reg); | 13857 | return sanitize_err(env, insn, ret); |
| 13859 | } | 13858 | } |
| 13860 | 13859 | ||
| 13861 | return 0; | 13860 | return 0; |
| @@ -14607,7 +14606,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, · 745 unmodified lines | |||
| 14607 | if (sanitize_needed(opcode)) { | 14606 | if (sanitize_needed(opcode)) { |
| 14608 | ret = sanitize_val_alu(env, insn); | 14607 | ret = sanitize_val_alu(env, insn); |
| 14609 | if (ret < 0) | 14608 | if (ret < 0) |
| 14610 | return sanitize_err(env, insn, ret, NULL, NULL); | 14609 | return sanitize_err(env, insn, ret); |
| 14611 | } | 14610 | } |
| 14612 | 14611 | ||
| 14613 | /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops. | 14612 | /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops. |
| @@ -14810,8 +14809,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, · 196 unmodified lines | |||
| 14810 | err = mark_chain_precision(env, insn->dst_reg); | 14809 | err = mark_chain_precision(env, insn->dst_reg); |
| 14811 | if (err) | 14810 | if (err) |
| 14812 | return err; | 14811 | return err; |
| 14813 | return adjust_ptr_min_max_vals(env, insn, | 14812 | off_reg = *dst_reg; |
| 14814 | src_reg, dst_reg); | 14813 | return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg); |
| 14815 | } | 14814 | } |
| 14816 | } else if (ptr_reg) { | 14815 | } else if (ptr_reg) { |
| 14817 | /* pointer += scalar */ | 14816 | /* pointer += scalar */ |