aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2016-06-15 21:25:38 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-16 02:37:54 -0400
commit19de99f70b87fcc3338da52a89c439b088cbff71 (patch)
tree43b5ff80043ee9ea62e09fe568502c9d68a188ee /kernel
parente582615ad33dbd39623084a02e95567b116e1eea (diff)
bpf: fix matching of data/data_end in verifier
The ctx structure passed into bpf programs is different depending on bpf program type. The verifier incorrectly marked ctx->data and ctx->data_end access based on ctx offset only. That caused loads in tracing programs int bpf_prog(struct pt_regs *ctx) { .. ctx->ax .. } to be incorrectly marked as PTR_TO_PACKET which later caused verifier to reject the program that was actually valid in tracing context. Fix this by doing program type specific matching of ctx offsets. Fixes: 969bf05eb3ce ("bpf: direct packet access") Reported-by: Sasha Goldshtein <goldshtn@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c41
-rw-r--r--kernel/trace/bpf_trace.c6
2 files changed, 11 insertions, 36 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 */
130enum 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
154struct reg_state { 129struct 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 */
697static int check_ctx_access(struct verifier_env *env, int off, int size, 672static 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, &reg_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) {
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 720b7bb01d43..e7af6cb9d5cf 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -349,7 +349,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func
349} 349}
350 350
351/* bpf+kprobe programs can access fields of 'struct pt_regs' */ 351/* bpf+kprobe programs can access fields of 'struct pt_regs' */
352static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type) 352static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
353 enum bpf_reg_type *reg_type)
353{ 354{
354 /* check bounds */ 355 /* check bounds */
355 if (off < 0 || off >= sizeof(struct pt_regs)) 356 if (off < 0 || off >= sizeof(struct pt_regs))
@@ -427,7 +428,8 @@ static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
427 } 428 }
428} 429}
429 430
430static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type) 431static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type,
432 enum bpf_reg_type *reg_type)
431{ 433{
432 if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE) 434 if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE)
433 return false; 435 return false;