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
126126 * are set to NOT_INIT to indicate that they are no longer readable.
127127 */
128128
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−
154129 struct reg_state {
155130 enum bpf_reg_type type;
156131 union {
@@ -695,10 +670,10 @@ static int check_packet_access(struct verifier_env *env, u32 regno, int off, · 538 unmodified lines
695670
696671 /* check access to 'struct bpf_context' fields */
697672 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)
699674 {
700675 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)) {
702677 /* remember the offset of last byte accessed in ctx */
703678 if (env->prog->aux->max_ctx_offset < off + size)
704679 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
798773 mark_reg_unknown_value(state->regs, value_regno);
799774
800775 } else if (reg->type == PTR_TO_CTX) {
776+ enum bpf_reg_type reg_type = UNKNOWN_VALUE;
777+
801778 if (t == BPF_WRITE && value_regno >= 0 &&
802779 is_pointer_value(env, value_regno)) {
803780 verbose("R%d leaks addr into ctx\n", value_regno);
804781 return -EACCES;
805782 }
806− err = check_ctx_access(env, off, size, t);
783+ err = check_ctx_access(env, off, size, t, &reg_type);
807784 if (!err && t == BPF_READ && value_regno >= 0) {
808785 mark_reg_unknown_value(state->regs, value_regno);
809− if (off == offsetof(struct __sk_buff, data) &&
810− env->allow_ptr_leaks)
786+ if (env->allow_ptr_leaks)
811787 /* note that reg.[id|off|range] == 0 */
812− state->regs[value_regno].type = PTR_TO_PACKET;
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;
788+ state->regs[value_regno].type = reg_type;
816789 }
817790
818791 } 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
349349 }
350350
351351 /* bpf+kprobe programs can access fields of 'struct pt_regs' */
352−static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type)
352+static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
353+ enum bpf_reg_type *reg_type)
353354 {
354355 /* check bounds */
355356 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
427428 }
428429 }
429430
430−static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type)
431+static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type,
432+ enum bpf_reg_type *reg_type)
431433 {
432434 if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE)
433435 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