Skip to content

Commit d1d10ce

Browse files
committed
Merge tag 'perf-tools-fixes-for-v6.17-2025-09-05' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools
Pull perf tools fixes from Namhyung Kim: "Fixes for use-after-free that resulted in segfaults after merging the bpf tree. Also a couple of build and test fixes" * tag 'perf-tools-fixes-for-v6.17-2025-09-05' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: perf symbol-elf: Add support for the block argument for libbfd perf test: Checking BPF metadata collection fails on version string perf tests: Fix "PE file support" test build perf bpf-utils: Harden get_bpf_prog_info_linear perf bpf-utils: Constify bpil_array_desc perf bpf-event: Fix use-after-free in synthesis
2 parents d3e4501 + ca81e74 commit d1d10ce

File tree

5 files changed

+76
-40
lines changed

5 files changed

+76
-40
lines changed

tools/perf/tests/pe-file-parsing.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static int run_dir(const char *d)
3737
size_t idx;
3838

3939
scnprintf(filename, PATH_MAX, "%s/pe-file.exe", d);
40-
ret = filename__read_build_id(filename, &bid);
40+
ret = filename__read_build_id(filename, &bid, /*block=*/true);
4141
TEST_ASSERT_VAL("Failed to read build_id",
4242
ret == sizeof(expect_build_id));
4343
TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id,
@@ -49,7 +49,7 @@ static int run_dir(const char *d)
4949
!strcmp(debuglink, expect_debuglink));
5050

5151
scnprintf(debugfile, PATH_MAX, "%s/%s", d, debuglink);
52-
ret = filename__read_build_id(debugfile, &bid);
52+
ret = filename__read_build_id(debugfile, &bid, /*block=*/true);
5353
TEST_ASSERT_VAL("Failed to read debug file build_id",
5454
ret == sizeof(expect_build_id));
5555
TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id,

tools/perf/tests/shell/test_bpf_metadata.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ test_bpf_metadata() {
6161
/perf_version/ {
6262
if (entry) print $NF;
6363
}
64-
' | egrep "$VERS" > /dev/null
64+
' | grep -qF "$VERS"
6565
then
6666
echo "Basic BPF metadata test [Failed invalid output]"
6767
err=1

tools/perf/util/bpf-event.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -657,9 +657,15 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
657657
info_node->info_linear = info_linear;
658658
info_node->metadata = NULL;
659659
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
660-
free(info_linear);
660+
/*
661+
* Insert failed, likely because of a duplicate event
662+
* made by the sideband thread. Ignore synthesizing the
663+
* metadata.
664+
*/
661665
free(info_node);
666+
goto out;
662667
}
668+
/* info_linear is now owned by info_node and shouldn't be freed below. */
663669
info_linear = NULL;
664670

