Perl / perl5

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

heap-use-after-free Perl_sv_setpv_bufsize (sv.c:4956) #15747

Open p5pRT opened 7 years ago

p5pRT commented 7 years ago

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

Searchable as RT130256$

p5pRT commented 7 years ago

From @geeknik

Triggered with Perl v5.25.7-26-g7332835.

./perl -e '@​0=$0|=*0=H or()'

==17224==ERROR​: AddressSanitizer​: heap-use-after-free on address 0x60200000e630 at pc 0x0000009399d4 bp 0x7ffc6e92ce70 sp 0x7ffc6e92ce68 WRITE of size 1 at 0x60200000e630 thread T0   #0 0x9399d3 in Perl_sv_setpv_bufsize /root/perl/sv.c​:4956​:5   #1 0xb1b832 in Perl_do_vop /root/perl/doop.c​:1011​:9   #2 0x9d13ef in Perl_pp_bit_or /root/perl/pp.c​:2471​:2   #3 0x7f63bb in Perl_runops_debug /root/perl/dump.c​:2260​:23   #4 0x5a06c3 in S_run_body /root/perl/perl.c​:2526​:2   #5 0x5a06c3 in perl_run /root/perl/perl.c​:2449   #6 0x4de6cd in main /root/perl/perlmain.c​:123​:9   #7 0x7f62d5d19b44 in __libc_start_main /build/glibc-daoqzt/glibc-2.19/csu/libc-start.c​:287   #8 0x4de33c in _start (/root/perl/perl+0x4de33c)

0x60200000e630 is located 0 bytes inside of 10-byte region [0x60200000e630\,0x60200000e63a) freed by thread T0 here​:   #0 0x4c0a3b in __interceptor_free (/root/perl/perl+0x4c0a3b)   #1 0x7fb019 in Perl_safesysfree /root/perl/util.c​:388​:2   #2 0x955f30 in Perl_sv_free2 /root/perl/sv.c​:7056​:9

previously allocated by thread T0 here​:   #0 0x4c0cbb in malloc (/root/perl/perl+0x4c0cbb)   #1 0x7fa227 in Perl_safesysmalloc /root/perl/util.c​:153​:21

SUMMARY​: AddressSanitizer​: heap-use-after-free /root/perl/sv.c​:4956 Perl_sv_setpv_bufsize Shadow bytes around the buggy address​:   0x0c047fff9c70​: fa fa 05 fa fa fa 00 05 fa fa 04 fa fa fa 05 fa   0x0c047fff9c80​: fa fa 05 fa fa fa 00 00 fa fa 00 02 fa fa 05 fa   0x0c047fff9c90​: fa fa 00 02 fa fa 00 fa fa fa 00 04 fa fa 07 fa   0x0c047fff9ca0​: fa fa 00 02 fa fa 00 03 fa fa 06 fa fa fa 00 03   0x0c047fff9cb0​: fa fa 05 fa fa fa 00 02 fa fa 00 05 fa fa 00 06 =>0x0c047fff9cc0​: fa fa 00 04 fa fa[fd]fd fa fa fd fa fa fa 00 02   0x0c047fff9cd0​: fa fa 00 02 fa fa 00 02 fa fa 00 02 fa fa 00 06   0x0c047fff9ce0​: fa fa 00 04 fa fa 00 02 fa fa 00 02 fa fa 00 00   0x0c047fff9cf0​: fa fa fd fa fa fa 00 02 fa fa fd fa fa fa 00 02   0x0c047fff9d00​: fa fa 00 02 fa fa 00 02 fa fa 00 02 fa fa 00 02   0x0c047fff9d10​: fa fa 00 02 fa fa 00 02 fa fa 00 02 fa fa 00 02 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 ==17224==ABORTING

p5pRT commented 7 years ago

From @tonycoz

On Sun\, 04 Dec 2016 01​:53​:36 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-26-g7332835.

./perl -e '@​0=$0|=*0=H or()'

Stack traces from valgrind​:

