aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2016-09-21 06:43:58 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-21 19:50:02 -0400
commit13a27dfc669724564aafa2699976ee756029fed2 (patch)
tree716dc81499b54b9bad19483ddc9a39c09210bbc9
parent58e2af8b3a6b587e4ac8414343581da4349d3c0f (diff)
bpf: enable non-core use of the verfier
Advanced JIT compilers and translators may want to use eBPF verifier as a base for parsers or to perform custom checks and validations. Add ability for external users to invoke the verifier and provide callbacks to be invoked for every intruction checked. For now only add most basic callback for per-instruction pre-interpretation checks is added. More advanced users may also like to have per-instruction post callback and state comparison callback. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/bpf_verifier.h11
-rw-r--r--kernel/bpf/verifier.c68
2 files changed, 79 insertions, 0 deletions
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 9457a22fc6e0..c5cb661712c9 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -59,6 +59,12 @@ struct bpf_insn_aux_data {
59 59
60#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ 60#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
61 61
62struct bpf_verifier_env;
63struct bpf_ext_analyzer_ops {
64 int (*insn_hook)(struct bpf_verifier_env *env,
65 int insn_idx, int prev_insn_idx);
66};
67
62/* single container for all structs 68/* single container for all structs
63 * one verifier_env per bpf_check() call 69 * one verifier_env per bpf_check() call
64 */ 70 */
@@ -68,6 +74,8 @@ struct bpf_verifier_env {
68 int stack_size; /* number of states to be processed */ 74 int stack_size; /* number of states to be processed */
69 struct bpf_verifier_state cur_state; /* current verifier state */ 75 struct bpf_verifier_state cur_state; /* current verifier state */
70 struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ 76 struct bpf_verifier_state_list **explored_states; /* search pruning optimization */
77 const struct bpf_ext_analyzer_ops *analyzer_ops; /* external analyzer ops */
78 void *analyzer_priv; /* pointer to external analyzer's private data */
71 struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */ 79 struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
72 u32 used_map_cnt; /* number of used maps */ 80 u32 used_map_cnt; /* number of used maps */
73 u32 id_gen; /* used to generate unique reg IDs */ 81 u32 id_gen; /* used to generate unique reg IDs */
@@ -76,4 +84,7 @@ struct bpf_verifier_env {
76 struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ 84 struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
77}; 85};
78 86
87int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
88 void *priv);
89
79#endif /* _LINUX_BPF_VERIFIER_H */ 90#endif /* _LINUX_BPF_VERIFIER_H */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index dca2b9b1d02e..ee86a77dc40b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -632,6 +632,10 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
632static int check_ctx_access(struct bpf_verifier_env *env, int off, int size, 632static int check_ctx_access(struct bpf_verifier_env *env, int off, int size,
633 enum bpf_access_type t, enum bpf_reg_type *reg_type) 633 enum bpf_access_type t, enum bpf_reg_type *reg_type)
634{ 634{
635 /* for analyzer ctx accesses are already validated and converted */
636 if (env->analyzer_ops)
637 return 0;
638
635 if (env->prog->aux->ops->is_valid_access && 639 if (env->prog->aux->ops->is_valid_access &&
636 env->prog->aux->ops->is_valid_access(off, size, t, reg_type)) { 640 env->prog->aux->ops->is_valid_access(off, size, t, reg_type)) {
637 /* remember the offset of last byte accessed in ctx */ 641 /* remember the offset of last byte accessed in ctx */
@@ -2225,6 +2229,15 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
2225 return 0; 2229 return 0;
2226} 2230}
2227 2231
2232static int ext_analyzer_insn_hook(struct bpf_verifier_env *env,
2233 int insn_idx, int prev_insn_idx)
2234{
2235 if (!env->analyzer_ops || !env->analyzer_ops->insn_hook)
2236 return 0;
2237
2238 return env->analyzer_ops->insn_hook(env, insn_idx, prev_insn_idx);
2239}
2240
2228static int do_check(struct bpf_verifier_env *env) 2241static int do_check(struct bpf_verifier_env *env)
2229{ 2242{
2230 struct bpf_verifier_state *state = &env->cur_state; 2243 struct bpf_verifier_state *state = &env->cur_state;
@@ -2283,6 +2296,10 @@ static int do_check(struct bpf_verifier_env *env)
2283 print_bpf_insn(insn); 2296 print_bpf_insn(insn);
2284 } 2297 }
2285 2298
2299 err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx);
2300 if (err)
2301 return err;
2302
2286 if (class == BPF_ALU || class == BPF_ALU64) { 2303 if (class == BPF_ALU || class == BPF_ALU64) {
2287 err = check_alu_op(env, insn); 2304 err = check_alu_op(env, insn);
2288 if (err) 2305 if (err)
@@ -2845,3 +2862,54 @@ err_free_env:
2845 kfree(env); 2862 kfree(env);
2846 return ret; 2863 return ret;
2847} 2864}
2865
2866int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
2867 void *priv)
2868{
2869 struct bpf_verifier_env *env;
2870 int ret;
2871
2872 env = kzalloc(sizeof(struct bpf_verifier_env), GFP_KERNEL);
2873 if (!env)
2874 return -ENOMEM;
2875
2876 env->insn_aux_data = vzalloc(sizeof(struct bpf_insn_aux_data) *
2877 prog->len);
2878 ret = -ENOMEM;
2879 if (!env->insn_aux_data)
2880 goto err_free_env;
2881 env->prog = prog;
2882 env->analyzer_ops = ops;
2883 env->analyzer_priv = priv;
2884
2885 /* grab the mutex to protect few globals used by verifier */
2886 mutex_lock(&bpf_verifier_lock);
2887
2888 log_level = 0;
2889
2890 env->explored_states = kcalloc(env->prog->len,
2891 sizeof(struct bpf_verifier_state_list *),
2892 GFP_KERNEL);
2893 ret = -ENOMEM;
2894 if (!env->explored_states)
2895 goto skip_full_check;
2896
2897 ret = check_cfg(env);
2898 if (ret < 0)
2899 goto skip_full_check;
2900
2901 env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
2902
2903 ret = do_check(env);
2904
2905skip_full_check:
2906 while (pop_stack(env, NULL) >= 0);
2907 free_states(env);
2908
2909 mutex_unlock(&bpf_verifier_lock);
2910 vfree(env->insn_aux_data);
2911err_free_env:
2912 kfree(env);
2913 return ret;
2914}
2915EXPORT_SYMBOL_GPL(bpf_analyzer);