mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 13:23:02 -04:00
Merge branch 'bpf-fix-warning-in-bpf_tracing_link_release'
Leon Hwang says: ==================== bpf: Fix WARNING in bpf_tracing_link_release The trampoline could be corrupted by the blindly 'tr->flags = BPF_TRAMP_F_TAIL_CALL_CTX' in verifier. 1. A fexit attached to a tail_call_reachable prog. 'tr->flags' became 'BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_TAIL_CALL_CTX'. And, the trampoline would poke the target prog's nop insn using jmp insn instead of call insn. 2. Another fexit loaded with the same tail_call_reachable prog target. 'tr->flags' became 'BPF_TRAMP_F_TAIL_CALL_CTX'. 3. Close the first fexit link. Due to no BPF_TRAMP_F_CALL_ORIG in 'tr->flags', the trampoline will fail to restore the prog's nop insn using call insn. [ 3.410719] WARNING: kernel/bpf/syscall.c:3551 at bpf_tracing_link_release+0x53/0x60, CPU#1: test_progs/98 ... [ 3.428793] bpf_link_free+0x58/0x130 [ 3.429293] bpf_link_release+0x23/0x30 Fix the warning by updating 'tr->flags' with '|=' and lock. Changes: v1 -> v2: * Update the patch #1 message with 'tr->flags' change. (per Jiri) * Drop the 'link' and the last 'if' in patch #2. (per Jiri) * v1: https://lore.kernel.org/bpf/20260721133036.49265-1-leon.hwang@linux.dev/ ==================== Link: https://patch.msgid.link/20260722151909.69142-1-leon.hwang@linux.dev Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
@@ -1523,6 +1523,7 @@ int bpf_trampoline_multi_attach(struct bpf_prog *prog, u32 *ids,
|
||||
struct bpf_tracing_multi_link *link);
|
||||
int bpf_trampoline_multi_detach(struct bpf_prog *prog,
|
||||
struct bpf_tracing_multi_link *link);
|
||||
void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags);
|
||||
|
||||
/*
|
||||
* When the architecture supports STATIC_CALL replace the bpf_dispatcher_fn
|
||||
@@ -1646,6 +1647,7 @@ static inline int bpf_trampoline_multi_detach(struct bpf_prog *prog,
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
static inline void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags) {}
|
||||
#endif
|
||||
|
||||
struct bpf_func_info_aux {
|
||||
|
||||
@@ -670,6 +670,13 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, int size)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags)
|
||||
{
|
||||
trampoline_lock(tr);
|
||||
tr->flags |= flags;
|
||||
trampoline_unlock(tr);
|
||||
}
|
||||
|
||||
static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex,
|
||||
const struct bpf_trampoline_ops *ops, void *data)
|
||||
{
|
||||
|
||||
@@ -19523,7 +19523,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tgt_prog && tgt_prog->aux->tail_call_reachable)
|
||||
tr->flags = BPF_TRAMP_F_TAIL_CALL_CTX;
|
||||
bpf_trampoline_set_flags(tr, BPF_TRAMP_F_TAIL_CALL_CTX);
|
||||
|
||||
prog->aux->dst_trampoline = tr;
|
||||
return 0;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "tailcall_cgrp_storage.skel.h"
|
||||
#include "tailcall_sleepable.skel.h"
|
||||
#include "tailcall_callback.skel.h"
|
||||
#include "tailcall_bpf2bpf2.skel.h"
|
||||
#include "tailcall_bpf2bpf_fexit.skel.h"
|
||||
|
||||
/* test_tailcall_1 checks basic functionality by patching multiple locations
|
||||
* in a single program for a single tail call slot with nop->jmp, jmp->nop
|
||||
@@ -1907,6 +1909,50 @@ static void test_tailcall_callback(void)
|
||||
RUN_TESTS(tailcall_callback);
|
||||
}
|
||||
|
||||
static void test_tailcall_bpf2bpf_fexit_links(void)
|
||||
{
|
||||
struct tailcall_bpf2bpf_fexit *skel1 = NULL, *skel2 = NULL;
|
||||
struct tailcall_bpf2bpf2 *skel_tc;
|
||||
int err, prog_fd;
|
||||
|
||||
skel_tc = tailcall_bpf2bpf2__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel_tc, "tailcall_bpf2bpf2__open_and_load"))
|
||||
return;
|
||||
|
||||
skel1 = tailcall_bpf2bpf_fexit__open();
|
||||
if (!ASSERT_OK_PTR(skel1, "tailcall_bpf2bpf_fexit__open"))
|
||||
goto out;
|
||||
|
||||
prog_fd = bpf_program__fd(skel_tc->progs.classifier_0);
|
||||
err = bpf_program__set_attach_target(skel1->progs.fexit, prog_fd, "subprog_tail");
|
||||
if (!ASSERT_OK(err, "bpf_program__set_attach_target"))
|
||||
goto out;
|
||||
|
||||
err = tailcall_bpf2bpf_fexit__load(skel1);
|
||||
if (!ASSERT_OK(err, "tailcall_bpf2bpf_fexit__load"))
|
||||
goto out;
|
||||
|
||||
skel1->links.fexit = bpf_program__attach_trace(skel1->progs.fexit);
|
||||
if (!ASSERT_OK_PTR(skel1->links.fexit, "bpf_program__attach_trace"))
|
||||
goto out;
|
||||
|
||||
skel2 = tailcall_bpf2bpf_fexit__open();
|
||||
if (!ASSERT_OK_PTR(skel2, "tailcall_bpf2bpf_fexit__open"))
|
||||
goto out;
|
||||
|
||||
err = bpf_program__set_attach_target(skel2->progs.fexit, prog_fd, "subprog_tail");
|
||||
if (!ASSERT_OK(err, "bpf_program__set_attach_target"))
|
||||
goto out;
|
||||
|
||||
err = tailcall_bpf2bpf_fexit__load(skel2);
|
||||
ASSERT_OK(err, "tailcall_bpf2bpf_fexit__load");
|
||||
|
||||
out:
|
||||
tailcall_bpf2bpf_fexit__destroy(skel1);
|
||||
tailcall_bpf2bpf_fexit__destroy(skel2);
|
||||
tailcall_bpf2bpf2__destroy(skel_tc);
|
||||
}
|
||||
|
||||
void test_tailcalls(void)
|
||||
{
|
||||
if (test__start_subtest("tailcall_1"))
|
||||
@@ -1974,4 +2020,6 @@ void test_tailcalls(void)
|
||||
if (test__start_subtest("tailcall_cgrp_storage_no_storage_bridge"))
|
||||
test_tailcall_cgrp_storage_no_storage_bridge();
|
||||
test_tailcall_callback();
|
||||
if (test__start_subtest("tailcall_bpf2bpf_fexit_links"))
|
||||
test_tailcall_bpf2bpf_fexit_links();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user