==19883== Invalid write of size 1 ==19883== at 0x5E3822​: Perl_sv_setpv_bufsize (sv.c​:4956) ==19883== by 0x6AB21D​: Perl_do_vop (doop.c​:1011) ==19883== by 0x62A6CB​: Perl_pp_bit_or (pp.c​:2471) ==19883== by 0x556D8A​: Perl_runops_debug (dump.c​:2260) ==19883== by 0x460EB1​: S_run_body (perl.c​:2526) ==19883== by 0x460494​: perl_run (perl.c​:2449) ==19883== by 0x41EFDD​: main (perlmain.c​:123) ==19883== Address 0x5f793b0 is 0 bytes inside a block of size 10 free'd ==19883== at 0x4C29E90​: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==19883== by 0x558891​: Perl_safesysfree (util.c​:388) ==19883== by 0x5F1B8E​: Perl_sv_clear (sv.c​:6754) ==19883== by 0x5F37A1​: Perl_sv_free2 (sv.c​:7056) ==19883== by 0x46CF09​: S_SvREFCNT_dec (inline.h​:189) ==19883== by 0x480C7A​: Perl_gp_free (gv.c​:2598) ==19883== by 0x5DF75B​: Perl_sv_setsv_flags (sv.c​:4569) ==19883== by 0x5A0C78​: Perl_pp_sassign (pp_hot.c​:226) ==19883== by 0x556D8A​: Perl_runops_debug (dump.c​:2260) ==19883== by 0x460EB1​: S_run_body (perl.c​:2526) ==19883== by 0x460494​: perl_run (perl.c​:2449) ==19883== by 0x41EFDD​: main (perlmain.c​:123)

This looks like another stack-not-refcounted issue.

Tony

p5pRT commented 7 years ago

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

p5pRT commented 7 years ago

From @tonycoz

On Sun\, 04 Dec 2016 16​:20​:22 -0800\, tonyc wrote​:

On Sun\, 04 Dec 2016 01​:53​:36 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-26-g7332835.

./perl -e '@​0=$0|=*0=H or()'

Simplifies to​:

./perl -e '$0|=*0="H"'

This looks like another stack-not-refcounted issue.

And so it is\, now public.

Tony

p5pRT commented 7 years ago

From @demerphq

On 31 Jan 2017 1​:04 p.m.\, "Tony Cook via RT" \perlbug\-followup@​perl\.org wrote​:

On Sun\, 04 Dec 2016 16​:20​:22 -0800\, tonyc wrote​:

On Sun\, 04 Dec 2016 01​:53​:36 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-26-g7332835.

./perl -e '@​0=$0|=*0=H or()'

Simplifies to​:

./perl -e '$0|=*0="H"'

This looks like another stack-not-refcounted issue.

And so it is\, now public

Is it *just* a stack not refcounted bug or is it more. What is supposed to happen when you assign a string to a glob? I know what is supposed to happen when it's a ref or another glob\, but a string?

Yves

p5pRT commented 7 years ago

From @tonycoz

On Tue\, Jan 31\, 2017 at 07​:30​:56AM +0100\, demerphq wrote​:

On 31 Jan 2017 1​:04 p.m.\, "Tony Cook via RT" \perlbug\-followup@​perl\.org wrote​:

On Sun\, 04 Dec 2016 16​:20​:22 -0800\, tonyc wrote​:

On Sun\, 04 Dec 2016 01​:53​:36 -0800\, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-26-g7332835.

./perl -e '@​0=$0|=*0=H or()'

Simplifies to​:

./perl -e '$0|=*0="H"'

This looks like another stack-not-refcounted issue.

And so it is\, now public

Is it *just* a stack not refcounted bug or is it more. What is supposed to happen when you assign a string to a glob? I know what is supposed to happen when it's a ref or another glob\, but a string?

It looks like the same as​:

  $0|=*0=*H

Tony

p5pRT commented 7 years ago

From @iabyn

On Tue\, Jan 31\, 2017 at 07​:30​:56AM +0100\, demerphq wrote​:

Is it *just* a stack not refcounted bug or is it more. What is supposed to happen when you assign a string to a glob? I know what is supposed to happen when it's a ref or another glob\, but a string?

It uses the string as the name of a typeglob. Sp

  *foo = "bar";

