diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 55 |
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 | ||
1640 | static void find_good_pkt_pointers(struct verifier_env *env, | 1640 | static 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, | |||
1668 | static int check_cond_jmp_op(struct verifier_env *env, | 1689 | static 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, ®s[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 | ||