diff options
| author | Ingo Molnar <mingo@kernel.org> | 2016-07-07 02:58:23 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2016-07-07 02:58:23 -0400 |
| commit | 3ebe3bd8fbd51b5e04e93c7f3fb90bd096a86344 (patch) | |
| tree | 41b67e7a92f1935b1d5acdc714de1b13f657b7af /kernel/bpf | |
| parent | c50f62454f4b489422333cb2e31401d87456bfa1 (diff) | |
| parent | 2c81a6477081966fe80b8c6daa68459bca896774 (diff) | |
Merge branch 'perf/urgent' into perf/core, to pick up fixes before merging new changes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/verifier.c | 41 |
1 files changed, 7 insertions, 34 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 668e07903c8f..eec9f90ba030 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -126,31 +126,6 @@ | |||
| 126 | * are set to NOT_INIT to indicate that they are no longer readable. | 126 | * are set to NOT_INIT to indicate that they are no longer readable. |
| 127 | */ | 127 | */ |
| 128 | 128 | ||
| 129 | /* types of values stored in eBPF registers */ | ||
| 130 | enum bpf_reg_type { | ||
| 131 | NOT_INIT = 0, /* nothing was written into register */ | ||
| 132 | UNKNOWN_VALUE, /* reg doesn't contain a valid pointer */ | ||
| 133 | PTR_TO_CTX, /* reg points to bpf_context */ | ||
| 134 | CONST_PTR_TO_MAP, /* reg points to struct bpf_map */ | ||
| 135 | PTR_TO_MAP_VALUE, /* reg points to map element value */ | ||
| 136 | PTR_TO_MAP_VALUE_OR_NULL,/* points to map elem value or NULL */ | ||
| 137 | FRAME_PTR, /* reg == frame_pointer */ | ||
| 138 | PTR_TO_STACK, /* reg == frame_pointer + imm */ | ||
| 139 | CONST_IMM, /* constant integer value */ | ||
| 140 | |||
| 141 | /* PTR_TO_PACKET represents: | ||
| 142 | * skb->data | ||
| 143 | * skb->data + imm | ||
| 144 | * skb->data + (u16) var | ||
| 145 | * skb->data + (u16) var + imm | ||
| 146 | * if (range > 0) then [ptr, ptr + range - off) is safe to access | ||
| 147 | * if (id > 0) means that some 'var' was added | ||
| 148 | * if (off > 0) menas that 'imm' was added | ||
| 149 | */ | ||
| 150 | PTR_TO_PACKET, | ||
| 151 | PTR_TO_PACKET_END, /* skb->data + headlen */ | ||
| 152 | }; | ||
| 153 | |||
| 154 | struct reg_state { | 129 | struct reg_state { |
| 155 | enum bpf_reg_type type; | 130 | enum bpf_reg_type type; |
| 156 | union { | 131 | union { |
| @@ -695,10 +670,10 @@ static int check_packet_access(struct verifier_env *env, u32 regno, int off, | |||
| 695 | 670 | ||
| 696 | /* check access to 'struct bpf_context' fields */ | 671 | /* check access to 'struct bpf_context' fields */ |
| 697 | static int check_ctx_access(struct verifier_env *env, int off, int size, | 672 | static int check_ctx_access(struct verifier_env *env, int off, int size, |
| 698 | enum bpf_access_type t) | 673 | enum bpf_access_type t, enum bpf_reg_type *reg_type) |
| 699 | { | 674 | { |
| 700 | if (env->prog->aux->ops->is_valid_access && | 675 | if (env->prog->aux->ops->is_valid_access && |
| 701 | env->prog->aux->ops->is_valid_access(off, size, t)) { | 676 | env->prog->aux->ops->is_valid_access(off, size, t, reg_type)) { |
| 702 | /* remember the offset of last byte accessed in ctx */ | 677 | /* remember the offset of last byte accessed in ctx */ |
| 703 | if (env->prog->aux->max_ctx_offset < off + size) | 678 | if (env->prog->aux->max_ctx_offset < off + size) |
| 704 | env->prog->aux->max_ctx_offset = off + size; | 679 | env->prog->aux->max_ctx_offset = off + size; |
| @@ -798,21 +773,19 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off, | |||
| 798 | mark_reg_unknown_value(state->regs, value_regno); | 773 | mark_reg_unknown_value(state->regs, value_regno); |
| 799 | 774 | ||
| 800 | } else if (reg->type == PTR_TO_CTX) { | 775 | } else if (reg->type == PTR_TO_CTX) { |
| 776 | enum bpf_reg_type reg_type = UNKNOWN_VALUE; | ||
| 777 | |||
| 801 | if (t == BPF_WRITE && value_regno >= 0 && | 778 | if (t == BPF_WRITE && value_regno >= 0 && |
| 802 | is_pointer_value(env, value_regno)) { | 779 | is_pointer_value(env, value_regno)) { |
| 803 | verbose("R%d leaks addr into ctx\n", value_regno); | 780 | verbose("R%d leaks addr into ctx\n", value_regno); |
| 804 | return -EACCES; | 781 | return -EACCES; |
| 805 | } | 782 | } |
| 806 | err = check_ctx_access(env, off, size, t); | 783 | err = check_ctx_access(env, off, size, t, ®_type); |
| 807 | if (!err && t == BPF_READ && value_regno >= 0) { | 784 | if (!err && t == BPF_READ && value_regno >= 0) { |
| 808 | mark_reg_unknown_value(state->regs, value_regno); | 785 | mark_reg_unknown_value(state->regs, value_regno); |
| 809 | if (off == offsetof(struct __sk_buff, data) && | 786 | if (env->allow_ptr_leaks) |
| 810 | env->allow_ptr_leaks) | ||
| 811 | /* note that reg.[id|off|range] == 0 */ | 787 | /* note that reg.[id|off|range] == 0 */ |
| 812 | state->regs[value_regno].type = PTR_TO_PACKET; | 788 | state->regs[value_regno].type = reg_type; |
| 813 | else if (off == offsetof(struct __sk_buff, data_end) && | ||
| 814 | env->allow_ptr_leaks) | ||
| 815 | state->regs[value_regno].type = PTR_TO_PACKET_END; | ||
| 816 | } | 789 | } |
| 817 | 790 | ||
| 818 | } else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) { | 791 | } else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) { |
