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.
Showing the changes to kernel (2 of 4 files). Show all
Unified · Split
| @@ -126,31 +126,6 @@ · 125 unmodified lines | ||
| 126 | 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 | 129 | struct reg_state { |
| 155 | 130 | enum bpf_reg_type type; |
| 156 | 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 | 671 | /* check access to 'struct bpf_context' fields */ |
| 697 | 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 | 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 | 677 | /* remember the offset of last byte accessed in ctx */ |
| 703 | 678 | if (env->prog->aux->max_ctx_offset < off + size) |
| 704 | 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 | 773 | mark_reg_unknown_value(state->regs, value_regno); |
| 799 | 774 | |
| 800 | 775 | } else if (reg->type == PTR_TO_CTX) { |
| 776 | + enum bpf_reg_type reg_type = UNKNOWN_VALUE; | |
| 777 | + | |
| 801 | 778 | if (t == BPF_WRITE && value_regno >= 0 && |
| 802 | 779 | is_pointer_value(env, value_regno)) { |
| 803 | 780 | verbose("R%d leaks addr into ctx\n", value_regno); |
| 804 | 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 | 784 | if (!err && t == BPF_READ && value_regno >= 0) { |
| 808 | 785 | 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) | |
| 811 | 787 | /* 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; | |
| 816 | 789 | } |
| 817 | 790 | |
| 818 | 791 | } else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) { |
| @@ -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 | 351 | /* 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) | |
| 353 | 354 | { |
| 354 | 355 | /* check bounds */ |
| 355 | 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 | |
| 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) | |
| 431 | 433 | { |
| 432 | 434 | if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE) |
| 433 | 435 | return false; |