665671
/*
@@ -827,18 +833,18 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
827833
return err;
828834
}
829835

830-
static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
836+
static int perf_env__add_bpf_info(struct perf_env *env, u32 id)
831837
{
832838
struct bpf_prog_info_node *info_node;
833839
struct perf_bpil *info_linear;
834840
struct btf *btf = NULL;
835841
u64 arrays;
836842
u32 btf_id;
837-
int fd;
843+
int fd, err = 0;
838844

839845
fd = bpf_prog_get_fd_by_id(id);
840846
if (fd < 0)
841-
return;
847+
return -EINVAL;
842848

843849
arrays = 1UL << PERF_BPIL_JITED_KSYMS;
844850
arrays |= 1UL << PERF_BPIL_JITED_FUNC_LENS;
@@ -852,6 +858,7 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
852858
info_linear = get_bpf_prog_info_linear(fd, arrays);
853859
if (IS_ERR_OR_NULL(info_linear)) {
854860
pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
861+
err = PTR_ERR(info_linear);
855862
goto out;
856863
}
857864

@@ -862,38 +869,46 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
862869
info_node->info_linear = info_linear;
863870
info_node->metadata = bpf_metadata_create(&info_linear->info);
864871
if (!perf_env__insert_bpf_prog_info(env, info_node)) {
872+
pr_debug("%s: duplicate add bpf info request for id %u\n",
873+
__func__, btf_id);
865874
free(info_linear);
866875
free(info_node);
876+
goto out;
867877
}
868-
} else
878+
} else {
869879
free(info_linear);
880+
err = -ENOMEM;
881+
goto out;
882+
}
870883

871884
if (btf_id == 0)
872885
goto out;
873886

874887
btf = btf__load_from_kernel_by_id(btf_id);
875-
if (libbpf_get_error(btf)) {
876-
pr_debug("%s: failed to get BTF of id %u, aborting\n",
877-
__func__, btf_id);
878-
goto out;
888+
if (!btf) {
889+
err = -errno;
890+
pr_debug("%s: failed to get BTF of id %u %d\n", __func__, btf_id, err);
891+
} else {
892+
perf_env__fetch_btf(env, btf_id, btf);
879893
}
880-
perf_env__fetch_btf(env, btf_id, btf);
881894

882895
out:
883896
btf__free(btf);
884897
close(fd);
898+
return err;
885899
}
886900

887901
static int bpf_event__sb_cb(union perf_event *event, void *data)
888902
{
889903
struct perf_env *env = data;
904+
int ret = 0;
890905

891906
if (event->header.type != PERF_RECORD_BPF_EVENT)
892907
return -1;
893908

894909
switch (event->bpf.type) {
895910
case PERF_BPF_EVENT_PROG_LOAD:
896-
perf_env__add_bpf_info(env, event->bpf.id);
911+
ret = perf_env__add_bpf_info(env, event->bpf.id);
897912

898913
case PERF_BPF_EVENT_PROG_UNLOAD:
899914
/*
@@ -907,7 +922,7 @@ static int bpf_event__sb_cb(union perf_event *event, void *data)
907922
break;
908923
}
909924

910-
return 0;
925+
return ret;
911926
}
912927

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

tools/perf/util/bpf-utils.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ struct bpil_array_desc {
2020
*/
2121
};
2222

23-
static struct bpil_array_desc bpil_array_desc[] = {
23+
static const struct bpil_array_desc bpil_array_desc[] = {
2424
[PERF_BPIL_JITED_INSNS] = {
2525
offsetof(struct bpf_prog_info, jited_prog_insns),
2626
offsetof(struct bpf_prog_info, jited_prog_len),
@@ -115,7 +115,7 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
115115
__u32 info_len = sizeof(info);
116116
__u32 data_len = 0;
117117
int i, err;
118-
void *ptr;
118+
__u8 *ptr;
119119

120120
if (arrays >> PERF_BPIL_LAST_ARRAY)
121121
return ERR_PTR(-EINVAL);
@@ -126,15 +126,15 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
126126
pr_debug("can't get prog info: %s", strerror(errno));
127127
return ERR_PTR(-EFAULT);
128128
}
129+
if (info.type >= __MAX_BPF_PROG_TYPE)
130+
pr_debug("%s:%d: unexpected program type %u\n", __func__, __LINE__, info.type);
129131

130132
/* step 2: calculate total size of all arrays */
131133
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
134+
const struct bpil_array_desc *desc = &bpil_array_desc[i];
132135
bool include_array = (arrays & (1UL << i)) > 0;
133-
struct bpil_array_desc *desc;
134136
__u32 count, size;
135137

136-
desc = bpil_array_desc + i;
137-
138138
/* kernel is too old to support this field */
139139
if (info_len < desc->array_offset + sizeof(__u32) ||
140140
info_len < desc->count_offset + sizeof(__u32) ||
@@ -163,19 +163,20 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
163163
ptr = info_linear->data;
164164

165165
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
166-
struct bpil_array_desc *desc;
166+
const struct bpil_array_desc *desc = &bpil_array_desc[i];
167167
__u32 count, size;
168168

169169
if ((arrays & (1UL << i)) == 0)
170170
continue;
171171

172-
desc = bpil_array_desc + i;
173172
count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
174173
size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
175174
bpf_prog_info_set_offset_u32(&info_linear->info,
176175
desc->count_offset, count);
177176
bpf_prog_info_set_offset_u32(&info_linear->info,
178177
desc->size_offset, size);
178+
assert(ptr >= info_linear->data);
179+
assert(ptr < &info_linear->data[data_len]);
179180
bpf_prog_info_set_offset_u64(&info_linear->info,
180181
desc->array_offset,
181182
ptr_to_u64(ptr));
@@ -189,27 +190,45 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
189190
free(info_linear);
190191
return ERR_PTR(-EFAULT);
191192
}
193+
if (info_linear->info.type >= __MAX_BPF_PROG_TYPE) {
194+
pr_debug("%s:%d: unexpected program type %u\n",
195+
__func__, __LINE__, info_linear->info.type);
196+
}
192197

193198
/* step 6: verify the data */
199+
ptr = info_linear->data;
194200
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
195-
struct bpil_array_desc *desc;
196-
__u32 v1, v2;
201+
const struct bpil_array_desc *desc = &bpil_array_desc[i];
202+
__u32 count1, count2, size1, size2;
203+
__u64 ptr2;
197204

198205
if ((arrays & (1UL << i)) == 0)
199206
continue;
200207

201-
desc = bpil_array_desc + i;
202-
v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
203-
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
208+
count1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
209+
count2 = bpf_prog_info_read_offset_u32(&info_linear->info,
204210
desc->count_offset);
205-
if (v1 != v2)
206-
pr_warning("%s: mismatch in element count\n", __func__);
211+
if (count1 != count2) {
212+
pr_warning("%s: mismatch in element count %u vs %u\n", __func__, count1, count2);
213+
free(info_linear);
214+
return ERR_PTR(-ERANGE);
215+
}
207216

208-
v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
209-
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
217+
size1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
218+
size2 = bpf_prog_info_read_offset_u32(&info_linear->info,
210219
desc->size_offset);
211-
if (v1 != v2)
212-
pr_warning("%s: mismatch in rec size\n", __func__);
220+
if (size1 != size2) {
221+
pr_warning("%s: mismatch in rec size %u vs %u\n", __func__, size1, size2);
222+
free(info_linear);
223+
return ERR_PTR(-ERANGE);
224+
}
225+
ptr2 = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset);
226+
if (ptr_to_u64(ptr) != ptr2) {
227+
pr_warning("%s: mismatch in array %p vs %llx\n", __func__, ptr, ptr2);
228+
free(info_linear);
229+
return ERR_PTR(-ERANGE);
230+
}
231+
ptr += roundup(count1 * size1, sizeof(__u64));
213232
}
214233

