Skip to content

Commit f3bf21d

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 9167bb6 commit f3bf21d

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

tools/perf/util/bpf-event.c

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

291291
info_node->info_linear = info_linear;
292292
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
293-
free(info_linear);
293+
/*
294+
* Insert failed, likely because of a duplicate event
295+
* made by the sideband thread. Ignore synthesizing the
296+
* metadata.
297+
*/
294298
free(info_node);
299+
goto out;
295300
}
301+
/* info_linear is now owned by info_node and shouldn't be freed below. */
296302
info_linear = NULL;
297303

298304
/*
@@ -451,18 +457,18 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
451457
return err;
452458
}
453459

454-
static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
460+
static int perf_env__add_bpf_info(struct perf_env *env, u32 id)
455461
{
456462
struct bpf_prog_info_node *info_node;
457463
struct perf_bpil *info_linear;
458464
struct btf *btf = NULL;
459465
u64 arrays;
460466
u32 btf_id;
461-
int fd;
467+
int fd, err = 0;
462468

463469
fd = bpf_prog_get_fd_by_id(id);
464470
if (fd < 0)
465-
return;
471+
return -EINVAL;
466472

467473
arrays = 1UL << PERF_BPIL_JITED_KSYMS;
468474
arrays |= 1UL << PERF_BPIL_JITED_FUNC_LENS;
@@ -475,6 +481,7 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
475481
info_linear = get_bpf_prog_info_linear(fd, arrays);
476482
if (IS_ERR_OR_NULL(info_linear)) {
477483
pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
484+
err = PTR_ERR(info_linear);
478485
goto out;
479486
}
480487

@@ -484,38 +491,46 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
484491
if (info_node) {
485492
info_node->info_linear = info_linear;
486493
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
494+
pr_debug("%s: duplicate add bpf info request for id %u\n",
495+
__func__, btf_id);
487496
free(info_linear);
488497
free(info_node);
498+
goto out;
489499
}
490-
} else
500+
} else {
491501
free(info_linear);
502+
err = -ENOMEM;
503+
goto out;
504+
}
492505

493506
if (btf_id == 0)
494507
goto out;
495508

496509
btf = btf__load_from_kernel_by_id(btf_id);
497-
if (libbpf_get_error(btf)) {
498-
pr_debug("%s: failed to get BTF of id %u, aborting\n",
499-
__func__, btf_id);
500-
goto out;
510+
if (!btf) {
511+
err = -errno;
512+
pr_debug("%s: failed to get BTF of id %u %d\n", __func__, btf_id, err);
513+
} else {
514+
perf_env__fetch_btf(env, btf_id, btf);
501515
}
502-
perf_env__fetch_btf(env, btf_id, btf);
503516

504517
out:
505518
btf__free(btf);
506519
close(fd);
520+
return err;
507521
}
508522

509523
static int bpf_event__sb_cb(union perf_event *event, void *data)
510524
{
511525
struct perf_env *env = data;
526+
int ret = 0;
512527

513528
if (event->header.type != PERF_RECORD_BPF_EVENT)
514529
return -1;
515530

516531
switch (event->bpf.type) {
517532
case PERF_BPF_EVENT_PROG_LOAD:
518-
perf_env__add_bpf_info(env, event->bpf.id);
533+
ret = perf_env__add_bpf_info(env, event->bpf.id);
519534

520535
case PERF_BPF_EVENT_PROG_UNLOAD:
521536
/*
@@ -529,7 +544,7 @@ static int bpf_event__sb_cb(union perf_event *event, void *data)
529544
break;
530545
}
531546

532-
return 0;
547+
return ret;
533548
}
534549

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

0 commit comments

Comments
 (0)