Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.98k stars 559 forks source link

heap-buffer-overflow Perl_vivify_ref (pp_hot.c:4362) #15762

Open p5pRT opened 7 years ago

p5pRT commented 7 years ago

Migrated from rt.perl.org#130321 (status was 'open')

Searchable as RT130321$

p5pRT commented 7 years ago

From @geeknik

Triggered with Perl v5.25.7-98-gdf13534 while fuzzing with AFL. However\, it doesn't always crash like this. Sometimes it is a simple null pointer deref @​ Perl_vivify_ref /root/perl/pp_hot.c​:4362\, sometimes it's an assertion failure @​ Perl_sv_clear (sv.c​:6540)\, but running it multiple times in a row can trigger the buffer overflow.

perl -e 'map$$_=0\,%$T=%​::'

==14745==ERROR​: AddressSanitizer​: heap-buffer-overflow on address 0x6210000114f0 at pc 0x0000008ac879 bp 0x7ffc728d4e80 sp 0x7ffc728d4e78 READ of size 8 at 0x6210000114f0 thread T0   #0 0x8ac878 in Perl_vivify_ref /root/perl/pp_hot.c​:4362​:2   #1 0x9aeb55 in Perl_pp_rv2sv /root/perl/pp.c​:404​:11   #2 0x7f81fb in Perl_runops_debug /root/perl/dump.c​:2260​:23   #3 0x5a0ab3 in S_run_body /root/perl/perl.c​:2526​:2   #4 0x5a0ab3 in perl_run /root/perl/perl.c​:2449   #5 0x4de6dd in main /root/perl/perlmain.c​:123​:9   #6 0x7fced94dbb44 in __libc_start_main /build/glibc-daoqzt/glibc-2.19/csu/libc-start.c​:287   #7 0x4de34c in _start (/root/perl/perl+0x4de34c)

0x6210000114f0 is located 0 bytes to the right of 4080-byte region [0x621000010500\,0x6210000114f0) allocated by thread T0 here​:   #0 0x4c0ccb in malloc (/root/perl/perl+0x4c0ccb)   #1 0x7fc067 in Perl_safesysmalloc /root/perl/util.c​:153​:21

SUMMARY​: AddressSanitizer​: heap-buffer-overflow /root/perl/pp_hot.c​:4362 Perl_vivify_ref Shadow bytes around the buggy address​:   0x0c427fffa240​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c427fffa250​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c427fffa260​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c427fffa270​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c427fffa280​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c427fffa290​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa   0x0c427fffa2a0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c427fffa2b0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c427fffa2c0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c427fffa2d0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c427fffa2e0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes)​:   Addressable​: 00   Partially addressable​: 01 02 03 04 05 06 07   Heap left redzone​: fa   Heap right redzone​: fb   Freed heap region​: fd   Stack left redzone​: f1   Stack mid redzone​: f2   Stack right redzone​: f3   Stack partial redzone​: f4   Stack after return​: f5   Stack use after scope​: f8   Global redzone​: f9   Global init order​: f6   Poisoned by user​: f7   Container overflow​: fc   ASan internal​: fe ==14745==ABORTING

