| From 05d57f1793fb250c85028c9952c3720010baa853 Mon Sep 17 00:00:00 2001 |
| From: Alexei Starovoitov <ast@kernel.org> |
| Date: Mon, 20 Jan 2020 19:22:31 -0800 |
| Subject: bpf: Fix trampoline usage in preempt |
| |
| From: Alexei Starovoitov <ast@kernel.org> |
| |
| commit 05d57f1793fb250c85028c9952c3720010baa853 upstream. |
| |
| Though the second half of trampoline page is unused a task could be |
| preempted in the middle of the first half of trampoline and two |
| updates to trampoline would change the code from underneath the |
| preempted task. Hence wait for tasks to voluntarily schedule or go |
| to userspace. Add similar wait before freeing the trampoline. |
| |
| Fixes: fec56f5890d9 ("bpf: Introduce BPF trampoline") |
| Reported-by: Jann Horn <jannh@google.com> |
| Signed-off-by: Alexei Starovoitov <ast@kernel.org> |
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> |
| Acked-by: Paul E. McKenney <paulmck@kernel.org> |
| Link: https://lore.kernel.org/bpf/20200121032231.3292185-1-ast@kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/bpf/trampoline.c | 10 ++++++++++ |
| 1 file changed, 10 insertions(+) |
| |
| --- a/kernel/bpf/trampoline.c |
| +++ b/kernel/bpf/trampoline.c |
| @@ -150,6 +150,14 @@ static int bpf_trampoline_update(struct |
| if (fexit_cnt) |
| flags = BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_SKIP_FRAME; |
| |
| + /* Though the second half of trampoline page is unused a task could be |
| + * preempted in the middle of the first half of trampoline and two |
| + * updates to trampoline would change the code from underneath the |
| + * preempted task. Hence wait for tasks to voluntarily schedule or go |
| + * to userspace. |
| + */ |
| + synchronize_rcu_tasks(); |
| + |
| err = arch_prepare_bpf_trampoline(new_image, &tr->func.model, flags, |
| fentry, fentry_cnt, |
| fexit, fexit_cnt, |
| @@ -240,6 +248,8 @@ void bpf_trampoline_put(struct bpf_tramp |
| goto out; |
| if (WARN_ON_ONCE(!hlist_empty(&tr->progs_hlist[BPF_TRAMP_FEXIT]))) |
| goto out; |
| + /* wait for tasks to get out of trampoline before freeing it */ |
| + synchronize_rcu_tasks(); |
| bpf_jit_free_exec(tr->image); |
| hlist_del(&tr->hlist); |
| kfree(tr); |