Skip to content

Commit 13a27df

Browse files
Jakub Kicinskidavem330
Jakub Kicinski
authored andcommitted
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 <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 58e2af8 commit 13a27df

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

Diff for: include/linux/bpf_verifier.h

+11
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ struct bpf_insn_aux_data {
5959

6060
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
6161

62+
struct bpf_verifier_env;
63+
struct bpf_ext_analyzer_ops {
64+
int (*insn_hook)(struct bpf_verifier_env *env,
65+
int insn_idx, int prev_insn_idx);
66+
};
67+
6268
/* single container for all structs
6369
* one verifier_env per bpf_check() call
6470
*/
@@ -68,6 +74,8 @@ struct bpf_verifier_env {
6874
int stack_size; /* number of states to be processed */
6975
struct bpf_verifier_state cur_state; /* current verifier state */
7076
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 */
7179
struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
7280
u32 used_map_cnt; /* number of used maps */
7381
u32 id_gen; /* used to generate unique reg IDs */
@@ -76,4 +84,7 @@ struct bpf_verifier_env {
7684
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
7785
};
7886

87+
int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
88+
void *priv);
89+
7990
#endif /* _LINUX_BPF_VERIFIER_H */

Diff for: kernel/bpf/verifier.c

+68
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,10 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
632632
static int check_ctx_access(struct bpf_verifier_env *env, int off, int size,
633633
enum bpf_access_type t, enum bpf_reg_type *reg_type)
634634
{
635+
/* for analyzer ctx accesses are already validated and converted */
636+
if (env->analyzer_ops)
637+
return 0;
638+
635639
if (env->prog->aux->ops->is_valid_access &&
636640
env->prog->aux->ops->is_valid_access(off, size, t, reg_type)) {
637641
/* 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)
22252229
return 0;
22262230
}
22272231

2232+
static 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+
22282241
static int do_check(struct bpf_verifier_env *env)
22292242
{
22302243
struct bpf_verifier_state *state = &env->cur_state;
@@ -2283,6 +2296,10 @@ static int do_check(struct bpf_verifier_env *env)
22832296
print_bpf_insn(insn);
22842297
}
22852298

2299+
err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx);
2300+
if (err)
2301+
return err;
2302+
22862303
if (class == BPF_ALU || class == BPF_ALU64) {
22872304
err = check_alu_op(env, insn);
22882305
if (err)
@@ -2845,3 +2862,54 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
28452862
kfree(env);
28462863
return ret;
28472864
}
2865+
2866+
int 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+
2905+
skip_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);
2911+
err_free_env:
2912+
kfree(env);
2913+
return ret;
2914+
}
2915+
EXPORT_SYMBOL_GPL(bpf_analyzer);

0 commit comments

Comments
 (0)