[PATCH 4.14 74/92] bpf: fix verifier memory leaks

From: Greg Kroah-Hartman
Date: Thu Apr 18 2019 - 14:22:36 EST


From: Alexei Starovoitov <ast@xxxxxx>

commit 1969db47f8d0e800397abd4ee4e8d27d2b578587 upstream.

fix verifier memory leaks

Fixes: 638f5b90d460 ("bpf: reduce verifier memory consumption")
Signed-off-by: Alexei Starovoitov <ast@xxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
Signed-off-by: Balbir Singh <sblbir@xxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
kernel/bpf/verifier.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)

--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -491,10 +491,12 @@ static int realloc_verifier_state(struct
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);
+ if (free_self)
+ kfree(state);
}

/* copy verifier state from src to dst growing dst stack space
@@ -532,6 +534,7 @@ static int pop_stack(struct bpf_verifier
if (prev_insn_idx)
*prev_insn_idx = head->prev_insn_idx;
elem = head->next;
+ free_verifier_state(&head->st, false);
kfree(head);
env->head = elem;
env->stack_size--;
@@ -549,14 +552,14 @@ static struct bpf_verifier_state *push_s
if (!elem)
goto err;

- err = copy_verifier_state(&elem->st, cur);
- if (err)
- return NULL;
elem->insn_idx = insn_idx;
elem->prev_insn_idx = prev_insn_idx;
elem->next = env->head;
env->head = elem;
env->stack_size++;
+ err = copy_verifier_state(&elem->st, cur);
+ if (err)
+ goto err;
if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) {
verbose("BPF program is too complex\n");
goto err;
@@ -3812,7 +3815,7 @@ static int is_state_visited(struct bpf_v
struct bpf_verifier_state_list *new_sl;
struct bpf_verifier_state_list *sl;
struct bpf_verifier_state *cur = env->cur_state;
- int i;
+ int i, err;

sl = env->explored_states[insn_idx];
if (!sl)
@@ -3850,7 +3853,12 @@ static int is_state_visited(struct bpf_v
return -ENOMEM;

/* 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];
env->explored_states[insn_idx] = new_sl;
/* connect new state to parentage chain */
@@ -4692,6 +4700,7 @@ static void free_states(struct bpf_verif
if (sl)
while (sl != STATE_LIST_MARK) {
sln = sl->next;
+ free_verifier_state(&sl->state, false);
kfree(sl);
sl = sln;
}
@@ -4768,7 +4777,7 @@ int bpf_check(struct bpf_prog **prog, un
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);

ret = do_check(env);
- free_verifier_state(env->cur_state);
+ free_verifier_state(env->cur_state, true);
env->cur_state = NULL;

skip_full_check:
@@ -4878,7 +4887,7 @@ int bpf_analyzer(struct bpf_prog *prog,
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);

ret = do_check(env);
- free_verifier_state(env->cur_state);
+ free_verifier_state(env->cur_state, true);
env->cur_state = NULL;

skip_full_check: