perf tool: Fix use after free in filename__read_build_id
PATCH 1/1 perf tool: Fix use after free in filename__read_build_id
In filename__read_build_id, phdr points to memory in buf, which gets realloced before a call to fseek that uses phdr->p_offset. This change stores the value of p_offset before buf is realloced, so the fseek can use the value safely.
--- tools/perf/util/symbol-minimal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/perf/util/symbol-minimal.c +6 -2
@@ -129,6 +129,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)for (i =0 , phdr = buf; i < ehdr.e_phnum; i++, phdr++) {void *tmp; +long offset;if (need_swap) { phdr->p_type =bswap_32 (phdr->p_type);
@@ -140,12 +141,13 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)continue ; buf_size = phdr->p_filesz; + offset = phdr->p_offset; tmp =realloc (buf, buf_size);if (tmp ==NULL ) goto out_free; buf = tmp; -fseek (fp, phdr->p_offset,SEEK_SET ); +fseek (fp, offset,SEEK_SET );if (fread (buf, buf_size,1 , fp) !=1 ) goto out_free;
@@ -178,6 +180,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)for (i =0 , phdr = buf; i < ehdr.e_phnum; i++, phdr++) {void *tmp; +long offset;if (need_swap) { phdr->p_type =bswap_32 (phdr->p_type);
@@ -189,12 +192,13 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)continue ; buf_size = phdr->p_filesz; + offset = phdr->p_offset; tmp =realloc (buf, buf_size);if (tmp ==NULL ) goto out_free; buf = tmp; -fseek (fp, phdr->p_offset,SEEK_SET ); +fseek (fp, offset,SEEK_SET );if (fread (buf, buf_size,1 , fp) !=1 ) goto out_free;
Signature · 1 line
1.9.1
Quoted 23 lines · Mitchell Krome
In
filename__read_build_id, phdr points to memory in buf, which gets realloced before a call to fseek that usesphdr->p_offset. This change stores the value ofp_offsetbefore buf is realloced, so the fseek can use the value safely.Signed-off-by Mitchell Krome <[email protected]>--- tools/perf/util/symbol-minimal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)tools/perf/util/symbol-minimal.c +1
-0@@ -129,6 +129,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)for (i =0 , phdr = buf; i < ehdr.e_phnum; i++, phdr++) {void *tmp; +long offset;if (need_swap) { phdr->p_type =bswap_32 (phdr->p_type);@@ -140,12 +141,13 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)continue ;
tools/perf/util/symbol-minimal.c int filename__read_build_id(const char *filename, void *bf, size_t size) · line 150
Quoted 10 lines
tools/perf/util/symbol-minimal.c +2
-1buf_size = phdr->p_filesz; + offset = phdr->p_offset; tmp =realloc (buf, buf_size);if (tmp ==NULL ) goto out_free; buf = tmp; -fseek (fp, phdr->p_offset,SEEK_SET ); +fseek (fp, offset,SEEK_SET );
so the concern is that the realloc buf_size will be smaller than the 'buf' offset of phdr->p_offset value, right? Anyway:
jirka
Arnaldo Carvalho de Melo
maintainerEm Tue, Dec 16, 2014 at 04:35:23PM +0100, Jiri Olsa escreveu:
Quoted 31 lines · Mitchell Krome
Quoted 30 lines
In
filename__read_build_id, phdr points to memory in buf, which gets realloced before a call to fseek that usesphdr->p_offset. This change stores the value ofp_offsetbefore buf is realloced, so the fseek can use the value safely.Signed-off-by Mitchell Krome <[email protected]>--- tools/perf/util/symbol-minimal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)tools/perf/util/symbol-minimal.c +2
-0@@ -129,6 +129,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)for (i =0 , phdr = buf; i < ehdr.e_phnum; i++, phdr++) {void *tmp; +long offset;if (need_swap) { phdr->p_type =bswap_32 (phdr->p_type);@@ -140,12 +141,13 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)continue ; buf_size = phdr->p_filesz; + offset = phdr->p_offset; tmp =realloc (buf, buf_size);if (tmp ==NULL ) goto out_free;
Quoted 6 lines
tools/perf/util/symbol-minimal.c int filename__read_build_id(const char *filename, void *bf, size_t size) · line 150
Quoted 3 lines
tools/perf/util/symbol-minimal.c +1
-1buf = tmp; -fseek (fp, phdr->p_offset,SEEK_SET ); +fseek (fp, offset,SEEK_SET );so the concern is that the realloc
buf_sizewill be smaller than the 'buf' offset ofphdr->p_offsetvalue, right? Anyway:
at first I got unsure because of what realloc man page says, i.e. the common part will have the same contents, i.e. before and after what is in a a given offset will remain the same if in an area <= new size.
But yeah, if phdr->p_filesz < offsetof(Elf32_Phdr, p_offset) (unlikely, I guess), then accessing phdr->p_offset after the realloc may be unsafe (perhaps when using some off-limits memory access tool that paints freed memory?).
Anyway, the new code is clear and more robust, applying.
Quoted 1 line
Acked-by Jiri Olsa <[email protected]>
Thanks,
Quoted 1 line
jirka
tip-bot for Mitchell Krome
merge bot[tip:perf/urgent] perf symbols: Fix use after free in filename__read_build_id
In reply to Mitchell Kromeperf symbols: Fix use after free in filename__read_build_id
Commit-ID: 7ad74b41e56e4f7f42c6b765bc44428cd09310d7 Gitweb: http://git.kernel.org/tip/7ad74b41e56e4f7f42c6b765bc44428cd09310d7 Author: Mitchell Krome <[email protected]> AuthorDate: Tue, 16 Dec 2014 12:16:12 +1000 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 17 Dec 2014 11:58:17 -0300
perf symbols: Fix use after free in filename__read_build_id
In filename__read_build_id, phdr points to memory in buf, which gets realloced before a call to fseek that uses phdr->p_offset. This change stores the value of p_offset before buf is realloced, so the fseek can use the value safely.
--- tools/perf/util/symbol-minimal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/perf/util/symbol-minimal.c +6 -2
@@ -129,6 +129,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)for (i =0 , phdr = buf; i < ehdr.e_phnum; i++, phdr++) {void *tmp; +long offset;if (need_swap) { phdr->p_type =bswap_32 (phdr->p_type);
@@ -140,12 +141,13 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)continue ; buf_size = phdr->p_filesz; + offset = phdr->p_offset; tmp =realloc (buf, buf_size);if (tmp ==NULL ) goto out_free; buf = tmp; -fseek (fp, phdr->p_offset,SEEK_SET ); +fseek (fp, offset,SEEK_SET );if (fread (buf, buf_size,1 , fp) !=1 ) goto out_free;
@@ -178,6 +180,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)for (i =0 , phdr = buf; i < ehdr.e_phnum; i++, phdr++) {void *tmp; +long offset;if (need_swap) { phdr->p_type =bswap_32 (phdr->p_type);
@@ -189,12 +192,13 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)continue ; buf_size = phdr->p_filesz; + offset = phdr->p_offset; tmp =realloc (buf, buf_size);if (tmp ==NULL ) goto out_free; buf = tmp; -fseek (fp, phdr->p_offset,SEEK_SET ); +fseek (fp, offset,SEEK_SET );if (fread (buf, buf_size,1 , fp) !=1 ) goto out_free;