Bug 90924 - lto-plugin/lto-plugin.c heap memory corruption due to insufficient sanitization.
Summary: lto-plugin/lto-plugin.c heap memory corruption due to insufficient sanitization.
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: plugins (show other bugs)
Version: 9.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-invalid-code
Depends on:
Blocks:
 
Reported: 2019-06-18 23:37 UTC by Ren Kimura
Modified: 2019-08-09 15:19 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-06-19 00:00:00


Attachments
Proof of Concept ELF binary for nm command (361 bytes, application/octet-stream)
2019-06-18 23:37 UTC, Ren Kimura
Details
Proof of Concept ELF binary for nm command (Purified) (2.30 KB, application/x-sharedlib)
2019-06-29 21:50 UTC, Ren Kimura
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ren Kimura 2019-06-18 23:37:16 UTC
Created attachment 46501 [details]
Proof of Concept ELF binary for nm command

On several major linux distributions like ubuntu, debian... binutils uses ELF parser from gold linker plugin, /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so instead of libbfd. 
I found a memory corruption bug (Heap OOB read) of gold ELF parser linked from latest nm command(2.30). 
If input binary file has a zero value string section offset (i.e e_shstrndx == 0.), gold ELF parser try to find string section by simple_object_find_sections() without enough sanitization.

https://github.com/gcc-mirror/gcc/blob/6c552ff765c1b02d3ec9094f92c1ce58f8cda14b/lto-plugin/lto-plugin.c#L1059

As a result if e_shstrndx is equal to 0, "(eor->shstrndx - 1)" at this line cause integer overflow (a result becomes negative value (unsigned int)-1 ) 
https://github.com/gcc-mirror/gcc/blob/6c552ff765c1b02d3ec9094f92c1ce58f8cda14b/libiberty/simple-object-elf.c#L600

and try to do out of bound access against heap memory, cause memory corruption.

On Ubuntu 18.10 with GCC 9.1.0.

PoC file is attached to this email.
Execute PoC:
nm ./memcorrupt_nm-2.30_gcc-9.1.0_gold 
Segmentation fault (core dumped)

CrashDump:
nm --plugin ./gcc-9.1.0/build/lto-plugin/.libs/liblto_plugin.so.0.0.0 ./memcorrupt_nm-2.30_gcc-9.1.0_gold
Core was generated by `nm --plugin ./gcc-9.1.0/build/lto-plugin/.libs/liblto_plugin.so.0.0.0 ./researc'.              
Program terminated with signal SIGSEGV, Segmentation fault.                                                           
#0  simple_object_fetch_little_64 (buf=0x5678b4bc3640 <error: Cannot access memory at address 0x5678b4bc3640>)        
    at ../../libiberty/simple-object-common.h:262                                                                     
262       return (((ulong_type) buf[7] << 56)                                                                         
(gdb) bt                                                                                                              
#0  simple_object_fetch_little_64 (buf=0x5678b4bc3640 <error: Cannot access memory at address 0x5678b4bc3640>)        
    at ../../libiberty/simple-object-common.h:262                                                                     
#1  0x00007feb2c5b7268 in simple_object_elf_find_sections (sobj=0x5638b4bc3630, pfn=0x7feb2c5b0930 <process_symtab>,  
    data=0x7ffd5884ca00, err=0x7ffd5884c9f4) at ../../libiberty/simple-object-elf.c:601                               
#2  0x00007feb2c5b0dd5 in claim_file_handler (file=0x7ffd5884cac0, claimed=0x7ffd5884cabc)                            
    at ../../lto-plugin/lto-plugin.c:1025                                                                             
#3  0x00007feb2c49796b in ?? () from /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so                             
#4  0x00007feb2c497bef in ?? () from /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so                             
#5  0x00007feb2c30880a in bfd_check_format_matches () from /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so       
#6  0x00005638b4012cb0 in ?? ()
#7  0x00005638b40109e6 in ?? ()
#8  0x00007feb2c07f09b in __libc_start_main (main=0x5638b4010590, argc=4, argv=0x7ffd5884ceb8, init=<optimized out>,
    fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffd5884cea8) at ../csu/libc-start.c:308
#9  0x00005638b4010a5a in ?? ()
```

