https://sourceware.org/bugzilla/show_bug.cgi?id=21440
Bug ID: 21440 Summary: Malicious PE with invalid extended relocation can cause binutils/objdumo 2.28 to allocate any-size big memory Product: binutils Version: 2.28 Status: UNCONFIRMED Severity: normal Priority: P2 Component: binutils Assignee: unassigned at sourceware dot org Reporter: jgj212 at gmail dot com Target Milestone: --- Created attachment 10029 --> https://sourceware.org/bugzilla/attachment.cgi?id=10029&action=edit Malicious PE with invalid extended relocation sample ----------------------- $objdump -x $FILE ----------------------- With x option, objdump will allocate memory to store relocation data, this is done in the following function: static void dump_relocs_in_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) { …. relsize = bfd_get_reloc_upper_bound (abfd, section); //can be controlled … relpp = (arelent **) xmalloc (relsize); //allocate memory relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms); //read reloc data … } the relsize is computed as : (asect->reloc_count + 1) * sizeof (arelent *) // coff_get_reloc_upper_bound(…) In the coff standard, reoc_count is WORD, which is 16bit wide. sizeof (arelent *) is constant and small. So normally, the result is small. But when PE section contain extended relocation, everything will go bad. PE section header is inited in the following function: static void coff_set_alignment_hook (bfd * abfd ATTRIBUTE_UNUSED, asection * section, void * scnhdr) { … /* Check for extended relocs. */ if (hdr->s_flags & IMAGE_SCN_LNK_NRELOC_OVFL) { struct external_reloc dst; struct internal_reloc n; file_ptr oldpos = bfd_tell (abfd); bfd_size_type relsz = bfd_coff_relsz (abfd); if (bfd_seek (abfd, (file_ptr) hdr->s_relptr, 0) != 0) //seek to the first reloc data return; if (bfd_bread (& dst, relsz, abfd) != relsz) //read the first reloc data return; coff_swap_reloc_in (abfd, &dst, &n);//fill struct if (bfd_seek (abfd, oldpos, 0) != 0) return; section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1; //can be controlled section->rel_filepos += relsz; } … } From the above, when pe section contain extended relocation, reloc_count is assigned from n.r_vaddr. n is a instance of struct internal_reloc as follow: struct internal_reloc { bfd_vma r_vaddr; /* Virtual address of reference */ long r_symndx; /* Index into symbol table */ unsigned short r_type; /* Relocation type */ unsigned char r_size; /* Used by RS/6000 and ECOFF */ unsigned char r_extern; /* Used by ECOFF */ unsigned long r_offset; /* Used by Alpha ECOFF, SPARC, others */ }; r_vaddr's type is unsigned long, it can be 32bit and 64bit, according to the os-archive. it is from the dst, which is a instance of struct external_reloc as follow: struct external_reloc { char r_vaddr[4]; char r_symndx[4]; char r_type[2]; }; So n.r_vaddr is really 32bit wide, section->reloc_count is also 32bit wide. (asect->reloc_count + 1) * sizeof (arelent *) can be very large. To control the memory size, it just need to modify the r_vaddr field of first reloc data, if can be from 0 to 0Xffffffff. This could cause memory exhaustion to dos. -- You are receiving this mail because: You are on the CC list for the bug. _______________________________________________ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils