mirror of
https://kernel.googlesource.com/pub/scm/linux/kernel/git/stable/linux-stable.git
synced 2025-09-13 11:07:46 +10:00
perf bpf-event: Fix use-after-free in synthesis
[ Upstream commitd7b67dd6f9
] Calls to perf_env__insert_bpf_prog_info may fail as a sideband thread may already have inserted the bpf_prog_info. Such failures may yield info_linear being freed which then causes use-after-free issues with the internal bpf_prog_info info struct. Make it so that perf_env__insert_bpf_prog_info trigger early non-error paths and fix the use-after-free in perf_event__synthesize_one_bpf_prog. Add proper return error handling to perf_env__add_bpf_info (that calls perf_env__insert_bpf_prog_info) and propagate the return value in its callers. Closes: https://lore.kernel.org/lkml/CAP-5=fWJQcmUOP7MuCA2ihKnDAHUCOBLkQFEkQES-1ZZTrgf8Q@mail.gmail.com/ Fixes:03edb7020b
("perf bpf: Fix two memory leakages when calling perf_env__insert_bpf_prog_info()") Reviewed-by: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Ian Rogers <irogers@google.com> Link: https://lore.kernel.org/r/20250902181713.309797-2-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
43167766ea
commit
b01a706f9e
@ -301,9 +301,15 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
|
||||
|
||||
info_node->info_linear = info_linear;
|
||||
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
|
||||
free(info_linear);
|
||||
/*
|
||||
* Insert failed, likely because of a duplicate event
|
||||
* made by the sideband thread. Ignore synthesizing the
|
||||
* metadata.
|
||||
*/
|
||||
free(info_node);
|
||||
goto out;
|
||||
}
|
||||
/* info_linear is now owned by info_node and shouldn't be freed below. */
|
||||
info_linear = NULL;
|
||||
|
||||
/*
|
||||
@ -459,18 +465,18 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
|
||||
return err;
|
||||
}
|
||||
|
||||
static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
|
||||
static int perf_env__add_bpf_info(struct perf_env *env, u32 id)
|
||||
{
|
||||
struct bpf_prog_info_linear *info_linear;
|
||||
struct bpf_prog_info_node *info_node;
|
||||
struct btf *btf = NULL;
|
||||
u64 arrays;
|
||||
u32 btf_id;
|
||||
int fd;
|
||||
int fd, err = 0;
|
||||
|
||||
fd = bpf_prog_get_fd_by_id(id);
|
||||
if (fd < 0)
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
|
||||
arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
|
||||
@ -483,6 +489,7 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
|
||||
info_linear = bpf_program__get_prog_info_linear(fd, arrays);
|
||||
if (IS_ERR_OR_NULL(info_linear)) {
|
||||
pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
|
||||
err = PTR_ERR(info_linear);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -492,38 +499,46 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
|
||||
if (info_node) {
|
||||
info_node->info_linear = info_linear;
|
||||
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
|
||||
pr_debug("%s: duplicate add bpf info request for id %u\n",
|
||||
__func__, btf_id);
|
||||
free(info_linear);
|
||||
free(info_node);
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
free(info_linear);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (btf_id == 0)
|
||||
goto out;
|
||||
|
||||
btf = btf__load_from_kernel_by_id(btf_id);
|
||||
if (libbpf_get_error(btf)) {
|
||||
pr_debug("%s: failed to get BTF of id %u, aborting\n",
|
||||
__func__, btf_id);
|
||||
goto out;
|
||||
if (!btf) {
|
||||
err = -errno;
|
||||
pr_debug("%s: failed to get BTF of id %u %d\n", __func__, btf_id, err);
|
||||
} else {
|
||||
perf_env__fetch_btf(env, btf_id, btf);
|
||||
}
|
||||
perf_env__fetch_btf(env, btf_id, btf);
|
||||
|
||||
out:
|
||||
btf__free(btf);
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bpf_event__sb_cb(union perf_event *event, void *data)
|
||||
{
|
||||
struct perf_env *env = data;
|
||||
int ret = 0;
|
||||
|
||||
if (event->header.type != PERF_RECORD_BPF_EVENT)
|
||||
return -1;
|
||||
|
||||
switch (event->bpf.type) {
|
||||
case PERF_BPF_EVENT_PROG_LOAD:
|
||||
perf_env__add_bpf_info(env, event->bpf.id);
|
||||
ret = perf_env__add_bpf_info(env, event->bpf.id);
|
||||
|
||||
case PERF_BPF_EVENT_PROG_UNLOAD:
|
||||
/*
|
||||
@ -537,7 +552,7 @@ static int bpf_event__sb_cb(union perf_event *event, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env)
|
||||
|
Loading…
Reference in New Issue
Block a user