is equivalent to

  *foo = *bar;

And both make the GP of *foo point to the GP of *bar\, freeing the old GP and any of its contents.

-- Overhead\, without any fuss\, the stars were going out.   -- Arthur C Clarke

p5pRT commented 7 years ago

From @demerphq

On 1 Feb 2017 22​:29\, "Dave Mitchell" \davem@​iabyn\.com wrote​:

On Tue\, Jan 31\, 2017 at 07​:30​:56AM +0100\, demerphq wrote​:

Is it *just* a stack not refcounted bug or is it more. What is supposed to happen when you assign a string to a glob? I know what is supposed to happen when it's a ref or another glob\, but a string?

It uses the string as the name of a typeglob. Sp

  *foo = "bar";

is equivalent to

  *foo = *bar;

And both make the GP of *foo point to the GP of *bar\, freeing the old GP and any of its contents

Wow. Not what I expected. Do you happen to know where that is documented? Is it intentional or coincidental that it works like that?

Yves

p5pRT commented 7 years ago

From @iabyn

On Wed\, Feb 01\, 2017 at 05​:21​:47PM +0100\, demerphq wrote​:

On 1 Feb 2017 22​:29\, "Dave Mitchell" \davem@​iabyn\.com wrote​:

It uses the string as the name of a typeglob. Sp

\*foo = "bar";

is equivalent to

\*foo = \*bar;

And both make the GP of *foo point to the GP of *bar\, freeing the old GP and any of its contents

Wow. Not what I expected. Do you happen to know where that is documented?

No idea - I just looked at what it actually does.

Is it intentional or coincidental that it works like that?

No idea (I seem to keep saying that). There does seem to be a lot of 'if you're expecting a typeglob and you get a string\, treat it as the name of the typeglob' behaviour in perl though\, c.f.

  readline 'FH'

behaving like

  readline *FH

I hate typeglobs.

-- This email is confidential\, and now that you have read it you are legally obliged to shoot yourself. Or shoot a lawyer\, if you prefer. If you have received this email in error\, place it in its original wrapping and return for a full refund. By opening this email\, you accept that Elvis lives.

p5pRT commented 6 years ago

From @geeknik

Just triggered this bug in v5.27.4-29-gdc41635.

./perl -e '$$.=*$=*$$'

================================================================= ==30274==ERROR​: AddressSanitizer​: heap-use-after-free on address 0x60200000e1f0 at pc 0xbcce5c bp 0x7fff60a28b20 sp 0x7fff60a28b18 WRITE of size 1 at 0x60200000e1f0 thread T0   #0 0xbcce5b in Perl_sv_setpv_bufsize /root/perl/sv.c​:4958   #1 0xaa2e02 in Perl_pp_concat /root/perl/pp_hot.c​:292   #2 0x92ee8e in Perl_runops_debug /root/perl/dump.c​:2486   #3 0x5a9bed in S_run_body /root/perl/perl.c​:2592   #4 0x5a9bed in perl_run /root/perl/perl.c​:2520   #5 0x4362e9 in main /root/perl/perlmain.c​:123   #6 0x7f6fce22cb44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)   #7 0x4372fa (/root/perl/perl+0x4372fa)

0x60200000e1f0 is located 0 bytes inside of 10-byte region [0x60200000e1f0\,0x60200000e1fa) freed by thread T0 here​:   #0 0x7f6fcf37e527 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x54527)   #1 0xb254d0 in Perl_sv_clear /root/perl/sv.c​:6825   #2 0xb28547 in Perl_sv_free2 /root/perl/sv.c​:7127   #3 0x5b91cb in S_SvREFCNT_dec /root/perl/inline.h​:191   #4 0x5b91cb in Perl_gp_free /root/perl/gv.c​:2638   #5 0xbc0d7e in S_glob_assign_glob /root/perl/sv.c​:3950   #6 0xb75020 in Perl_sv_setsv_flags /root/perl/sv.c​:4461   #7 0xa9c427 in Perl_pp_sassign /root/perl/pp_hot.c​:226   #8 0x92ee8e in Perl_runops_debug /root/perl/dump.c​:2486   #9 0x5a9bed in S_run_body /root/perl/perl.c​:2592   #10 0x5a9bed in perl_run /root/perl/perl.c​:2520   #11 0x4362e9 in main /root/perl/perlmain.c​:123   #12 0x7f6fce22cb44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)

