diff options
| author | Alex Gartrell <agartrell@fb.com> | 2015-07-23 17:24:40 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-07-27 03:54:10 -0400 |
| commit | 24b4d2abd0bd628f396dada3e915d395cbf459eb (patch) | |
| tree | ff4993b4c6f7c86b2f325d93d5c944446e5d5c61 | |
| parent | 6ecfdd28c8a6504349ca8501316b1ed3f639ce44 (diff) | |
ebpf: Allow dereferences of PTR_TO_STACK registers
mov %rsp, %r1 ; r1 = rsp
add $-8, %r1 ; r1 = rsp - 8
store_q $123, -8(%rsp) ; *(u64*)r1 = 123 <- valid
store_q $123, (%r1) ; *(u64*)r1 = 123 <- previously invalid
mov $0, %r0
exit ; Always need to exit
And we'd get the following error:
0: (bf) r1 = r10
1: (07) r1 += -8
2: (7a) *(u64 *)(r10 -8) = 999
3: (7a) *(u64 *)(r1 +0) = 999
R1 invalid mem access 'fp'
Unable to load program
We already know that a register is a stack address and the appropriate
offset, so we should be able to validate those references as well.
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | kernel/bpf/verifier.c | 6 | ||||
| -rw-r--r-- | samples/bpf/test_verifier.c | 59 |
2 files changed, 64 insertions, 1 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 039d866fd36a..cd307df98cb3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -648,6 +648,9 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off, | |||
| 648 | struct verifier_state *state = &env->cur_state; | 648 | struct verifier_state *state = &env->cur_state; |
| 649 | int size, err = 0; | 649 | int size, err = 0; |
| 650 | 650 | ||
| 651 | if (state->regs[regno].type == PTR_TO_STACK) | ||
| 652 | off += state->regs[regno].imm; | ||
| 653 | |||
| 651 | size = bpf_size_to_bytes(bpf_size); | 654 | size = bpf_size_to_bytes(bpf_size); |
| 652 | if (size < 0) | 655 | if (size < 0) |
| 653 | return size; | 656 | return size; |
| @@ -667,7 +670,8 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off, | |||
| 667 | if (!err && t == BPF_READ && value_regno >= 0) | 670 | if (!err && t == BPF_READ && value_regno >= 0) |
| 668 | mark_reg_unknown_value(state->regs, value_regno); | 671 | mark_reg_unknown_value(state->regs, value_regno); |
| 669 | 672 | ||
| 670 | } else if (state->regs[regno].type == FRAME_PTR) { | 673 | } else if (state->regs[regno].type == FRAME_PTR || |
| 674 | state->regs[regno].type == PTR_TO_STACK) { | ||
| 671 | if (off >= 0 || off < -MAX_BPF_STACK) { | 675 | if (off >= 0 || off < -MAX_BPF_STACK) { |
| 672 | verbose("invalid stack off=%d size=%d\n", off, size); | 676 | verbose("invalid stack off=%d size=%d\n", off, size); |
| 673 | return -EACCES; | 677 | return -EACCES; |
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 693605997abc..ee0f110c9c54 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c | |||
| @@ -822,6 +822,65 @@ static struct bpf_test tests[] = { | |||
| 822 | .result = ACCEPT, | 822 | .result = ACCEPT, |
| 823 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 823 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| 824 | }, | 824 | }, |
| 825 | { | ||
| 826 | "PTR_TO_STACK store/load", | ||
| 827 | .insns = { | ||
| 828 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
| 829 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10), | ||
| 830 | BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c), | ||
| 831 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2), | ||
| 832 | BPF_EXIT_INSN(), | ||
| 833 | }, | ||
| 834 | .result = ACCEPT, | ||
| 835 | }, | ||
| 836 | { | ||
| 837 | "PTR_TO_STACK store/load - bad alignment on off", | ||
| 838 | .insns = { | ||
| 839 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
| 840 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), | ||
| 841 | BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c), | ||
| 842 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2), | ||
| 843 | BPF_EXIT_INSN(), | ||
| 844 | }, | ||
| 845 | .result = REJECT, | ||
| 846 | .errstr = "misaligned access off -6 size 8", | ||
| 847 | }, | ||
| 848 | { | ||
| 849 | "PTR_TO_STACK store/load - bad alignment on reg", | ||
| 850 | .insns = { | ||
| 851 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
| 852 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10), | ||
| 853 | BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), | ||
| 854 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), | ||
| 855 | BPF_EXIT_INSN(), | ||
| 856 | }, | ||
| 857 | .result = REJECT, | ||
| 858 | .errstr = "misaligned access off -2 size 8", | ||
| 859 | }, | ||
| 860 | { | ||
| 861 | "PTR_TO_STACK store/load - out of bounds low", | ||
| 862 | .insns = { | ||
| 863 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
| 864 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -80000), | ||
| 865 | BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), | ||
| 866 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), | ||
| 867 | BPF_EXIT_INSN(), | ||
| 868 | }, | ||
| 869 | .result = REJECT, | ||
| 870 | .errstr = "invalid stack off=-79992 size=8", | ||
| 871 | }, | ||
| 872 | { | ||
| 873 | "PTR_TO_STACK store/load - out of bounds high", | ||
| 874 | .insns = { | ||
| 875 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
| 876 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), | ||
| 877 | BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), | ||
| 878 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), | ||
| 879 | BPF_EXIT_INSN(), | ||
| 880 | }, | ||
| 881 | .result = REJECT, | ||
| 882 | .errstr = "invalid stack off=0 size=8", | ||
| 883 | }, | ||
| 825 | }; | 884 | }; |
| 826 | 885 | ||
| 827 | static int probe_filter_length(struct bpf_insn *fp) | 886 | static int probe_filter_length(struct bpf_insn *fp) |
