Skip to content

Commit b01a706

Browse files
captain5050gregkh
authored andcommitted
perf bpf-event: Fix use-after-free in synthesis
[ Upstream commit d7b67dd ] 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: 03edb70 ("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>
1 parent 4316776 commit b01a706

1 file changed

Lines changed: 27 additions & 12 deletions

File tree

tools/perf/util/bpf-event.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,15 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
301301

302302
info_node->info_linear = info_linear;
303303
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
304-
free(info_linear);
304+
/*
305+
* Insert failed, likely because of a duplicate event
306+
* made by the sideband thread. Ignore synthesizing the
307+
* metadata.
308+
*/
305309
free(info_node);
310+
goto out;
306311
}
312+
/* info_linear is now owned by info_node and shouldn't be freed below. */
307313
info_linear = NULL;
308314

309315
/*
@@ -459,18 +465,18 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
459465
return err;
460466
}
461467

462-
static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
468+
static int perf_env__add_bpf_info(struct perf_env *env, u32 id)
463469
{
464470
struct bpf_prog_info_linear *info_linear;
465471
struct bpf_prog_info_node *info_node;
466472
struct btf *btf = NULL;
467473
u64 arrays;
468474
u32 btf_id;
469-
int fd;
475+
int fd, err = 0;
470476

471477
fd = bpf_prog_get_fd_by_id(id);
472478
if (fd < 0)
473-
return;
479+
return -EINVAL;
474480

475481
arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
476482
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)
483489
info_linear = bpf_program__get_prog_info_linear(fd, arrays);
484490
if (IS_ERR_OR_NULL(info_linear)) {
485491
pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
492+
err = PTR_ERR(info_linear);
486493
goto out;
487494
}
488495

@@ -492,38 +499,46 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
492499
if (info_node) {
493500
info_node->info_linear = info_linear;
494501
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
502+
pr_debug("%s: duplicate add bpf info request for id %u\n",
503+
__func__, btf_id);
495504
free(info_linear);
496505
free(info_node);
506+
goto out;
497507
}
498-
} else
508+
} else {
499509
free(info_linear);
510+
err = -ENOMEM;
511+
goto out;
512+
}
500513

501514
if (btf_id == 0)
502515
goto out;
503516

504517
btf = btf__load_from_kernel_by_id(btf_id);
505-
if (libbpf_get_error(btf)) {
506-
pr_debug("%s: failed to get BTF of id %u, aborting\n",
507-
__func__, btf_id);
508-
goto out;
518+
if (!btf) {
519+
err = -errno;
520+
pr_debug("%s: failed to get BTF of id %u %d\n", __func__, btf_id, err);
521+
} else {
522+
perf_env__fetch_btf(env, btf_id, btf);
509523
}
510-
perf_env__fetch_btf(env, btf_id, btf);
511524

512525
out:
513526
btf__free(btf);
514527
close(fd);
528+
return err;
515529
}
516530

517531
static int bpf_event__sb_cb(union perf_event *event, void *data)
518532
{
519533
struct perf_env *env = data;
534+
int ret = 0;
520535

521536
if (event->header.type != PERF_RECORD_BPF_EVENT)
522537
return -1;
523538

524539
switch (event->bpf.type) {
525540
case PERF_BPF_EVENT_PROG_LOAD:
526-
perf_env__add_bpf_info(env, event->bpf.id);
541+
ret = perf_env__add_bpf_info(env, event->bpf.id);
527542

528543
case PERF_BPF_EVENT_PROG_UNLOAD:
529544
/*
@@ -537,7 +552,7 @@ static int bpf_event__sb_cb(union perf_event *event, void *data)
537552
break;
538553
}
539554

540-
return 0;
555+
return ret;
541556
}
542557

543558
int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env)

0 commit comments

Comments
 (0)