Skip to content

Commit ba0b708

Browse files
captain5050namhyung
authored andcommitted
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: fef8f64 ("perf symbol: Fix use-after-free in filename__read_build_id") Signed-off-by: Ian Rogers <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Namhyung Kim <[email protected]>
1 parent f79a62f commit ba0b708

File tree

1 file changed

+27
-28
lines changed

1 file changed

+27
-28
lines changed

tools/perf/util/symbol-minimal.c

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include <errno.h>
66
#include <unistd.h>
7-
#include <stdio.h>
87
#include <fcntl.h>
98
#include <string.h>
109
#include <stdlib.h>
@@ -88,11 +87,8 @@ int filename__read_debuglink(const char *filename __maybe_unused,
8887
*/
8988
int filename__read_build_id(const char *filename, struct build_id *bid)
9089
{
91-
FILE *fp;
92-
int ret = -1;
90+
int fd, ret = -1;
9391
bool need_swap = false, elf32;
94-
u8 e_ident[EI_NIDENT];
95-
int i;
9692
union {
9793
struct {
9894
Elf32_Ehdr ehdr32;
@@ -103,28 +99,27 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
10399
Elf64_Phdr *phdr64;
104100
};
105101
} hdrs;
106-
void *phdr;
107-
size_t phdr_size;
108-
void *buf = NULL;
109-
size_t buf_size = 0;
102+
void *phdr, *buf = NULL;
103+
ssize_t phdr_size, ehdr_size, buf_size = 0;
110104

111-
fp = fopen(filename, "r");
112-
if (fp == NULL)
105+
fd = open(filename, O_RDONLY);
106+
if (fd < 0)
113107
return -1;
114108

115-
if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
109+
if (read(fd, hdrs.ehdr32.e_ident, EI_NIDENT) != EI_NIDENT)
116110
goto out;
117111

118-
if (memcmp(e_ident, ELFMAG, SELFMAG) ||
119-
e_ident[EI_VERSION] != EV_CURRENT)
112+
if (memcmp(hdrs.ehdr32.e_ident, ELFMAG, SELFMAG) ||
113+
hdrs.ehdr32.e_ident[EI_VERSION] != EV_CURRENT)
120114
goto out;
121115

122-
need_swap = check_need_swap(e_ident[EI_DATA]);
123-
elf32 = e_ident[EI_CLASS] == ELFCLASS32;
116+
need_swap = check_need_swap(hdrs.ehdr32.e_ident[EI_DATA]);
117+
elf32 = hdrs.ehdr32.e_ident[EI_CLASS] == ELFCLASS32;
118+
ehdr_size = (elf32 ? sizeof(hdrs.ehdr32) : sizeof(hdrs.ehdr64)) - EI_NIDENT;
124119

125-
if (fread(elf32 ? (void *)&hdrs.ehdr32 : (void *)&hdrs.ehdr64,
126-
elf32 ? sizeof(hdrs.ehdr32) : sizeof(hdrs.ehdr64),
127-
1, fp) != 1)
120+
if (read(fd,
121+
(elf32 ? (void *)&hdrs.ehdr32 : (void *)&hdrs.ehdr64) + EI_NIDENT,
122+
ehdr_size) != ehdr_size)
128123
goto out;
129124

130125
if (need_swap) {
@@ -138,23 +133,27 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
138133
hdrs.ehdr64.e_phnum = bswap_16(hdrs.ehdr64.e_phnum);
139134
}
140135
}
141-
phdr_size = elf32 ? hdrs.ehdr32.e_phentsize * hdrs.ehdr32.e_phnum
142-
: hdrs.ehdr64.e_phentsize * hdrs.ehdr64.e_phnum;
136+
if ((elf32 && hdrs.ehdr32.e_phentsize != sizeof(Elf32_Phdr)) ||
137+
(!elf32 && hdrs.ehdr64.e_phentsize != sizeof(Elf64_Phdr)))
138+
goto out;
139+
140+
phdr_size = elf32 ? sizeof(Elf32_Phdr) * hdrs.ehdr32.e_phnum
141+
: sizeof(Elf64_Phdr) * hdrs.ehdr64.e_phnum;
143142
phdr = malloc(phdr_size);
144143
if (phdr == NULL)
145144
goto out;
146145

147-
fseek(fp, elf32 ? hdrs.ehdr32.e_phoff : hdrs.ehdr64.e_phoff, SEEK_SET);
148-
if (fread(phdr, phdr_size, 1, fp) != 1)
146+
lseek(fd, elf32 ? hdrs.ehdr32.e_phoff : hdrs.ehdr64.e_phoff, SEEK_SET);
147+
if (read(fd, phdr, phdr_size) != phdr_size)
149148
goto out_free;
150149

151150
if (elf32)
152151
hdrs.phdr32 = phdr;
153152
else
154153
hdrs.phdr64 = phdr;
155154

156-
for (i = 0; i < elf32 ? hdrs.ehdr32.e_phnum : hdrs.ehdr64.e_phnum; i++) {
157-
size_t p_filesz;
155+
for (int i = 0; i < (elf32 ? hdrs.ehdr32.e_phnum : hdrs.ehdr64.e_phnum); i++) {
156+
ssize_t p_filesz;
158157

159158
if (need_swap) {
160159
if (elf32) {
@@ -180,8 +179,8 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
180179
goto out_free;
181180
buf = tmp;
182181
}
183-
fseek(fp, elf32 ? hdrs.phdr32[i].p_offset : hdrs.phdr64[i].p_offset, SEEK_SET);
184-
if (fread(buf, p_filesz, 1, fp) != 1)
182+
lseek(fd, elf32 ? hdrs.phdr32[i].p_offset : hdrs.phdr64[i].p_offset, SEEK_SET);
183+
if (read(fd, buf, p_filesz) != p_filesz)
185184
goto out_free;
186185

187186
ret = read_build_id(buf, p_filesz, bid, need_swap);
@@ -194,7 +193,7 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
194193
free(buf);
195194
free(phdr);
196195
out:
197-
fclose(fp);
196+
close(fd);
198197
return ret;
199198
}
200199

0 commit comments

Comments
 (0)