aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2016-09-21 06:43:56 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-21 19:50:02 -0400
commit3df126f35f88dc76eea33769f85a3c3bb8ce6c6b (patch)
tree72d11939e2d7219edb506fb783014f02f4130740
parenteadb41489fd2249e71fd14b36fb488ed7217ca4b (diff)
bpf: don't (ab)use instructions to store state
Storing state in reserved fields of instructions makes it impossible to run verifier on programs already marked as read-only. Allocate and use an array of per-instruction state instead. While touching the error path rename and move existing jump target. Suggested-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--kernel/bpf/verifier.c70
1 files changed, 40 insertions, 30 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3a75ee3bdcd1..a9542d89f293 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -181,6 +181,10 @@ struct verifier_stack_elem {
181 struct verifier_stack_elem *next; 181 struct verifier_stack_elem *next;
182}; 182};
183 183
184struct bpf_insn_aux_data {
185 enum bpf_reg_type ptr_type; /* pointer type for load/store insns */
186};
187
184#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ 188#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
185 189
186/* single container for all structs 190/* single container for all structs
@@ -197,6 +201,7 @@ struct verifier_env {
197 u32 id_gen; /* used to generate unique reg IDs */ 201 u32 id_gen; /* used to generate unique reg IDs */
198 bool allow_ptr_leaks; 202 bool allow_ptr_leaks;
199 bool seen_direct_write; 203 bool seen_direct_write;
204 struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
200}; 205};
201 206
202#define BPF_COMPLEXITY_LIMIT_INSNS 65536 207#define BPF_COMPLEXITY_LIMIT_INSNS 65536
@@ -2344,7 +2349,7 @@ static int do_check(struct verifier_env *env)
2344 return err; 2349 return err;
2345 2350
2346 } else if (class == BPF_LDX) { 2351 } else if (class == BPF_LDX) {
2347 enum bpf_reg_type src_reg_type; 2352 enum bpf_reg_type *prev_src_type, src_reg_type;
2348 2353
2349 /* check for reserved fields is already done */ 2354 /* check for reserved fields is already done */
2350 2355
@@ -2374,16 +2379,18 @@ static int do_check(struct verifier_env *env)
2374 continue; 2379 continue;
2375 } 2380 }
2376 2381
2377 if (insn->imm == 0) { 2382 prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
2383
2384 if (*prev_src_type == NOT_INIT) {
2378 /* saw a valid insn 2385 /* saw a valid insn
2379 * dst_reg = *(u32 *)(src_reg + off) 2386 * dst_reg = *(u32 *)(src_reg + off)
2380 * use reserved 'imm' field to mark this insn 2387 * save type to validate intersecting paths
2381 */ 2388 */
2382 insn->imm = src_reg_type; 2389 *prev_src_type = src_reg_type;
2383 2390
2384 } else if (src_reg_type != insn->imm && 2391 } else if (src_reg_type != *prev_src_type &&
2385 (src_reg_type == PTR_TO_CTX || 2392 (src_reg_type == PTR_TO_CTX ||
2386 insn->imm == PTR_TO_CTX)) { 2393 *prev_src_type == PTR_TO_CTX)) {
2387 /* ABuser program is trying to use the same insn 2394 /* ABuser program is trying to use the same insn
2388 * dst_reg = *(u32*) (src_reg + off) 2395 * dst_reg = *(u32*) (src_reg + off)
2389 * with different pointer types: 2396 * with different pointer types:
@@ -2396,7 +2403,7 @@ static int do_check(struct verifier_env *env)
2396 } 2403 }
2397 2404
2398 } else if (class == BPF_STX) { 2405 } else if (class == BPF_STX) {
2399 enum bpf_reg_type dst_reg_type; 2406 enum bpf_reg_type *prev_dst_type, dst_reg_type;
2400 2407
2401 if (BPF_MODE(insn->code) == BPF_XADD) { 2408 if (BPF_MODE(insn->code) == BPF_XADD) {
2402 err = check_xadd(env, insn); 2409 err = check_xadd(env, insn);
@@ -2424,11 +2431,13 @@ static int do_check(struct verifier_env *env)
2424 if (err) 2431 if (err)
2425 return err; 2432 return err;
2426 2433
2427 if (insn->imm == 0) { 2434 prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type;
2428 insn->imm = dst_reg_type; 2435
2429 } else if (dst_reg_type != insn->imm && 2436 if (*prev_dst_type == NOT_INIT) {
2437 *prev_dst_type = dst_reg_type;
2438 } else if (dst_reg_type != *prev_dst_type &&
2430 (dst_reg_type == PTR_TO_CTX || 2439 (dst_reg_type == PTR_TO_CTX ||
2431 insn->imm == PTR_TO_CTX)) { 2440 *prev_dst_type == PTR_TO_CTX)) {
2432 verbose("same insn cannot be used with different pointers\n"); 2441 verbose("same insn cannot be used with different pointers\n");
2433 return -EINVAL; 2442 return -EINVAL;
2434 } 2443 }
@@ -2686,10 +2695,11 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env)
2686static int convert_ctx_accesses(struct verifier_env *env) 2695static int convert_ctx_accesses(struct verifier_env *env)
2687{ 2696{
2688 const struct bpf_verifier_ops *ops = env->prog->aux->ops; 2697 const struct bpf_verifier_ops *ops = env->prog->aux->ops;
2698 const int insn_cnt = env->prog->len;
2689 struct bpf_insn insn_buf[16], *insn; 2699 struct bpf_insn insn_buf[16], *insn;
2690 struct bpf_prog *new_prog; 2700 struct bpf_prog *new_prog;
2691 enum bpf_access_type type; 2701 enum bpf_access_type type;
2692 int i, insn_cnt, cnt; 2702 int i, cnt, delta = 0;
2693 2703
2694 if (ops->gen_prologue) { 2704 if (ops->gen_prologue) {
2695 cnt = ops->gen_prologue(insn_buf, env->seen_direct_write, 2705 cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
@@ -2703,18 +2713,16 @@ static int convert_ctx_accesses(struct verifier_env *env)
2703 if (!new_prog) 2713 if (!new_prog)
2704 return -ENOMEM; 2714 return -ENOMEM;
2705 env->prog = new_prog; 2715 env->prog = new_prog;
2716 delta += cnt - 1;
2706 } 2717 }
2707 } 2718 }
2708 2719
2709 if (!ops->convert_ctx_access) 2720 if (!ops->convert_ctx_access)
2710 return 0; 2721 return 0;
2711 2722
2712 insn_cnt = env->prog->len; 2723 insn = env->prog->insnsi + delta;
2713 insn = env->prog->insnsi;
2714 2724
2715 for (i = 0; i < insn_cnt; i++, insn++) { 2725 for (i = 0; i < insn_cnt; i++, insn++) {
2716 u32 insn_delta;
2717
2718 if (insn->code == (BPF_LDX | BPF_MEM | BPF_W) || 2726 if (insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
2719 insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) 2727 insn->code == (BPF_LDX | BPF_MEM | BPF_DW))
2720 type = BPF_READ; 2728 type = BPF_READ;
@@ -2724,11 +2732,8 @@ static int convert_ctx_accesses(struct verifier_env *env)
2724 else 2732 else
2725 continue; 2733 continue;
2726 2734
2727 if (insn->imm != PTR_TO_CTX) { 2735 if (env->insn_aux_data[i].ptr_type != PTR_TO_CTX)
2728 /* clear internal mark */
2729 insn->imm = 0;
2730 continue; 2736 continue;
2731 }
2732 2737
2733 cnt = ops->convert_ctx_access(type, insn->dst_reg, insn->src_reg, 2738 cnt = ops->convert_ctx_access(type, insn->dst_reg, insn->src_reg,
2734 insn->off, insn_buf, env->prog); 2739 insn->off, insn_buf, env->prog);
@@ -2737,18 +2742,16 @@ static int convert_ctx_accesses(struct verifier_env *env)
2737 return -EINVAL; 2742 return -EINVAL;
2738 } 2743 }
2739 2744
2740 new_prog = bpf_patch_insn_single(env->prog, i, insn_buf, cnt); 2745 new_prog = bpf_patch_insn_single(env->prog, i + delta, insn_buf,
2746 cnt);
2741 if (!new_prog) 2747 if (!new_prog)
2742 return -ENOMEM; 2748 return -ENOMEM;
2743 2749
2744 insn_delta = cnt - 1; 2750 delta += cnt - 1;
2745 2751
2746 /* keep walking new program and skip insns we just inserted */ 2752 /* keep walking new program and skip insns we just inserted */
2747 env->prog = new_prog; 2753 env->prog = new_prog;
2748 insn = new_prog->insnsi + i + insn_delta; 2754 insn = new_prog->insnsi + i + delta;
2749
2750 insn_cnt += insn_delta;
2751 i += insn_delta;
2752 } 2755 }
2753 2756
2754 return 0; 2757 return 0;
@@ -2792,6 +2795,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
2792 if (!env) 2795 if (!env)
2793 return -ENOMEM; 2796 return -ENOMEM;
2794 2797
2798 env->insn_aux_data = vzalloc(sizeof(struct bpf_insn_aux_data) *
2799 (*prog)->len);
2800 ret = -ENOMEM;
2801 if (!env->insn_aux_data)
2802 goto err_free_env;
2795 env->prog = *prog; 2803 env->prog = *prog;
2796 2804
2797 /* grab the mutex to protect few globals used by verifier */ 2805 /* grab the mutex to protect few globals used by verifier */
@@ -2810,12 +2818,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
2810 /* log_* values have to be sane */ 2818 /* log_* values have to be sane */
2811 if (log_size < 128 || log_size > UINT_MAX >> 8 || 2819 if (log_size < 128 || log_size > UINT_MAX >> 8 ||
2812 log_level == 0 || log_ubuf == NULL) 2820 log_level == 0 || log_ubuf == NULL)
2813 goto free_env; 2821 goto err_unlock;
2814 2822
2815 ret = -ENOMEM; 2823 ret = -ENOMEM;
2816 log_buf = vmalloc(log_size); 2824 log_buf = vmalloc(log_size);
2817 if (!log_buf) 2825 if (!log_buf)
2818 goto free_env; 2826 goto err_unlock;
2819 } else { 2827 } else {
2820 log_level = 0; 2828 log_level = 0;
2821 } 2829 }
@@ -2884,14 +2892,16 @@ skip_full_check:
2884free_log_buf: 2892free_log_buf:
2885 if (log_level) 2893 if (log_level)
2886 vfree(log_buf); 2894 vfree(log_buf);
2887free_env:
2888 if (!env->prog->aux->used_maps) 2895 if (!env->prog->aux->used_maps)
2889 /* if we didn't copy map pointers into bpf_prog_info, release 2896 /* if we didn't copy map pointers into bpf_prog_info, release
2890 * them now. Otherwise free_bpf_prog_info() will release them. 2897 * them now. Otherwise free_bpf_prog_info() will release them.
2891 */ 2898 */
2892 release_maps(env); 2899 release_maps(env);
2893 *prog = env->prog; 2900 *prog = env->prog;
2894 kfree(env); 2901err_unlock:
2895 mutex_unlock(&bpf_verifier_lock); 2902 mutex_unlock(&bpf_verifier_lock);
2903 vfree(env->insn_aux_data);
2904err_free_env:
2905 kfree(env);
2896 return ret; 2906 return ret;
2897} 2907}