previously allocated by thread T0 here​:   #0 0x7f6fcf37e73f in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x5473f)   #1 0x96d04d in Perl_safesysmalloc /root/perl/util.c​:153   #2 0xb888b7 in Perl_sv_grow /root/perl/sv.c​:1603   #3 0xb8e1cc in Perl_sv_2pv_flags /root/perl/sv.c​:3090   #4 0x613b62 in Perl_gv_fetchsv /root/perl/gv.c​:1569   #5 0xc7c54d in S_rv2gv /root/perl/pp.c​:191   #6 0xc7c54d in Perl_pp_rv2gv /root/perl/pp.c​:210   #7 0x92ee8e in Perl_runops_debug /root/perl/dump.c​:2486   #8 0x5a9bed in S_run_body /root/perl/perl.c​:2592   #9 0x5a9bed in perl_run /root/perl/perl.c​:2520   #10 0x4362e9 in main /root/perl/perlmain.c​:123   #11 0x7f6fce22cb44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)

SUMMARY​: AddressSanitizer​: heap-use-after-free /root/perl/sv.c​:4958 Perl_sv_setpv_bufsize

And if I change it ever so slightly\, we get a null pointer dereference instead​:

./perl -e '$$.=*$=0'

ASAN​:SIGSEGV

==21206==ERROR​: AddressSanitizer​: SEGV on unknown address 0x000000000000 (pc 0x000000bcc503 sp 0x7ffd0cde5380 bp 0x7ffd0cde53b0 T0)   #0 0xbcc502 in Perl_sv_setpv_bufsize /root/perl/sv.c​:4959   #1 0xaa2e02 in Perl_pp_concat /root/perl/pp_hot.c​:292   #2 0x92ee8e in Perl_runops_debug /root/perl/dump.c​:2486   #3 0x5a9bed in S_run_body /root/perl/perl.c​:2592   #4 0x5a9bed in perl_run /root/perl/perl.c​:2520   #5 0x4362e9 in main /root/perl/perlmain.c​:123   #6 0x7fe49ff72b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)   #7 0x4372fa (/root/perl/perl+0x4372fa)

AddressSanitizer can not provide additional info. SUMMARY​: AddressSanitizer​: SEGV /root/perl/sv.c​:4959 Perl_sv_setpv_bufsize ==21206==ABORTING

lightsey commented 4 years ago

This example of the same problem was submitted by Dominik Chylinski to the Perl security team:

jd@toucan:~/src/git/lab/perl5 (blead)$ ./perl -e '$0.=do{*0={}.$0[0]^p}if%0=0'
=================================================================
==6532==ERROR: AddressSanitizer: heap-use-after-free on address 0xf5b00910 at pc 0x088381f1 bp 0xffc126a8 sp 0xffc126a0
WRITE of size 1 at 0xf5b00910 thread T0
    #0 0x88381f0 in Perl_sv_setpv_bufsize /home/jd/src/git/lab/perl5/sv.c:4948:17
    #1 0x879c791 in S_do_concat /home/jd/src/git/lab/perl5/pp_hot.c:299:13
    #2 0x879b7e8 in Perl_pp_concat /home/jd/src/git/lab/perl5/pp_hot.c:333:5
    #3 0x87961ff in Perl_runops_standard /home/jd/src/git/lab/perl5/run.c:41:26
    #4 0x825063d in S_run_body /home/jd/src/git/lab/perl5/perl.c:2759:2
    #5 0x824e256 in perl_run /home/jd/src/git/lab/perl5/perl.c:2682:2
    #6 0x8154029 in main /home/jd/src/git/lab/perl5/perlmain.c:127:9
    #7 0xf7bfab40 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x1ab40)
    #8 0x807fd11 in _start (/home/jd/src/git/lab/perl5/perl+0x807fd11)