From: sashiko-bot@kernel.org
To: "Hui Zhu" <hui.zhu@linux.dev>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v2 1/3] bpf: Fix UAF in bpf_trampoline_multi_detach on update failure
Date: Wed, 05 Aug 2026 04:17:35 +0000 [thread overview]
Message-ID: <20260805041736.957931F000E9@smtp.kernel.org> (raw)
In-Reply-To: <0276810360a8c0e57aab95a292ff6453242b969c.1785902527.git.zhuhui@kylinos.cn>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Low] Multi-line comment opening `/*` is not on its own line.
Pre-existing issues:
- [High] Incomplete fix: Use-After-Free of `bpf_prog` when `__bpf_trampoline_unlink_prog()` fails.
- [High] Use-After-Free of trampoline image in `bpf_trampoline_multi_attach` error path.
--
--- Patch [1]: [PATCH bpf-next v2 1/3] bpf: Fix UAF in bpf_trampoline_multi_detach on update failure ---
commit 26ad7c4ab94aa890dec18cbc899359aabf65c015
Author: Hui Zhu <zhuhui@kylinos.cn>
bpf: Fix UAF in bpf_trampoline_multi_detach on update failure
The commit attempts to fix Use-After-Free issues in the error paths of
bpf_trampoline_multi_detach() by changing when old_image is freed and
introducing a rollback mechanism when ftrace updates fail. It pins the
bpf_prog onto the image to avoid freeing it while ftrace might still
direct calls to it.
> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index ed7999ad6c66c..c08d1a09e6381 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
[ ... ]
> @@ -1719,11 +1760,11 @@ int bpf_trampoline_multi_attach(struct bpf_prog *prog, u32 *ids,
> return err;
> }
>
> -int bpf_trampoline_multi_detach(struct bpf_prog *prog, struct bpf_tracing_multi_link *link)
> +void bpf_trampoline_multi_detach(struct bpf_prog *prog, struct bpf_tracing_multi_link *link)
> {
> struct bpf_tracing_multi_data *data = &link->data;
> struct bpf_tracing_multi_node *mnode;
> - int i, err;
> + int i, err, err_unreg = 0, err_mod = 0;
>
> trampoline_lock_all();
>
> @@ -1735,13 +1776,65 @@ int bpf_trampoline_multi_detach(struct bpf_prog *prog, struct bpf_tracing_multi_
> WARN_ONCE(err, "__bpf_trampoline_unlink_prog failed: %d\n", err);
> }
>
> - if (ftrace_hash_count(data->unreg))
> - WARN_ON_ONCE(update_ftrace_direct_del(&direct_ops, data->unreg));
> - if (ftrace_hash_count(data->modify))
> - WARN_ON_ONCE(update_ftrace_direct_mod(&direct_ops, data->modify, true));
> + if (ftrace_hash_count(data->unreg)) {
> + err_unreg = update_ftrace_direct_del(&direct_ops, data->unreg);
> + WARN_ON_ONCE(err_unreg);
> + }
> + if (ftrace_hash_count(data->modify)) {
> + err_mod = update_ftrace_direct_mod(&direct_ops, data->modify, true);
> + WARN_ON_ONCE(err_mod);
> + }
>
> - for_each_mnode(mnode, link)
> - bpf_trampoline_multi_attach_free(mnode->trampoline);
> + for_each_mnode(mnode, link) {
> + struct bpf_trampoline *tr = mnode->trampoline;
> +
> + /* If the batch ftrace update failed for this mnode's path,
> + * ftrace still points to old_image. Use rollback to restore
[Severity: Low]
Does this multi-line comment violate the BPF subsystem guidelines? The
opening /* of a multi-line comment must be on its own line.
> + * cur_image to old_image (putting the new cur_image if any)
> + * so the trampoline keeps the image ftrace is calling.
[ ... ]
> + * image if the trampoline is torn down first instead (see
> + * bpf_trampoline_put()).
> + */
> + if (tr->multi_attach.old_image &&
> + tr->multi_attach.old_image != tr->cur_image &&
> + ((err_unreg && !tr->cur_image) ||
> + (err_mod && tr->cur_image))) {
[Severity: High]
This is a pre-existing issue, but does this incomplete fix lead to a
Use-After-Free of the bpf_prog structure if __bpf_trampoline_unlink_prog()
fails?
When __bpf_trampoline_unlink_prog() fails, old_image equals cur_image,
so this condition evaluates to false, bypassing the logic to pin the
bpf_prog onto the retained image. This allows the caller to release its
reference to the bpf_prog and free it, even though the active ftrace
trampoline image still contains a direct machine-code call to the freed
prog.
A similar missing pinning logic exists in the non-multi caller of
__bpf_trampoline_unlink_prog() where it directly returns the failure of
bpf_trampoline_update() without pinning the prog:
kernel/bpf/trampoline.c:__bpf_trampoline_unlink_prog() {
...
bpf_trampoline_remove_prog(tr, node);
return bpf_trampoline_update(tr, true /* lock_direct_mutex */, ops, data);
}
> + WARN_ON_ONCE(tr->multi_attach.old_image->pinned_prog);
> + bpf_prog_inc(prog);
> + tr->multi_attach.old_image->pinned_prog = prog;
> + bpf_trampoline_multi_attach_rollback(tr);
> + } else {
> + bpf_trampoline_multi_attach_free(tr);
> + }
> + }
>
> trampoline_unlock_all();
[Severity: High]
This isn't a bug introduced by this patch, but does the error path in
bpf_trampoline_multi_attach() cause a Use-After-Free of the trampoline
image?
If update_ftrace_direct_del() fails during rollback:
kernel/bpf/trampoline.c:bpf_trampoline_multi_attach() {
...
if (ftrace_hash_count(data->modify)) {
err = update_ftrace_direct_mod(&direct_ops, data->modify, true);
if (err) {
if (ftrace_hash_count(data->reg))
WARN_ON_ONCE(update_ftrace_direct_del(&direct_ops, data->reg));
goto rollback_unlink;
}
}
...
}
It proceeds blindly to rollback_unlink, which calls
bpf_trampoline_multi_attach_rollback():
kernel/bpf/trampoline.c:bpf_trampoline_multi_attach_rollback() {
...
if (tr->cur_image)
bpf_tramp_image_put(tr->cur_image);
...
}
Does this unconditionally free the newly allocated trampoline images even
when update_ftrace_direct_del() fails, leading to a UAF since ftrace
is still actively pointing to them?
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1785902527.git.zhuhui@kylinos.cn?part=1
next prev parent reply other threads:[~2026-08-05 4:17 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 4:04 [PATCH bpf-next v2 0/3] bpf: Fix UAF in bpf_trampoline_multi_attach/detach on update failure Hui Zhu
2026-08-05 4:04 ` [PATCH bpf-next v2 1/3] bpf: Fix UAF in bpf_trampoline_multi_detach " Hui Zhu
2026-08-05 4:17 ` sashiko-bot [this message]
2026-08-05 4:04 ` [PATCH bpf-next v2 2/3] bpf: Fix prog UAF in bpf_trampoline_multi_attach() register-path rollback Hui Zhu
2026-08-05 4:17 ` sashiko-bot
2026-08-05 4:04 ` [PATCH bpf-next v2 3/3] bpf: Fix prog UAF in __bpf_trampoline_unlink_prog() on update failure Hui Zhu
2026-08-05 4:21 ` sashiko-bot
2026-08-06 8:25 ` [PATCH bpf-next v2 0/3] bpf: Fix UAF in bpf_trampoline_multi_attach/detach " Jiri Olsa
2026-08-07 2:00 ` Hui Zhu
2026-08-07 8:19 ` Jiri Olsa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260805041736.957931F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=hui.zhu@linux.dev \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.