[PATCH bpf-next v2 3/3] bpf: Fix prog UAF in __bpf_trampoline_unlink_prog() on update failure
"Hui Zhu" <[email protected]> Wed, 5 Aug 2026 12:04:08 +0800
| Newsgroups | org.kernel.vger.linux-trace-kernel,org.kernel.vger.bpf,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <0e91fde8222bcfc0b318cfa2dcc3e06cc476c1a2.1785902527.git.zhuhui@kylinos.cn> |
From: Hui Zhu <[email protected]> If bpf_trampoline_update() fails in __bpf_trampoline_unlink_prog(), cur_image is unchanged and still has node->link->prog's call baked into it. All callers only WARN_ON_ONCE() the failure and then unconditionally free the prog -- a UAF. Fix: on failure, pin node->link->prog onto tr->cur_image via the pinned_prog mechanism, so it outlives the link. This covers both the multi (bpf_trampoline_multi_detach) and non-multi (bpf_tracing_link_release, bpf_shim_tramp_link_release) paths. Fixes: aef4dfa790b2 ("bpf: Add bpf_trampoline_multi_attach/detach functions") Signed-off-by: Hui Zhu <[email protected]> --- kernel/bpf/trampoline.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index 7fac27374ece..6071261fd66b 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -991,7 +991,25 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_node *node, return err; } bpf_trampoline_remove_prog(tr, node); - return bpf_trampoline_update(tr, true /* lock_direct_mutex */, ops, data); + err = bpf_trampoline_update(tr, true /* lock_direct_mutex */, ops, data); + /* + * If the update above failed, tr->cur_image is unchanged, i.e. ftrace + * (or the direct jump, for the standard ops) is still actually + * calling into an image with node->link->prog's call baked into its + * machine code, even though this unlink is being reported as failed. + * Every caller of this function only WARN_ON_ONCE()'s a failure here + * and then unconditionally frees the underlying bpf_prog, which + * would be a use-after-free the next time that image is executed. + * Pin an extra reference on the prog onto tr->cur_image so it + * outlives this link, mirroring the fix applied to + * bpf_trampoline_multi_attach()/bpf_trampoline_multi_detach(). + */ + if (err && tr->cur_image) { + WARN_ON_ONCE(tr->cur_image->pinned_prog); + bpf_prog_inc(node->link->prog); + tr->cur_image->pinned_prog = node->link->prog; + } + return err; } /* bpf_trampoline_unlink_prog() should never fail. */ -- 2.53.0