Commit 1969db47 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by David S. Miller

bpf: fix verifier memory leaks

fix verifier memory leaks

Fixes: 638f5b90 ("bpf: reduce verifier memory consumption")
Signed-off-by: default avatarAlexei Starovoitov <ast@fb.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4bfbe53f
...@@ -341,10 +341,12 @@ static int realloc_verifier_state(struct bpf_verifier_state *state, int size, ...@@ -341,10 +341,12 @@ static int realloc_verifier_state(struct bpf_verifier_state *state, int size,
return 0; return 0;
} }
static void free_verifier_state(struct bpf_verifier_state *state) static void free_verifier_state(struct bpf_verifier_state *state,
bool free_self)
{ {
kfree(state->stack); kfree(state->stack);
kfree(state); if (free_self)
kfree(state);
} }
/* copy verifier state from src to dst growing dst stack space /* copy verifier state from src to dst growing dst stack space
...@@ -382,6 +384,7 @@ static int pop_stack(struct bpf_verifier_env *env, int *prev_insn_idx, ...@@ -382,6 +384,7 @@ static int pop_stack(struct bpf_verifier_env *env, int *prev_insn_idx,
if (prev_insn_idx) if (prev_insn_idx)
*prev_insn_idx = head->prev_insn_idx; *prev_insn_idx = head->prev_insn_idx;
elem = head->next; elem = head->next;
free_verifier_state(&head->st, false);
kfree(head); kfree(head);
env->head = elem; env->head = elem;
env->stack_size--; env->stack_size--;
...@@ -399,14 +402,14 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env, ...@@ -399,14 +402,14 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
if (!elem) if (!elem)
goto err; goto err;
err = copy_verifier_state(&elem->st, cur);
if (err)
return NULL;
elem->insn_idx = insn_idx; elem->insn_idx = insn_idx;
elem->prev_insn_idx = prev_insn_idx; elem->prev_insn_idx = prev_insn_idx;
elem->next = env->head; elem->next = env->head;
env->head = elem; env->head = elem;
env->stack_size++; env->stack_size++;
err = copy_verifier_state(&elem->st, cur);
if (err)
goto err;
if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) { if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) {
verbose(env, "BPF program is too complex\n"); verbose(env, "BPF program is too complex\n");
goto err; goto err;
...@@ -3641,7 +3644,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) ...@@ -3641,7 +3644,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
struct bpf_verifier_state_list *new_sl; struct bpf_verifier_state_list *new_sl;
struct bpf_verifier_state_list *sl; struct bpf_verifier_state_list *sl;
struct bpf_verifier_state *cur = env->cur_state; struct bpf_verifier_state *cur = env->cur_state;
int i; int i, err;
sl = env->explored_states[insn_idx]; sl = env->explored_states[insn_idx];
if (!sl) if (!sl)
...@@ -3679,7 +3682,12 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) ...@@ -3679,7 +3682,12 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
return -ENOMEM; return -ENOMEM;
/* add new state to the head of linked list */ /* add new state to the head of linked list */
copy_verifier_state(&new_sl->state, cur); err = copy_verifier_state(&new_sl->state, cur);
if (err) {
free_verifier_state(&new_sl->state, false);
kfree(new_sl);
return err;
}
new_sl->next = env->explored_states[insn_idx]; new_sl->next = env->explored_states[insn_idx];
env->explored_states[insn_idx] = new_sl; env->explored_states[insn_idx] = new_sl;
/* connect new state to parentage chain */ /* connect new state to parentage chain */
...@@ -4424,6 +4432,7 @@ static void free_states(struct bpf_verifier_env *env) ...@@ -4424,6 +4432,7 @@ static void free_states(struct bpf_verifier_env *env)
if (sl) if (sl)
while (sl != STATE_LIST_MARK) { while (sl != STATE_LIST_MARK) {
sln = sl->next; sln = sl->next;
free_verifier_state(&sl->state, false);
kfree(sl); kfree(sl);
sl = sln; sl = sln;
} }
...@@ -4494,7 +4503,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4494,7 +4503,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
ret = do_check(env); ret = do_check(env);
free_verifier_state(env->cur_state); free_verifier_state(env->cur_state, true);
env->cur_state = NULL; env->cur_state = NULL;
skip_full_check: skip_full_check:
...@@ -4601,7 +4610,7 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, ...@@ -4601,7 +4610,7 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
ret = do_check(env); ret = do_check(env);
free_verifier_state(env->cur_state); free_verifier_state(env->cur_state, true);
env->cur_state = NULL; env->cur_state = NULL;
skip_full_check: skip_full_check:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment