From: Jiri Slaby <jirislaby@kernel.org>
To: Riccardo Mancini <rickyman7@gmail.com>, namhyung@kernel.org
Cc: linux-perf-users@vger.kernel.org, Ian Rogers <irogers@google.com>,
acme@kernel.org
Subject: Re: perf-top: heap-buffer-overflow in elf_sec__is_text reported from ASan
Date: Mon, 21 Jun 2021 08:54:17 +0200 [thread overview]
Message-ID: <c0f82ef2-e87b-8ede-3525-429fcb9f645c@kernel.org> (raw)
In-Reply-To: <e883163b0c0295bfb8a56dcc82f6cae4cbbdc84a.camel@gmail.com>
Hi,
On 18. 06. 21, 11:17, Riccardo Mancini wrote:
> ASan reports a heap-buffer-overflow in elf_sec__is_text when using perf-top.
> The bug is introduced by commit 6833e0b: "perf symbols: Resolve symbols against
> debug file first" from Jiri Slaby.
...
> pwndbg> p syms_ss->name
> $4 = 0x607000018f90 "/usr/lib/debug/usr/lib64/libglib-2.0.so.0.6800.2-2.68.2-1.fc34.x86_64.debug"
> pwndbg> p runtime_ss->name
> $5 = 0x6070000190e0 "/root/.debug/.build-id/37/475e3b392fb3971c8ad0d9ac0a4d7e1b93c521/elf"
Out of curiosity, could you post output of 'readelf -S' on both of them?
> Furthermore, the branch in line symbol-elf.c:1241 (the one added in the referred
> patch) is not taken.
>
> As you can see, sh_name is out-of-range (342 > 332).
> I can also provide a coredump, if it can be useful.
>
> I have no idea of how the ELF stuff works, but I thought this may be caused by
> the fact that secstrs is built from runtime_ss, while shdr is built from syms_ss
> (since it is the change of the commit). I tried to test this theory with the
> following change:
>
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index a73345730ba9..8d2b692f11a2 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -1146,7 +1146,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
> if (symstrs == NULL)
> goto out_elf_end;
>
> - sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
> + sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
> if (sec_strndx == NULL)
> goto out_elf_end;
>
> @@ -1244,6 +1244,14 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
> * values for syms (invalid) and runtime (valid).
> */
> if (shdr.sh_type == SHT_NOBITS) {
> + sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
> + if (sec_strndx == NULL)
> + goto out_elf_end;
> +
> + secstrs = elf_getdata(sec_strndx, NULL);
> + if (secstrs == NULL)
> + goto out_elf_end;
> +
> sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
> if (!sec)
> goto out_elf_end;
>
> However, it still overflows, but oddly the branch is not taken before the
> overflow. Is there some kind of state that gets changed in the ELF structs?
Something like that should work. But you should reset sec_strndx also in
the else branch, IMO. So what about this?
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1081,7 +1081,7 @@ int dso__load_sym(struct dso *dso, struct map
*map, struct symsrc *syms_ss,
struct maps *kmaps = kmap ? map__kmaps(map) : NULL;
struct map *curr_map = map;
struct dso *curr_dso = dso;
- Elf_Data *symstrs, *secstrs;
+ Elf_Data *symstrs, *secstrs, *secstrs_run, *secstrs_sym;
uint32_t nr_syms;
int err = -1;
uint32_t idx;
@@ -1150,8 +1150,16 @@ int dso__load_sym(struct dso *dso, struct map
*map, struct symsrc *syms_ss,
if (sec_strndx == NULL)
goto out_elf_end;
- secstrs = elf_getdata(sec_strndx, NULL);
- if (secstrs == NULL)
+ secstrs_run = elf_getdata(sec_strndx, NULL);
+ if (secstrs_run == NULL)
+ goto out_elf_end;
+
+ sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+ if (sec_strndx == NULL)
+ goto out_elf_end;
+
+ secstrs_sym = elf_getdata(sec_strndx, NULL);
+ if (secstrs_sym == NULL)
goto out_elf_end;
nr_syms = shdr.sh_size / shdr.sh_entsize;
@@ -1237,6 +1245,8 @@ int dso__load_sym(struct dso *dso, struct map
*map, struct symsrc *syms_ss,
gelf_getshdr(sec, &shdr);
+ secstrs = secstrs_sym;
+
/*
* We have to fallback to runtime when syms' section
header has
* NOBITS set. NOBITS results in file offset
(sh_offset) not
@@ -1249,6 +1259,7 @@ int dso__load_sym(struct dso *dso, struct map
*map, struct symsrc *syms_ss,
goto out_elf_end;
gelf_getshdr(sec, &shdr);
+ secstrs = secstrs_run;
}
if (is_label && !elf_sec__filter(&shdr, secstrs))
thanks,
--
js
--
js
suse labs
next prev parent reply other threads:[~2021-06-21 6:54 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-18 9:17 perf-top: heap-buffer-overflow in elf_sec__is_text reported from ASan Riccardo Mancini
2021-06-21 6:54 ` Jiri Slaby [this message]
2021-06-21 14:15 ` Riccardo Mancini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c0f82ef2-e87b-8ede-3525-429fcb9f645c@kernel.org \
--to=jirislaby@kernel.org \
--cc=acme@kernel.org \
--cc=irogers@google.com \
--cc=linux-perf-users@vger.kernel.org \
--cc=namhyung@kernel.org \
--cc=rickyman7@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.