diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a8d67d097b0d..f72f23b8fdab 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -653,6 +653,16 @@ static int check_map_access(struct verifier_env *env, u32 regno, int off, | |||
653 | 653 | ||
654 | #define MAX_PACKET_OFF 0xffff | 654 | #define MAX_PACKET_OFF 0xffff |
655 | 655 | ||
656 | static bool may_write_pkt_data(enum bpf_prog_type type) | ||
657 | { | ||
658 | switch (type) { | ||
659 | case BPF_PROG_TYPE_XDP: | ||
660 | return true; | ||
661 | default: | ||
662 | return false; | ||
663 | } | ||
664 | } | ||
665 | |||
656 | static int check_packet_access(struct verifier_env *env, u32 regno, int off, | 666 | static int check_packet_access(struct verifier_env *env, u32 regno, int off, |
657 | int size) | 667 | int size) |
658 | { | 668 | { |
@@ -806,10 +816,15 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off, | |||
806 | err = check_stack_read(state, off, size, value_regno); | 816 | err = check_stack_read(state, off, size, value_regno); |
807 | } | 817 | } |
808 | } else if (state->regs[regno].type == PTR_TO_PACKET) { | 818 | } else if (state->regs[regno].type == PTR_TO_PACKET) { |
809 | if (t == BPF_WRITE) { | 819 | if (t == BPF_WRITE && !may_write_pkt_data(env->prog->type)) { |
810 | verbose("cannot write into packet\n"); | 820 | verbose("cannot write into packet\n"); |
811 | return -EACCES; | 821 | return -EACCES; |
812 | } | 822 | } |
823 | if (t == BPF_WRITE && value_regno >= 0 && | ||
824 | is_pointer_value(env, value_regno)) { | ||
825 | verbose("R%d leaks addr into packet\n", value_regno); | ||
826 | return -EACCES; | ||
827 | } | ||
813 | err = check_packet_access(env, regno, off, size); | 828 | err = check_packet_access(env, regno, off, size); |
814 | if (!err && t == BPF_READ && value_regno >= 0) | 829 | if (!err && t == BPF_READ && value_regno >= 0) |
815 | mark_reg_unknown_value(state->regs, value_regno); | 830 | mark_reg_unknown_value(state->regs, value_regno); |