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.

perf symbol-minimal: Fix ehdr reading in filename__read_build_id

The e_ident is part of the ehdr and so reading it a second time would
mean the read ehdr was displaced by 16-bytes. Switch from stdio to
open/read/lseek syscalls for similarity with the symbol-elf version of
the function and so that later changes can alter then open flags.

Fixes: fef8f648bb47 ("perf symbol: Fix use-after-free in filename__read_build_id")
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250823000024.724394-2-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
ba0b7081 f79a62f4

+27 -28
+27 -28
tools/perf/util/symbol-minimal.c
··· 4 4 5 5 #include <errno.h> 6 6 #include <unistd.h> 7 - #include <stdio.h> 8 7 #include <fcntl.h> 9 8 #include <string.h> 10 9 #include <stdlib.h> ··· 87 88 */ 88 89 int filename__read_build_id(const char *filename, struct build_id *bid) 89 90 { 90 - FILE *fp; 91 - int ret = -1; 91 + int fd, ret = -1; 92 92 bool need_swap = false, elf32; 93 - u8 e_ident[EI_NIDENT]; 94 - int i; 95 93 union { 96 94 struct { 97 95 Elf32_Ehdr ehdr32; ··· 99 103 Elf64_Phdr *phdr64; 100 104 }; 101 105 } hdrs; 102 - void *phdr; 103 - size_t phdr_size; 104 - void *buf = NULL; 105 - size_t buf_size = 0; 106 + void *phdr, *buf = NULL; 107 + ssize_t phdr_size, ehdr_size, buf_size = 0; 106 108 107 - fp = fopen(filename, "r"); 108 - if (fp == NULL) 109 + fd = open(filename, O_RDONLY); 110 + if (fd < 0) 109 111 return -1; 110 112 111 - if (fread(e_ident, sizeof(e_ident), 1, fp) != 1) 113 + if (read(fd, hdrs.ehdr32.e_ident, EI_NIDENT) != EI_NIDENT) 112 114 goto out; 113 115 114 - if (memcmp(e_ident, ELFMAG, SELFMAG) || 115 - e_ident[EI_VERSION] != EV_CURRENT) 116 + if (memcmp(hdrs.ehdr32.e_ident, ELFMAG, SELFMAG) || 117 + hdrs.ehdr32.e_ident[EI_VERSION] != EV_CURRENT) 116 118 goto out; 117 119 118 - need_swap = check_need_swap(e_ident[EI_DATA]); 119 - elf32 = e_ident[EI_CLASS] == ELFCLASS32; 120 + need_swap = check_need_swap(hdrs.ehdr32.e_ident[EI_DATA]); 121 + elf32 = hdrs.ehdr32.e_ident[EI_CLASS] == ELFCLASS32; 122 + ehdr_size = (elf32 ? sizeof(hdrs.ehdr32) : sizeof(hdrs.ehdr64)) - EI_NIDENT; 120 123 121 - if (fread(elf32 ? (void *)&hdrs.ehdr32 : (void *)&hdrs.ehdr64, 122 - elf32 ? sizeof(hdrs.ehdr32) : sizeof(hdrs.ehdr64), 123 - 1, fp) != 1) 124 + if (read(fd, 125 + (elf32 ? (void *)&hdrs.ehdr32 : (void *)&hdrs.ehdr64) + EI_NIDENT, 126 + ehdr_size) != ehdr_size) 124 127 goto out; 125 128 126 129 if (need_swap) { ··· 133 138 hdrs.ehdr64.e_phnum = bswap_16(hdrs.ehdr64.e_phnum); 134 139 } 135 140 } 136 - phdr_size = elf32 ? hdrs.ehdr32.e_phentsize * hdrs.ehdr32.e_phnum 137 - : hdrs.ehdr64.e_phentsize * hdrs.ehdr64.e_phnum; 141 + if ((elf32 && hdrs.ehdr32.e_phentsize != sizeof(Elf32_Phdr)) || 142 + (!elf32 && hdrs.ehdr64.e_phentsize != sizeof(Elf64_Phdr))) 143 + goto out; 144 + 145 + phdr_size = elf32 ? sizeof(Elf32_Phdr) * hdrs.ehdr32.e_phnum 146 + : sizeof(Elf64_Phdr) * hdrs.ehdr64.e_phnum; 138 147 phdr = malloc(phdr_size); 139 148 if (phdr == NULL) 140 149 goto out; 141 150 142 - fseek(fp, elf32 ? hdrs.ehdr32.e_phoff : hdrs.ehdr64.e_phoff, SEEK_SET); 143 - if (fread(phdr, phdr_size, 1, fp) != 1) 151 + lseek(fd, elf32 ? hdrs.ehdr32.e_phoff : hdrs.ehdr64.e_phoff, SEEK_SET); 152 + if (read(fd, phdr, phdr_size) != phdr_size) 144 153 goto out_free; 145 154 146 155 if (elf32) ··· 152 153 else 153 154 hdrs.phdr64 = phdr; 154 155 155 - for (i = 0; i < elf32 ? hdrs.ehdr32.e_phnum : hdrs.ehdr64.e_phnum; i++) { 156 - size_t p_filesz; 156 + for (int i = 0; i < (elf32 ? hdrs.ehdr32.e_phnum : hdrs.ehdr64.e_phnum); i++) { 157 + ssize_t p_filesz; 157 158 158 159 if (need_swap) { 159 160 if (elf32) { ··· 179 180 goto out_free; 180 181 buf = tmp; 181 182 } 182 - fseek(fp, elf32 ? hdrs.phdr32[i].p_offset : hdrs.phdr64[i].p_offset, SEEK_SET); 183 - if (fread(buf, p_filesz, 1, fp) != 1) 183 + lseek(fd, elf32 ? hdrs.phdr32[i].p_offset : hdrs.phdr64[i].p_offset, SEEK_SET); 184 + if (read(fd, buf, p_filesz) != p_filesz) 184 185 goto out_free; 185 186 186 187 ret = read_build_id(buf, p_filesz, bid, need_swap); ··· 193 194 free(buf); 194 195 free(phdr); 195 196 out: 196 - fclose(fp); 197 + close(fd); 197 198 return ret; 198 199 } 199 200