215234
/* step 7: update info_len and data_len */
@@ -224,13 +243,12 @@ void bpil_addr_to_offs(struct perf_bpil *info_linear)
224243
int i;
225244

226245
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
227-
struct bpil_array_desc *desc;
246+
const struct bpil_array_desc *desc = &bpil_array_desc[i];
228247
__u64 addr, offs;
229248

230249
if ((info_linear->arrays & (1UL << i)) == 0)
231250
continue;
232251

233-
desc = bpil_array_desc + i;
234252
addr = bpf_prog_info_read_offset_u64(&info_linear->info,
235253
desc->array_offset);
236254
offs = addr - ptr_to_u64(info_linear->data);
@@ -244,13 +262,12 @@ void bpil_offs_to_addr(struct perf_bpil *info_linear)
244262
int i;
245263

246264
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
247-
struct bpil_array_desc *desc;
265+
const struct bpil_array_desc *desc = &bpil_array_desc[i];
248266
__u64 addr, offs;
249267

250268
if ((info_linear->arrays & (1UL << i)) == 0)
251269
continue;
252270

253-
desc = bpil_array_desc + i;
254271
offs = bpf_prog_info_read_offset_u64(&info_linear->info,
255272
desc->array_offset);
256273
addr = offs + ptr_to_u64(info_linear->data);

tools/perf/util/symbol-elf.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -873,13 +873,17 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
873873

874874
#ifdef HAVE_LIBBFD_BUILDID_SUPPORT
875875

876-
static int read_build_id(const char *filename, struct build_id *bid)
876+
static int read_build_id(const char *filename, struct build_id *bid, bool block)
877877
{
878878
size_t size = sizeof(bid->data);
879-
int err = -1;
879+
int err = -1, fd;
880880
bfd *abfd;
881881

882-
abfd = bfd_openr(filename, NULL);
882+
fd = open(filename, block ? O_RDONLY : (O_RDONLY | O_NONBLOCK));
883+
if (fd < 0)
884+
return -1;
885+
886+
abfd = bfd_fdopenr(filename, /*target=*/NULL, fd);
883887
if (!abfd)
884888
return -1;
885889

0 commit comments

Comments
 (0)