Thanks
Ren
Comment 1 Martin Liška 2019-06-19 12:01:34 UTC
(In reply to Ren Kimura from comment #0)
> Created attachment 46501 [details]
> Proof of Concept ELF binary for nm command

Hello.

Is the file created with a fuzzer? I can confirm the crash, but the ELF container
looks broken to me:

$ readelf -S memcorrupt_nm-2.30_gcc-9.1.0_gold 
readelf: Warning: possibly corrupt ELF file header - it has a non-zero section header offset, but no section headers
readelf: Error: Too many program headers - 0xdeff - the file is not that big

Can you provide steps how to create such a file?

Thanks

> 
> On several major linux distributions like ubuntu, debian... binutils uses
> ELF parser from gold linker plugin,
> /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so instead of libbfd. 
> I found a memory corruption bug (Heap OOB read) of gold ELF parser linked
> from latest nm command(2.30). 
> If input binary file has a zero value string section offset (i.e e_shstrndx
> == 0.), gold ELF parser try to find string section by
> simple_object_find_sections() without enough sanitization.
> 
> https://github.com/gcc-mirror/gcc/blob/
> 6c552ff765c1b02d3ec9094f92c1ce58f8cda14b/lto-plugin/lto-plugin.c#L1059
> 
> As a result if e_shstrndx is equal to 0, "(eor->shstrndx - 1)" at this line
> cause integer overflow (a result becomes negative value (unsigned int)-1 ) 
> https://github.com/gcc-mirror/gcc/blob/
> 6c552ff765c1b02d3ec9094f92c1ce58f8cda14b/libiberty/simple-object-elf.c#L600
> 
> and try to do out of bound access against heap memory, cause memory
> corruption.
> 
> On Ubuntu 18.10 with GCC 9.1.0.
> 
> PoC file is attached to this email.
> Execute PoC:
> nm ./memcorrupt_nm-2.30_gcc-9.1.0_gold 
> Segmentation fault (core dumped)
> 
> CrashDump:
> nm --plugin ./gcc-9.1.0/build/lto-plugin/.libs/liblto_plugin.so.0.0.0
> ./memcorrupt_nm-2.30_gcc-9.1.0_gold
> Core was generated by `nm --plugin
> ./gcc-9.1.0/build/lto-plugin/.libs/liblto_plugin.so.0.0.0 ./researc'.       
> 
> Program terminated with signal SIGSEGV, Segmentation fault.                 
> 
> #0  simple_object_fetch_little_64 (buf=0x5678b4bc3640 <error: Cannot access
> memory at address 0x5678b4bc3640>)        
>     at ../../libiberty/simple-object-common.h:262                           
> 
> 262       return (((ulong_type) buf[7] << 56)                               
> 
> (gdb) bt                                                                    
> 
> #0  simple_object_fetch_little_64 (buf=0x5678b4bc3640 <error: Cannot access
> memory at address 0x5678b4bc3640>)        
>     at ../../libiberty/simple-object-common.h:262                           
> 
> #1  0x00007feb2c5b7268 in simple_object_elf_find_sections
> (sobj=0x5638b4bc3630, pfn=0x7feb2c5b0930 <process_symtab>,  
>     data=0x7ffd5884ca00, err=0x7ffd5884c9f4) at
> ../../libiberty/simple-object-elf.c:601                               
> #2  0x00007feb2c5b0dd5 in claim_file_handler (file=0x7ffd5884cac0,
> claimed=0x7ffd5884cabc)                            
>     at ../../lto-plugin/lto-plugin.c:1025                                   
> 
> #3  0x00007feb2c49796b in ?? () from
> /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so                        
> 
> #4  0x00007feb2c497bef in ?? () from
> /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so                        
> 
> #5  0x00007feb2c30880a in bfd_check_format_matches () from
> /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so       
> #6  0x00005638b4012cb0 in ?? ()
> #7  0x00005638b40109e6 in ?? ()
> #8  0x00007feb2c07f09b in __libc_start_main (main=0x5638b4010590, argc=4,
> argv=0x7ffd5884ceb8, init=<optimized out>,
>     fini=<optimized out>, rtld_fini=<optimized out>,
> stack_end=0x7ffd5884cea8) at ../csu/libc-start.c:308
> #9  0x00005638b4010a5a in ?? ()
> ```
> 
> Thanks
> Ren
Comment 2 Ren Kimura 2019-06-29 21:50:03 UTC
Created attachment 46534 [details]
Proof of Concept ELF binary for nm command (Purified)
Comment 3 Ren Kimura 2019-06-29 21:55:52 UTC
Hi. Sorry for late. I've just attached more simple one.

PoC file for this bug can be created easily, just generating ELF file and edit e_shstrndx in ELF header file to 0.

Attached one is built from simple Hello World program.

#include <stdio.h>
int main() {
  printf("Hello World\n");
};

gcc -o memcorrupt_nm-2.30_gcc-9.1.0_gold_simple hello_world.c

Edit e_shtrndx (offset 0x3E) to 0.

Thanks
Ren

(In reply to Martin Liška from comment #1)
> (In reply to Ren Kimura from comment #0)
> > Created attachment 46501 [details]
> > Proof of Concept ELF binary for nm command
> 
> Hello.
> 
> Is the file created with a fuzzer? I can confirm the crash, but the ELF
> container
> looks broken to me:
> 
> $ readelf -S memcorrupt_nm-2.30_gcc-9.1.0_gold 
> readelf: Warning: possibly corrupt ELF file header - it has a non-zero
> section header offset, but no section headers
> readelf: Error: Too many program headers - 0xdeff - the file is not that big
> 
> Can you provide steps how to create such a file?
> 
> Thanks
> 
> > 
> > On several major linux distributions like ubuntu, debian... binutils uses
> > ELF parser from gold linker plugin,
> > /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so instead of libbfd. 
> > I found a memory corruption bug (Heap OOB read) of gold ELF parser linked
> > from latest nm command(2.30). 
> > If input binary file has a zero value string section offset (i.e e_shstrndx
> > == 0.), gold ELF parser try to find string section by
> > simple_object_find_sections() without enough sanitization.
> > 
> > https://github.com/gcc-mirror/gcc/blob/
> > 6c552ff765c1b02d3ec9094f92c1ce58f8cda14b/lto-plugin/lto-plugin.c#L1059
> > 
> > As a result if e_shstrndx is equal to 0, "(eor->shstrndx - 1)" at this line
> > cause integer overflow (a result becomes negative value (unsigned int)-1 ) 
> > https://github.com/gcc-mirror/gcc/blob/
> > 6c552ff765c1b02d3ec9094f92c1ce58f8cda14b/libiberty/simple-object-elf.c#L600
> > 
> > and try to do out of bound access against heap memory, cause memory
> > corruption.
> > 
> > On Ubuntu 18.10 with GCC 9.1.0.
> > 
> > PoC file is attached to this email.
> > Execute PoC:
> > nm ./memcorrupt_nm-2.30_gcc-9.1.0_gold 
> > Segmentation fault (core dumped)
> > 
> > CrashDump:
> > nm --plugin ./gcc-9.1.0/build/lto-plugin/.libs/liblto_plugin.so.0.0.0
> > ./memcorrupt_nm-2.30_gcc-9.1.0_gold
> > Core was generated by `nm --plugin
> > ./gcc-9.1.0/build/lto-plugin/.libs/liblto_plugin.so.0.0.0 ./researc'.       
> > 
> > Program terminated with signal SIGSEGV, Segmentation fault.                 
> > 
> > #0  simple_object_fetch_little_64 (buf=0x5678b4bc3640 <error: Cannot access
> > memory at address 0x5678b4bc3640>)        
> >     at ../../libiberty/simple-object-common.h:262                           
> > 
> > 262       return (((ulong_type) buf[7] << 56)                               
> > 
> > (gdb) bt                                                                    
> > 
> > #0  simple_object_fetch_little_64 (buf=0x5678b4bc3640 <error: Cannot access
> > memory at address 0x5678b4bc3640>)        
> >     at ../../libiberty/simple-object-common.h:262                           
> > 
> > #1  0x00007feb2c5b7268 in simple_object_elf_find_sections
> > (sobj=0x5638b4bc3630, pfn=0x7feb2c5b0930 <process_symtab>,  
> >     data=0x7ffd5884ca00, err=0x7ffd5884c9f4) at
> > ../../libiberty/simple-object-elf.c:601                               
> > #2  0x00007feb2c5b0dd5 in claim_file_handler (file=0x7ffd5884cac0,
> > claimed=0x7ffd5884cabc)                            
> >     at ../../lto-plugin/lto-plugin.c:1025                                   
> > 
> > #3  0x00007feb2c49796b in ?? () from
> > /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so                        
> > 
> > #4  0x00007feb2c497bef in ?? () from
> > /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so                        
> > 
> > #5  0x00007feb2c30880a in bfd_check_format_matches () from
> > /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-multiarch.so       
> > #6  0x00005638b4012cb0 in ?? ()
> > #7  0x00005638b40109e6 in ?? ()
> > #8  0x00007feb2c07f09b in __libc_start_main (main=0x5638b4010590, argc=4,
> > argv=0x7ffd5884ceb8, init=<optimized out>,
> >     fini=<optimized out>, rtld_fini=<optimized out>,
> > stack_end=0x7ffd5884cea8) at ../csu/libc-start.c:308
> > #9  0x00005638b4010a5a in ?? ()
> > ```
> > 
> > Thanks
> > Ren
Comment 4 Martin Liška 2019-07-01 07:28:52 UTC
(In reply to Ren Kimura from comment #3)
> Hi. Sorry for late. I've just attached more simple one.
> 
> PoC file for this bug can be created easily, just generating ELF file and
> edit e_shstrndx in ELF header file to 0.
> 
> Attached one is built from simple Hello World program.
> 
> #include <stdio.h>
> int main() {
>   printf("Hello World\n");
> };
> 
> gcc -o memcorrupt_nm-2.30_gcc-9.1.0_gold_simple hello_world.c
> 
> Edit e_shtrndx (offset 0x3E) to 0.

What sense does it make to create a valid ELF container and then corrupt it?
It's expected that various tools will crash then.
Comment 5 Ren Kimura 2019-07-04 00:34:09 UTC
Yes. I can understand what you want to say. It may annoying for developers to fix such nitpicky bugs. 
But unfortunately these kind of bugs have been reported like, memory corruption with *crafted* ELF file.
https://www.google.com/search?q=binutils+crafted+elf+cve

From the perspective of attackers, they can prevent some kind of services by sending crafted ELF file through network. i.e. Denial of Service.

Please consider our request of fixing.

Thanks

(In reply to Martin Liška from comment #4)
> (In reply to Ren Kimura from comment #3)
> > Hi. Sorry for late. I've just attached more simple one.
> > 
> > PoC file for this bug can be created easily, just generating ELF file and
> > edit e_shstrndx in ELF header file to 0.
> > 
> > Attached one is built from simple Hello World program.
> > 
> > #include <stdio.h>
> > int main() {
> >   printf("Hello World\n");
> > };
> > 
> > gcc -o memcorrupt_nm-2.30_gcc-9.1.0_gold_simple hello_world.c
> > 
> > Edit e_shtrndx (offset 0x3E) to 0.
> 
> What sense does it make to create a valid ELF container and then corrupt it?
> It's expected that various tools will crash then.
Comment 6 Martin Liška 2019-07-04 06:53:49 UTC
(In reply to Ren Kimura from comment #5)
> Yes. I can understand what you want to say. It may annoying for developers
> to fix such nitpicky bugs. 

I'm willing to fix any inappropriate ELF container that will be created with GCC
or with an other ELF creating tool. 

> But unfortunately these kind of bugs have been reported like, memory
> corruption with *crafted* ELF file.
> https://www.google.com/search?q=binutils+crafted+elf+cve

I can imagine bazillion of such corruptions if you do a random mutation of an ELF
container.

> 
> From the perspective of attackers, they can prevent some kind of services by
> sending crafted ELF file through network. i.e. Denial of Service.

I'm all ears here. What kind of service would run or analyze untrusted ELF executables?

> 
> Please consider our request of fixing.

Patches are welcome, feel free to send a patch submission to the mailing list.

> 
> Thanks
> 
> (In reply to Martin Liška from comment #4)
> > (In reply to Ren Kimura from comment #3)
> > > Hi. Sorry for late. I've just attached more simple one.
> > > 
> > > PoC file for this bug can be created easily, just generating ELF file and
> > > edit e_shstrndx in ELF header file to 0.
> > > 
> > > Attached one is built from simple Hello World program.
> > > 
> > > #include <stdio.h>
> > > int main() {
> > >   printf("Hello World\n");
> > > };
> > > 
> > > gcc -o memcorrupt_nm-2.30_gcc-9.1.0_gold_simple hello_world.c
> > > 
> > > Edit e_shtrndx (offset 0x3E) to 0.
> > 
> > What sense does it make to create a valid ELF container and then corrupt it?
> > It's expected that various tools will crash then.
Comment 7 Tobias Burnus 2019-07-23 08:02:15 UTC
Mark as FIXED - as I see that the fix has been committed to the GCC trunk.
[I assume, someone will merge it also to binutils-gdb/libiberty]


Ren Kimura has submitted a patch:
https://gcc.gnu.org/ml/gcc-patches/2019-07/msg01009.html

which was approved and then committed as: r273718

Author: marxin
Date: Tue Jul 23 07:33:32 2019
New Revision: 273718

URL: https://gcc.gnu.org/viewcvs?rev=273718&root=gcc&view=rev
Log:
libiberty: Check zero value shstrndx in simple-object-elf.c

Modified:
    trunk/libiberty/ChangeLog
    trunk/libiberty/simple-object-elf.c
Comment 8 Richard Biener 2019-07-25 10:47:25 UTC
Author: rguenth
Date: Thu Jul 25 10:46:54 2019
New Revision: 273793

URL: https://gcc.gnu.org/viewcvs?rev=273793&root=gcc&view=rev
Log:
2019-07-25  Richard Biener  <rguenther@suse.de>

	PR lto/90924
	Backport from mainline
	2019-07-12  Ren Kimura  <rkx1209dev@gmail.com>

	* simple-object-elf.c (simple_object_elf_match): Check zero value
	shstrndx.

Modified:
    branches/gcc-9-branch/libiberty/ChangeLog
    branches/gcc-9-branch/libiberty/simple-object-elf.c
Comment 9 Richard Biener 2019-07-25 10:48:58 UTC
Author: rguenth
Date: Thu Jul 25 10:48:26 2019
New Revision: 273794

URL: https://gcc.gnu.org/viewcvs?rev=273794&root=gcc&view=rev
Log:
2019-07-25  Richard Biener  <rguenther@suse.de>

	PR lto/90924
	Backport from mainline
	2019-07-12  Ren Kimura  <rkx1209dev@gmail.com>

	* simple-object-elf.c (simple_object_elf_match): Check zero value
	shstrndx.

Modified:
    branches/gcc-8-branch/libiberty/ChangeLog
    branches/gcc-8-branch/libiberty/simple-object-elf.c
Comment 10 Richard Biener 2019-07-25 10:51:18 UTC
Author: rguenth
Date: Thu Jul 25 10:50:47 2019
New Revision: 273795

URL: https://gcc.gnu.org/viewcvs?rev=273795&root=gcc&view=rev
Log:
2019-07-25  Richard Biener  <rguenther@suse.de>

	PR lto/90924
	Backport from mainline
	2019-07-12  Ren Kimura  <rkx1209dev@gmail.com>

	* simple-object-elf.c (simple_object_elf_match): Check zero value
	shstrndx.

Modified:
    branches/gcc-7-branch/libiberty/ChangeLog
    branches/gcc-7-branch/libiberty/simple-object-elf.c
Comment 11 Tanaya Patil 2019-08-09 09:18:19 UTC
Hello,

May I know if Binutils-2.31 is also affected and requires this fix? Any heads up will be appreciated.

Thank you in advance.

Best Regards,
Comment 12 Nick Clifton 2019-08-09 15:19:28 UTC
Hi Tanaya,

(In reply to Tanaya Patil from comment #11)
> May I know if Binutils-2.31 is also affected and requires this fix? Any
> heads up will be appreciated.

Yes it is.  As is 2.32 as well.

I have however updated the binutils mainline sources so version 2.33, 
which is due out soon, will contain the fix.

Cheers
  Nick