Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+76 -40
+2 -2
tools/perf/tests/pe-file-parsing.c
··· 37 37 size_t idx; 38 38 39 39 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); 41 41 TEST_ASSERT_VAL("Failed to read build_id", 42 42 ret == sizeof(expect_build_id)); 43 43 TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id, ··· 49 49 !strcmp(debuglink, expect_debuglink)); 50 50 51 51 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); 53 53 TEST_ASSERT_VAL("Failed to read debug file build_id", 54 54 ret == sizeof(expect_build_id)); 55 55 TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id,
+1 -1
tools/perf/tests/shell/test_bpf_metadata.sh
··· 61 61 /perf_version/ { 62 62 if (entry) print $NF; 63 63 } 64 - ' | egrep "$VERS" > /dev/null 64 + ' | grep -qF "$VERS" 65 65 then 66 66 echo "Basic BPF metadata test [Failed invalid output]" 67 67 err=1
+27 -12
tools/perf/util/bpf-event.c
··· 657 657 info_node->info_linear = info_linear; 658 658 info_node->metadata = NULL; 659 659 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 + */ 661 665 free(info_node); 666 + goto out; 662 667 } 668 + /* info_linear is now owned by info_node and shouldn't be freed below. */ 663 669 info_linear = NULL; 664 670 665 671 /* ··· 833 827 return err; 834 828 } 835 829 836 - static void perf_env__add_bpf_info(struct perf_env *env, u32 id) 830 + static int perf_env__add_bpf_info(struct perf_env *env, u32 id) 837 831 { 838 832 struct bpf_prog_info_node *info_node; 839 833 struct perf_bpil *info_linear; 840 834 struct btf *btf = NULL; 841 835 u64 arrays; 842 836 u32 btf_id; 843 - int fd; 837 + int fd, err = 0; 844 838 845 839 fd = bpf_prog_get_fd_by_id(id); 846 840 if (fd < 0) 847 - return; 841 + return -EINVAL; 848 842 849 843 arrays = 1UL << PERF_BPIL_JITED_KSYMS; 850 844 arrays |= 1UL << PERF_BPIL_JITED_FUNC_LENS; ··· 858 852 info_linear = get_bpf_prog_info_linear(fd, arrays); 859 853 if (IS_ERR_OR_NULL(info_linear)) { 860 854 pr_debug("%s: failed to get BPF program info. aborting\n", __func__); 855 + err = PTR_ERR(info_linear); 861 856 goto out; 862 857 } 863 858 ··· 869 862 info_node->info_linear = info_linear; 870 863 info_node->metadata = bpf_metadata_create(&info_linear->info); 871 864 if (!perf_env__insert_bpf_prog_info(env, info_node)) { 865 + pr_debug("%s: duplicate add bpf info request for id %u\n", 866 + __func__, btf_id); 872 867 free(info_linear); 873 868 free(info_node); 869 + goto out; 874 870 } 875 - } else 871 + } else { 876 872 free(info_linear); 873 + err = -ENOMEM; 874 + goto out; 875 + } 877 876 878 877 if (btf_id == 0) 879 878 goto out; 880 879 881 880 btf = btf__load_from_kernel_by_id(btf_id); 882 - if (libbpf_get_error(btf)) { 883 - pr_debug("%s: failed to get BTF of id %u, aborting\n", 884 - __func__, btf_id); 885 - goto out; 881 + if (!btf) { 882 + err = -errno; 883 + pr_debug("%s: failed to get BTF of id %u %d\n", __func__, btf_id, err); 884 + } else { 885 + perf_env__fetch_btf(env, btf_id, btf); 886 886 } 887 - perf_env__fetch_btf(env, btf_id, btf); 888 887 889 888 out: 890 889 btf__free(btf); 891 890 close(fd); 891 + return err; 892 892 } 893 893 894 894 static int bpf_event__sb_cb(union perf_event *event, void *data) 895 895 { 896 896 struct perf_env *env = data; 897 + int ret = 0; 897 898 898 899 if (event->header.type != PERF_RECORD_BPF_EVENT) 899 900 return -1; 900 901 901 902 switch (event->bpf.type) { 902 903 case PERF_BPF_EVENT_PROG_LOAD: 903 - perf_env__add_bpf_info(env, event->bpf.id); 904 + ret = perf_env__add_bpf_info(env, event->bpf.id); 904 905 905 906 case PERF_BPF_EVENT_PROG_UNLOAD: 906 907 /* ··· 922 907 break; 923 908 } 924 909 925 - return 0; 910 + return ret; 926 911 } 927 912 928 913 int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env)
+39 -22
tools/perf/util/bpf-utils.c
··· 20 20 */ 21 21 }; 22 22 23 - static struct bpil_array_desc bpil_array_desc[] = { 23 + static const struct bpil_array_desc bpil_array_desc[] = { 24 24 [PERF_BPIL_JITED_INSNS] = { 25 25 offsetof(struct bpf_prog_info, jited_prog_insns), 26 26 offsetof(struct bpf_prog_info, jited_prog_len), ··· 115 115 __u32 info_len = sizeof(info); 116 116 __u32 data_len = 0; 117 117 int i, err; 118 - void *ptr; 118 + __u8 *ptr; 119 119 120 120 if (arrays >> PERF_BPIL_LAST_ARRAY) 121 121 return ERR_PTR(-EINVAL); ··· 126 126 pr_debug("can't get prog info: %s", strerror(errno)); 127 127 return ERR_PTR(-EFAULT); 128 128 } 129 + if (info.type >= __MAX_BPF_PROG_TYPE) 130 + pr_debug("%s:%d: unexpected program type %u\n", __func__, __LINE__, info.type); 129 131 130 132 /* step 2: calculate total size of all arrays */ 131 133 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { 134 + const struct bpil_array_desc *desc = &bpil_array_desc[i]; 132 135 bool include_array = (arrays & (1UL << i)) > 0; 133 - struct bpil_array_desc *desc; 134 136 __u32 count, size; 135 - 136 - desc = bpil_array_desc + i; 137 137 138 138 /* kernel is too old to support this field */ 139 139 if (info_len < desc->array_offset + sizeof(__u32) || ··· 163 163 ptr = info_linear->data; 164 164 165 165 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]; 167 167 __u32 count, size; 168 168 169 169 if ((arrays & (1UL << i)) == 0) 170 170 continue; 171 171 172 - desc = bpil_array_desc + i; 173 172 count = bpf_prog_info_read_offset_u32(&info, desc->count_offset); 174 173 size = bpf_prog_info_read_offset_u32(&info, desc->size_offset); 175 174 bpf_prog_info_set_offset_u32(&info_linear->info, 176 175 desc->count_offset, count); 177 176 bpf_prog_info_set_offset_u32(&info_linear->info, 178 177 desc->size_offset, size); 178 + assert(ptr >= info_linear->data); 179 + assert(ptr < &info_linear->data[data_len]); 179 180 bpf_prog_info_set_offset_u64(&info_linear->info, 180 181 desc->array_offset, 181 182 ptr_to_u64(ptr)); ··· 190 189 free(info_linear); 191 190 return ERR_PTR(-EFAULT); 192 191 } 192 + if (info_linear->info.type >= __MAX_BPF_PROG_TYPE) { 193 + pr_debug("%s:%d: unexpected program type %u\n", 194 + __func__, __LINE__, info_linear->info.type); 195 + } 193 196 194 197 /* step 6: verify the data */ 198 + ptr = info_linear->data; 195 199 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { 196 - struct bpil_array_desc *desc; 197 - __u32 v1, v2; 200 + const struct bpil_array_desc *desc = &bpil_array_desc[i]; 201 + __u32 count1, count2, size1, size2; 202 + __u64 ptr2; 198 203 199 204 if ((arrays & (1UL << i)) == 0) 200 205 continue; 201 206 202 - desc = bpil_array_desc + i; 203 - v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset); 204 - v2 = bpf_prog_info_read_offset_u32(&info_linear->info, 207 + count1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset); 208 + count2 = bpf_prog_info_read_offset_u32(&info_linear->info, 205 209 desc->count_offset); 206 - if (v1 != v2) 207 - pr_warning("%s: mismatch in element count\n", __func__); 210 + if (count1 != count2) { 211 + pr_warning("%s: mismatch in element count %u vs %u\n", __func__, count1, count2); 212 + free(info_linear); 213 + return ERR_PTR(-ERANGE); 214 + } 208 215 209 - v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset); 210 - v2 = bpf_prog_info_read_offset_u32(&info_linear->info, 216 + size1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset); 217 + size2 = bpf_prog_info_read_offset_u32(&info_linear->info, 211 218 desc->size_offset); 212 - if (v1 != v2) 213 - pr_warning("%s: mismatch in rec size\n", __func__); 219 + if (size1 != size2) { 220 + pr_warning("%s: mismatch in rec size %u vs %u\n", __func__, size1, size2); 221 + free(info_linear); 222 + return ERR_PTR(-ERANGE); 223 + } 224 + ptr2 = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset); 225 + if (ptr_to_u64(ptr) != ptr2) { 226 + pr_warning("%s: mismatch in array %p vs %llx\n", __func__, ptr, ptr2); 227 + free(info_linear); 228 + return ERR_PTR(-ERANGE); 229 + } 230 + ptr += roundup(count1 * size1, sizeof(__u64)); 214 231 } 215 232 216 233 /* step 7: update info_len and data_len */ ··· 243 224 int i; 244 225 245 226 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { 246 - struct bpil_array_desc *desc; 227 + const struct bpil_array_desc *desc = &bpil_array_desc[i]; 247 228 __u64 addr, offs; 248 229 249 230 if ((info_linear->arrays & (1UL << i)) == 0) 250 231 continue; 251 232 252 - desc = bpil_array_desc + i; 253 233 addr = bpf_prog_info_read_offset_u64(&info_linear->info, 254 234 desc->array_offset); 255 235 offs = addr - ptr_to_u64(info_linear->data); ··· 262 244 int i; 263 245 264 246 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { 265 - struct bpil_array_desc *desc; 247 + const struct bpil_array_desc *desc = &bpil_array_desc[i]; 266 248 __u64 addr, offs; 267 249 268 250 if ((info_linear->arrays & (1UL << i)) == 0) 269 251 continue; 270 252 271 - desc = bpil_array_desc + i; 272 253 offs = bpf_prog_info_read_offset_u64(&info_linear->info, 273 254 desc->array_offset); 274 255 addr = offs + ptr_to_u64(info_linear->data);
+7 -3
tools/perf/util/symbol-elf.c
··· 873 873 874 874 #ifdef HAVE_LIBBFD_BUILDID_SUPPORT 875 875 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) 877 877 { 878 878 size_t size = sizeof(bid->data); 879 - int err = -1; 879 + int err = -1, fd; 880 880 bfd *abfd; 881 881 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); 883 887 if (!abfd) 884 888 return -1; 885 889