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.

bpf: Account for BPF_FETCH in insn_has_def32()

insn_has_def32() returns false for 32-bit BPF_FETCH insns. This makes
adjust_insn_aux_data() incorrectly set zext_dst, as can be seen in [1].
This happens because insn_no_def() does not know about the BPF_FETCH
variants of BPF_STX.

Fix in two steps.

First, replace insn_no_def() with insn_def_regno(), which returns the
register an insn defines. Normally insn_no_def() calls are followed by
insn->dst_reg uses; replace those with the insn_def_regno() return
value.

Second, adjust the BPF_STX special case in is_reg64() to deal with
queries made from opt_subreg_zext_lo32_rnd_hi32(), where the state
information is no longer available. Add a comment, since the purpose
of this special case is not clear at first glance.

[1] https://lore.kernel.org/bpf/20210223150845.1857620-1-jackmanb@google.com/

Fixes: 5ffa25502b5a ("bpf: Add instructions for atomic_[cmp]xchg")
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Brendan Jackman <jackmanb@google.com>
Link: https://lore.kernel.org/bpf/20210301154019.129110-1-iii@linux.ibm.com

authored by

Ilya Leoshkevich and committed by
Daniel Borkmann
83a28819 2b2aedab

+39 -31
+39 -31
kernel/bpf/verifier.c
··· 1703 1703 } 1704 1704 1705 1705 if (class == BPF_STX) { 1706 - if (reg->type != SCALAR_VALUE) 1706 + /* BPF_STX (including atomic variants) has multiple source 1707 + * operands, one of which is a ptr. Check whether the caller is 1708 + * asking about it. 1709 + */ 1710 + if (t == SRC_OP && reg->type != SCALAR_VALUE) 1707 1711 return true; 1708 1712 return BPF_SIZE(code) == BPF_DW; 1709 1713 } ··· 1739 1735 return true; 1740 1736 } 1741 1737 1742 - /* Return TRUE if INSN doesn't have explicit value define. */ 1743 - static bool insn_no_def(struct bpf_insn *insn) 1738 + /* Return the regno defined by the insn, or -1. */ 1739 + static int insn_def_regno(const struct bpf_insn *insn) 1744 1740 { 1745 - u8 class = BPF_CLASS(insn->code); 1746 - 1747 - return (class == BPF_JMP || class == BPF_JMP32 || 1748 - class == BPF_STX || class == BPF_ST); 1741 + switch (BPF_CLASS(insn->code)) { 1742 + case BPF_JMP: 1743 + case BPF_JMP32: 1744 + case BPF_ST: 1745 + return -1; 1746 + case BPF_STX: 1747 + if (BPF_MODE(insn->code) == BPF_ATOMIC && 1748 + (insn->imm & BPF_FETCH)) { 1749 + if (insn->imm == BPF_CMPXCHG) 1750 + return BPF_REG_0; 1751 + else 1752 + return insn->src_reg; 1753 + } else { 1754 + return -1; 1755 + } 1756 + default: 1757 + return insn->dst_reg; 1758 + } 1749 1759 } 1750 1760 1751 1761 /* Return TRUE if INSN has defined any 32-bit value explicitly. */ 1752 1762 static bool insn_has_def32(struct bpf_verifier_env *env, struct bpf_insn *insn) 1753 1763 { 1754 - if (insn_no_def(insn)) 1764 + int dst_reg = insn_def_regno(insn); 1765 + 1766 + if (dst_reg == -1) 1755 1767 return false; 1756 1768 1757 - return !is_reg64(env, insn, insn->dst_reg, NULL, DST_OP); 1769 + return !is_reg64(env, insn, dst_reg, NULL, DST_OP); 1758 1770 } 1759 1771 1760 1772 static void mark_insn_zext(struct bpf_verifier_env *env, ··· 11026 11006 for (i = 0; i < len; i++) { 11027 11007 int adj_idx = i + delta; 11028 11008 struct bpf_insn insn; 11029 - u8 load_reg; 11009 + int load_reg; 11030 11010 11031 11011 insn = insns[adj_idx]; 11012 + load_reg = insn_def_regno(&insn); 11032 11013 if (!aux[adj_idx].zext_dst) { 11033 11014 u8 code, class; 11034 11015 u32 imm_rnd; ··· 11039 11018 11040 11019 code = insn.code; 11041 11020 class = BPF_CLASS(code); 11042 - if (insn_no_def(&insn)) 11021 + if (load_reg == -1) 11043 11022 continue; 11044 11023 11045 11024 /* NOTE: arg "reg" (the fourth one) is only used for 11046 - * BPF_STX which has been ruled out in above 11047 - * check, it is safe to pass NULL here. 11025 + * BPF_STX + SRC_OP, so it is safe to pass NULL 11026 + * here. 11048 11027 */ 11049 - if (is_reg64(env, &insn, insn.dst_reg, NULL, DST_OP)) { 11028 + if (is_reg64(env, &insn, load_reg, NULL, DST_OP)) { 11050 11029 if (class == BPF_LD && 11051 11030 BPF_MODE(code) == BPF_IMM) 11052 11031 i++; ··· 11061 11040 imm_rnd = get_random_int(); 11062 11041 rnd_hi32_patch[0] = insn; 11063 11042 rnd_hi32_patch[1].imm = imm_rnd; 11064 - rnd_hi32_patch[3].dst_reg = insn.dst_reg; 11043 + rnd_hi32_patch[3].dst_reg = load_reg; 11065 11044 patch = rnd_hi32_patch; 11066 11045 patch_len = 4; 11067 11046 goto apply_patch_buffer; ··· 11070 11049 if (!bpf_jit_needs_zext()) 11071 11050 continue; 11072 11051 11073 - /* zext_dst means that we want to zero-extend whatever register 11074 - * the insn defines, which is dst_reg most of the time, with 11075 - * the notable exception of BPF_STX + BPF_ATOMIC + BPF_FETCH. 11076 - */ 11077 - if (BPF_CLASS(insn.code) == BPF_STX && 11078 - BPF_MODE(insn.code) == BPF_ATOMIC) { 11079 - /* BPF_STX + BPF_ATOMIC insns without BPF_FETCH do not 11080 - * define any registers, therefore zext_dst cannot be 11081 - * set. 11082 - */ 11083 - if (WARN_ON(!(insn.imm & BPF_FETCH))) 11084 - return -EINVAL; 11085 - load_reg = insn.imm == BPF_CMPXCHG ? BPF_REG_0 11086 - : insn.src_reg; 11087 - } else { 11088 - load_reg = insn.dst_reg; 11052 + if (WARN_ON(load_reg == -1)) { 11053 + verbose(env, "verifier bug. zext_dst is set, but no reg is defined\n"); 11054 + return -EFAULT; 11089 11055 } 11090 11056 11091 11057 zext_patch[0] = insn;