Perl 5.20.2 fails like so​: ==20640== Invalid read of size 1 ==20640== at 0x4F0DA54​: ??? (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F0DBBD​: Perl_sv_unmagic (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F0C7DE​: Perl_sv_clear (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F0D289​: Perl_sv_free2 (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F3943C​: Perl_pp_mapwhile (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4EFB055​: Perl_runops_standard (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4E8B73D​: perl_run (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x400E18​: main (in /usr/bin/perl) ==20640== Address 0xff00000012 is not stack'd\, malloc'd or (recently) free'd ==20640== ==20640== ==20640== Process terminating with default action of signal 11 (SIGSEGV) ==20640== Access not within mapped region at address 0xFF00000012 ==20640== at 0x4F0DA54​: ??? (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F0DBBD​: Perl_sv_unmagic (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F0C7DE​: Perl_sv_clear (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F0D289​: Perl_sv_free2 (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4F3943C​: Perl_pp_mapwhile (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4EFB055​: Perl_runops_standard (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x4E8B73D​: perl_run (in /usr/lib/x86_64-linux-gnu/libperl.so.5.20.2) ==20640== by 0x400E18​: main (in /usr/bin/perl) ==20640== If you believe this happened as a result of a stack ==20640== overflow in your program's main thread (unlikely but ==20640== possible)\, you can try to increase the size of the ==20640== main thread stack using the --main-stacksize= flag. ==20640== The main thread stack size used in this run was 8388608. Segmentation fault

p5pRT commented 7 years ago

From @tonycoz

On Sun\, 11 Dec 2016 14​:18​:44 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-98-gdf13534 while fuzzing with AFL. However\, it doesn't always crash like this. Sometimes it is a simple null pointer deref @​ Perl_vivify_ref /root/perl/pp_hot.c​:4362\, sometimes it's an assertion failure @​ Perl_sv_clear (sv.c​:6540)\, but running it multiple times in a row can trigger the buffer overflow.

perl -e 'map$$_=0\,%$T=%​::'

This looks like another stack-not-refcounted bug.

Tony

p5pRT commented 7 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 7 years ago

From @tonycoz

On Tue\, 13 Dec 2016 21​:11​:01 -0800\, tonyc wrote​:

On Sun\, 11 Dec 2016 14​:18​:44 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-98-gdf13534 while fuzzing with AFL. However\, it doesn't always crash like this. Sometimes it is a simple null pointer deref @​ Perl_vivify_ref /root/perl/pp_hot.c​:4362\, sometimes it's an assertion failure @​ Perl_sv_clear (sv.c​:6540)\, but running it multiple times in a row can trigger the buffer overflow.

perl -e 'map$$_=0\,%$T=%​::'

This looks like another stack-not-refcounted bug.

I can't reproduce the buffer overflow.

The random behaviour is caused by hash randomization\, so if you can still reproduce it\, can you provide the hash seed where it occurs? Like this​:

  PERL_HASH_SEED_DEBUG=1 ./perl -e 'map$$_=0\,%$T=%​::'

You'll get something like​:

HASH_FUNCTION = HYBRID_OAATHU_SIPHASH_1_3 HASH_SEED = 0x9c21037e507a4e690fc406e7d29b44b960076c875b6852f8 PERTURB_KEYS = 1 (RANDOM)

which in my case produced​:

perl​: sv.c​:6547​: Perl_sv_clear​: Assertion `((svtype)((sv)->sv_flags & 0xff)) != (svtype)0xff' failed. Aborted

Tony

p5pRT commented 7 years ago

From @iabyn

On Tue\, Jan 31\, 2017 at 03​:23​:20PM -0800\, Tony Cook via RT wrote​:

On Tue\, 13 Dec 2016 21​:11​:01 -0800\, tonyc wrote​:

On Sun\, 11 Dec 2016 14​:18​:44 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-98-gdf13534 while fuzzing with AFL. However\, it doesn't always crash like this. Sometimes it is a simple null pointer deref @​ Perl_vivify_ref /root/perl/pp_hot.c​:4362\, sometimes it's an assertion failure @​ Perl_sv_clear (sv.c​:6540)\, but running it multiple times in a row can trigger the buffer overflow.

perl -e 'map$$_=0\,%$T=%​::'

This looks like another stack-not-refcounted bug.

I can't reproduce the buffer overflow.

The random behaviour is caused by hash randomization\, so if you can still reproduce it\, can you provide the hash seed where it occurs? Like this​:

PERL_HASH_SEED_DEBUG=1 ./perl -e 'map$$_=0\,%$T=%​::'

You'll get something like​:

HASH_FUNCTION = HYBRID_OAATHU_SIPHASH_1_3 HASH_SEED = 0x9c21037e507a4e690fc406e7d29b44b960076c875b6852f8 PERTURB_KEYS = 1 (RANDOM)

which in my case produced​:

perl​: sv.c​:6547​: Perl_sv_clear​: Assertion `((svtype)((sv)->sv_flags & 0xff)) != (svtype)0xff' failed. Aborted

I also cannot reproduce the buffer overflow​: with both valgrind and ASAN I've run the code in a loop for a couple of hours and only ever got the assertion failure or null ptr deref.

I agree its a stack refcount issue. The code can be reduced further as follows​:

  map$$_=0\,%$T=%​::   =>   map $$_=0\, %$T = ('T'\, $​::{'T'});   =>   map $$_=0\, %$T = ('T'\, *T);

The hash assign in list context leaves a fake glob on the stack which had been stored as $T->{'T'}. The map then iterates over 'T' and the fake glob. The first iteration does $$_=0\, which is equivalent to ${'T'} = 0 which stops $T being a reference to the hash\, so $%T gets freed\, so the glob $T->{'T'} gets freed\, so on the second iteration $_ gets aliased to a freed or reallocated value.

Given that this requires code which already dangerously manipulates globs and stashes\, I can't see that it is a security issue.

I propose that the ticket be moved to the public queue\, added to the 'stack not ref counted' meta ticket\, then ignored until such time as we fix that wider issue.

-- No matter how many dust sheets you use\, you will get paint on the carpet.

p5pRT commented 7 years ago

From @iabyn

On Mon\, Feb 20\, 2017 at 11​:40​:55AM +0000\, Dave Mitchell wrote​:

Given that this requires code which already dangerously manipulates globs and stashes\, I can't see that it is a security issue.

I propose that the ticket be moved to the public queue\, added to the 'stack not ref counted' meta ticket\, then ignored until such time as we fix that wider issue.

which I am now doing.

-- "Foul and greedy Dwarf - you have eaten the last candle."   -- "Hordes of the Things"\, BBC Radio.