Bug 1658947 (CVE-2018-19931)
Summary: | CVE-2018-19931 binutils: Heap-based buffer overflow in bfd_elf32_swap_phdr_in function resulting in a denial of service | ||
---|---|---|---|
Product: | [Other] Security Response | Reporter: | Andrej Nemec <anemec> |
Component: | vulnerability | Assignee: | Red Hat Product Security <security-response-team> |
Status: | CLOSED WONTFIX | QA Contact: | |
Severity: | low | Docs Contact: | |
Priority: | low | ||
Version: | unspecified | CC: | abhgupta, dbaker, fweimer, jokerman, kanderso, law, mcermak, mnewsome, mpolacek, nickc, ohudlick, sjubran, sthangav, trankin, virt-maint |
Target Milestone: | --- | Keywords: | Security |
Target Release: | --- | ||
Hardware: | All | ||
OS: | Linux | ||
Whiteboard: | |||
Fixed In Version: | Doc Type: | If docs needed, set a value | |
Doc Text: | Story Points: | --- | |
Clone Of: | Environment: | ||
Last Closed: | 2019-06-10 10:43:52 UTC | Type: | --- |
Regression: | --- | Mount Type: | --- |
Documentation: | --- | CRM: | |
Verified Versions: | Category: | --- | |
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
Cloudforms Team: | --- | Target Upstream Version: | |
Embargoed: | |||
Bug Depends On: | |||
Bug Blocks: | 1658951 |
Description
Andrej Nemec
2018-12-13 08:53:06 UTC
This does not appear to impact 64bit nm. ``` (gdb) print sizeof(*i_phdr) $5 = 64 (gdb) print i_ehdrp->e_phnum $6 = 536870912 ``` On 32-bit, 536870912 * 64 = 0. Presumably bfd_alloc returns success on an allocation of 0, and a later write triggers the heap out-of-bounds write. On 64-bit, the calculation does not overflow with this poc. I originally didn't understand where e_phnum is coming from though. If we run readelf on the binary: ``` Number of program headers: 65535 (536870912) ``` I'd expect 65535, instead we have this: ``` (gdb) print i_ehdrp->e_phnum $9 = 536870912 ``` which matches readelfs argument after the number of program headers. However: ``` /* * Extended Numbering * * If the real number of program header table entries is larger than * or equal to PN_XNUM(0xffff), it is set to sh_info field of the * section header at index 0, and PN_XNUM is set to e_phnum * field. Otherwise, the section header at index 0 is zero * initialized, if it exists. * * Specifications are available in: * * - Oracle: Linker and Libraries. * Part No: 817–1984–19, August 2011. * http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf * * - System V ABI AMD64 Architecture Processor Supplement * Draft Version 0.99.4, * January 13, 2010. * http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf */ ``` readelf source shows that this is a special case: ``` if (section_headers != NULL && elf_header.e_phnum == PN_XNUM && section_headers[0].sh_info != 0) printf (" (%ld)", (long) section_headers[0].sh_info); ``` and it looks like sh_info is 32bits, hence, we can't set it to a value that would overflow on 64bit platforms. Also, here's a run of the 32-bit crash. ``` nm poc Segmentation fault (core dumped) ==28303== Memcheck, a memory error detector ==28303== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==28303== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==28303== Command: nm poc ==28303== ==28303== Invalid write of size 4 ==28303== at 0xC39A52: bfd_elf32_swap_phdr_in (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC3C98E: bfd_elf32_object_p (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC18549: bfd_check_format_matches (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0x804B6DE: ??? (in /usr/bin/nm) ==28303== by 0x804BCA7: ??? (in /usr/bin/nm) ==28303== by 0x9FED35: (below main) (in /lib/libc-2.12.so) ==28303== Address 0x40201b8 is 0 bytes after a block of size 4,064 alloc'd ==28303== at 0x40072B2: malloc (vg_replace_malloc.c:270) ==28303== by 0xCA0D45: objalloc_create (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC1AD67: _bfd_new_bfd (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC1B07C: bfd_fopen (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC1B266: bfd_openr (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0x804B601: ??? (in /usr/bin/nm) ==28303== by 0x804BCA7: ??? (in /usr/bin/nm) ==28303== by 0x9FED35: (below main) (in /lib/libc-2.12.so) ... ==28303== Process terminating with default action of signal 11 (SIGSEGV) ==28303== Access not within mapped region at address 0x9066 ==28303== at 0xA63311: __GI_memcpy (in /lib/libc-2.12.so) ==28303== by 0xA561F7: _IO_sgetn (in /lib/libc-2.12.so) ==28303== by 0xA496AD: fread (in /lib/libc-2.12.so) ==28303== by 0xC143D0: ??? (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC1392A: bfd_bread (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC3C9C8: bfd_elf32_object_p (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0xC18549: bfd_check_format_matches (in /usr/lib/libbfd-2.20.51.0.2-5.44.el6.so) ==28303== by 0x804B6DE: ??? (in /usr/bin/nm) ==28303== by 0x804BCA7: ??? (in /usr/bin/nm) ==28303== by 0x9FED35: (below main) (in /lib/libc-2.12.so) ==28303== If you believe this happened as a result of a stack ==28303== overflow in your program's main thread (unlikely but ==28303== possible), you can try to increase the size of the ==28303== main thread stack using the --main-stacksize= flag. ==28303== The main thread stack size used in this run was 10485760. ``` 64-bit run: ``` $ nm poc nm: poc: memory exhausted ``` Is it permissible to close this BZ ? I would consider the problem itself to be very low priority. It only affects specially crafted, corrupt 32-bit ELF binaries, and the only denial of service is that tools like nm and objdump will fail, and then only if these tools themselves are 32-bit executables. The bug has been fixed upstream and will be in the next official release of the GNU binutils. This in turn will make its way into Fedora rawhide, and eventually some future RHEL release. Backporting the patch to other versions of Fedora and RHEL is possible, but it does not seem like a profitable use of time. |