aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/verifier.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r--kernel/bpf/verifier.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 48c2705db22c..90493a66dddd 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1637,21 +1637,42 @@ static int check_alu_op(struct verifier_env *env, struct bpf_insn *insn)
1637 return 0; 1637 return 0;
1638} 1638}
1639 1639
1640static void find_good_pkt_pointers(struct verifier_env *env, 1640static void find_good_pkt_pointers(struct verifier_state *state,
1641 struct reg_state *dst_reg) 1641 const struct reg_state *dst_reg)
1642{ 1642{
1643 struct verifier_state *state = &env->cur_state;
1644 struct reg_state *regs = state->regs, *reg; 1643 struct reg_state *regs = state->regs, *reg;
1645 int i; 1644 int i;
1646 /* r2 = r3; 1645
1647 * r2 += 8 1646 /* LLVM can generate two kind of checks:
1648 * if (r2 > pkt_end) goto somewhere 1647 *
1649 * r2 == dst_reg, pkt_end == src_reg, 1648 * Type 1:
1650 * r2=pkt(id=n,off=8,r=0) 1649 *
1651 * r3=pkt(id=n,off=0,r=0) 1650 * r2 = r3;
1652 * find register r3 and mark its range as r3=pkt(id=n,off=0,r=8) 1651 * r2 += 8;
1653 * so that range of bytes [r3, r3 + 8) is safe to access 1652 * if (r2 > pkt_end) goto <handle exception>
1653 * <access okay>
1654 *
1655 * Where:
1656 * r2 == dst_reg, pkt_end == src_reg
1657 * r2=pkt(id=n,off=8,r=0)
1658 * r3=pkt(id=n,off=0,r=0)
1659 *
1660 * Type 2:
1661 *
1662 * r2 = r3;
1663 * r2 += 8;
1664 * if (pkt_end >= r2) goto <access okay>
1665 * <handle exception>
1666 *
1667 * Where:
1668 * pkt_end == dst_reg, r2 == src_reg
1669 * r2=pkt(id=n,off=8,r=0)
1670 * r3=pkt(id=n,off=0,r=0)
1671 *
1672 * Find register r3 and mark its range as r3=pkt(id=n,off=0,r=8)
1673 * so that range of bytes [r3, r3 + 8) is safe to access.
1654 */ 1674 */
1675
1655 for (i = 0; i < MAX_BPF_REG; i++) 1676 for (i = 0; i < MAX_BPF_REG; i++)
1656 if (regs[i].type == PTR_TO_PACKET && regs[i].id == dst_reg->id) 1677 if (regs[i].type == PTR_TO_PACKET && regs[i].id == dst_reg->id)
1657 regs[i].range = dst_reg->off; 1678 regs[i].range = dst_reg->off;
@@ -1668,8 +1689,8 @@ static void find_good_pkt_pointers(struct verifier_env *env,
1668static int check_cond_jmp_op(struct verifier_env *env, 1689static int check_cond_jmp_op(struct verifier_env *env,
1669 struct bpf_insn *insn, int *insn_idx) 1690 struct bpf_insn *insn, int *insn_idx)
1670{ 1691{
1671 struct reg_state *regs = env->cur_state.regs, *dst_reg; 1692 struct verifier_state *other_branch, *this_branch = &env->cur_state;
1672 struct verifier_state *other_branch; 1693 struct reg_state *regs = this_branch->regs, *dst_reg;
1673 u8 opcode = BPF_OP(insn->code); 1694 u8 opcode = BPF_OP(insn->code);
1674 int err; 1695 int err;
1675 1696
@@ -1750,13 +1771,17 @@ static int check_cond_jmp_op(struct verifier_env *env,
1750 } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && 1771 } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT &&
1751 dst_reg->type == PTR_TO_PACKET && 1772 dst_reg->type == PTR_TO_PACKET &&
1752 regs[insn->src_reg].type == PTR_TO_PACKET_END) { 1773 regs[insn->src_reg].type == PTR_TO_PACKET_END) {
1753 find_good_pkt_pointers(env, dst_reg); 1774 find_good_pkt_pointers(this_branch, dst_reg);
1775 } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE &&
1776 dst_reg->type == PTR_TO_PACKET_END &&
1777 regs[insn->src_reg].type == PTR_TO_PACKET) {
1778 find_good_pkt_pointers(other_branch, &regs[insn->src_reg]);
1754 } else if (is_pointer_value(env, insn->dst_reg)) { 1779 } else if (is_pointer_value(env, insn->dst_reg)) {
1755 verbose("R%d pointer comparison prohibited\n", insn->dst_reg); 1780 verbose("R%d pointer comparison prohibited\n", insn->dst_reg);
1756 return -EACCES; 1781 return -EACCES;
1757 } 1782 }
1758 if (log_level) 1783 if (log_level)
1759 print_verifier_state(&env->cur_state); 1784 print_verifier_state(this_branch);
1760 return 0; 1785 return 0;
1761} 1786}
1762 1787