History

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.

Alexei Starovoitov committed 10 years ago

Commit 19de99f1 parent e5826154 files · +52 −39Browse files

Showing the changes to kernel (2 of 4 files). Show all

Unified · Split

2 files
  1. kernel/bpf/verifier.c +7 −34
  2. kernel/trace/bpf_trace.c +4 −2
kernel/bpf/verifier.c+7−34
@@ -126,31 +126,6 @@ · 125 unmodified lines
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, · 538 unmodified lines
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, · 93 unmodified lines
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) {
kernel/trace/bpf_trace.c+4−2
@@ -349,7 +349,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func · 348 unmodified lines
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) · 71 unmodified lines
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;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t