diff options
author | Alan Modra <amodra@gmail.com> | 2020-12-14 19:36:47 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2020-12-14 23:36:19 +1030 |
commit | a86c6c19643e9ac795b17846e5b0db8b3e4c54de (patch) | |
tree | f5386f7ef68e42eb20296f3b436e0d947fbfa136 /bfd/elf.c | |
parent | 8da4f428d1663541bdd49f5aa2041d06ac6a06de (diff) | |
download | binutils-gdb-a86c6c19643e9ac795b17846e5b0db8b3e4c54de.tar.gz |
Put bfd_section_from_shdr loop detection array in elf_tdata
The static variables used by bfd_section_from_shdr to detect loops
in ELF sections have a problem: Comparing a BFD pointer doesn't
guarantee that the current bfd is the same as the one previously used
to allocate the sections_being_created array. For example, doing
size bad_elf_1 bad_elf_2
with two corrupted ELF files containing section loops will leave the
section_being_created array allocated for the first file and since
bfd_close is called for bad_elf_1 before bfd_elf_2 is opened, it is
possible that the BFD for the second file is allocated in the same
memory as the first file. If bad_elf_2 has more sections than
bad_elf_1 then we might write beyond the end of the array.
So this patch implements the FIXME Nick put in a comment about
attaching the array to the BFD.
* elf-bfd.h (struct elf_obj_tdata): Add being_created.
* elf.c (bfd_section_from_shdr): Delete static vars for loop
detection. Use new tdata variable instead.
* elfcode.h (elf_object_p): Allocate being_created.
Diffstat (limited to 'bfd/elf.c')
-rw-r--r-- | bfd/elf.c | 54 |
1 files changed, 9 insertions, 45 deletions
diff --git a/bfd/elf.c b/bfd/elf.c index 419c5f4420c..7f2237655d3 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -2045,49 +2045,20 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) const struct elf_backend_data *bed; const char *name; bfd_boolean ret = TRUE; - static bfd_boolean * sections_being_created = NULL; - static bfd * sections_being_created_abfd = NULL; - static unsigned int nesting = 0; if (shindex >= elf_numsections (abfd)) return FALSE; - if (++ nesting > 3) + /* PR17512: A corrupt ELF binary might contain a loop of sections via + sh_link or sh_info. Detect this here, by refusing to load a + section that we are already in the process of loading. */ + if (elf_tdata (abfd)->being_created[shindex]) { - /* PR17512: A corrupt ELF binary might contain a recursive group of - sections, with each the string indices pointing to the next in the - loop. Detect this here, by refusing to load a section that we are - already in the process of loading. We only trigger this test if - we have nested at least three sections deep as normal ELF binaries - can expect to recurse at least once. - - FIXME: It would be better if this array was attached to the bfd, - rather than being held in a static pointer. */ - - if (sections_being_created_abfd != abfd) - { - free (sections_being_created); - sections_being_created = NULL; - } - if (sections_being_created == NULL) - { - size_t amt = elf_numsections (abfd) * sizeof (bfd_boolean); - - /* PR 26005: Do not use bfd_zalloc here as the memory might - be released before the bfd has been fully scanned. */ - sections_being_created = (bfd_boolean *) bfd_zmalloc (amt); - if (sections_being_created == NULL) - return FALSE; - sections_being_created_abfd = abfd; - } - if (sections_being_created [shindex]) - { - _bfd_error_handler - (_("%pB: warning: loop in section dependencies detected"), abfd); - return FALSE; - } - sections_being_created [shindex] = TRUE; + _bfd_error_handler + (_("%pB: warning: loop in section dependencies detected"), abfd); + return FALSE; } + elf_tdata (abfd)->being_created[shindex] = TRUE; hdr = elf_elfsections (abfd)[shindex]; ehdr = elf_elfheader (abfd); @@ -2611,14 +2582,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) fail: ret = FALSE; success: - if (sections_being_created && sections_being_created_abfd == abfd) - sections_being_created [shindex] = FALSE; - if (-- nesting == 0) - { - free (sections_being_created); - sections_being_created = NULL; - sections_being_created_abfd = NULL; - } + elf_tdata (abfd)->being_created[shindex] = FALSE; return ret; } |