Perl / perl5

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

AddressSanitizer: heap-buffer-overflow in S_ckwarn_common #15908

Open p5pRT opened 7 years ago

p5pRT commented 7 years ago

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

Searchable as RT130916$

p5pRT commented 7 years ago

From mtowalski@pentest.net.pl

Hello\,

I've attached the poc and the asan log. Tested on git version of perl.

Configure options​:

“./Configure -des -Dusedevel -DDEBUGGING -Dcc=clang -Doptimize=-O2 -Accflags="-fsanitize=address -fsanitize-coverage=edge" -Aldflags="-fsanitize=address -fsanitize-coverage=edge" -Alddlflags=-shared"

Information about configuration​:

Distributor ID​: Ubuntu Description​: Ubuntu 16.10 Release​: 16.10 Codename​: yakkety Arch​: x86_64

Best Regards\, Marcin T.

p5pRT commented 7 years ago

From mtowalski@pentest.net.pl

heap-buffer-overflow-9cb-ce6-ce6

p5pRT commented 7 years ago

From mtowalski@pentest.net.pl

/usr/bin/llvm-symbolizer perl​: warning​: Setting locale failed. perl​: warning​: Please check that your locale settings​:   LANGUAGE = (unset)\,   LC_ALL = (unset)\,   LC_CTYPE = "UTF-8"\,   LANG = "en_US.UTF-8"   are supported and installed on your system. perl​: warning​: Falling back to a fallback locale ("en_US.UTF-8").

==11610==ERROR​: AddressSanitizer​: heap-buffer-overflow on address 0x60200000113f at pc 0x00000080b9cc bp 0x7fff324f3110 sp 0x7fff324f3108 READ of size 1 at 0x60200000113f thread T0   #0 0x80b9cb in S_ckwarn_common /home/mtowalski/Fuzzing/Programs/perl-git/util.c​:2027​:6   #1 0x655ce6 in S_pending_ident /home/mtowalski/Fuzzing/Programs/perl-git/toke.c​:8971​:9   #2 0x655ce6 in Perl_yylex /home/mtowalski/Fuzzing/Programs/perl-git/toke.c​:4811   #3 0x6e834d in Perl_yyparse /home/mtowalski/Fuzzing/Programs/perl-git/perly.c​:340​:34   #4 0x5e3dc6 in S_parse_body /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:2377​:9   #5 0x5db300 in perl_parse /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:1692​:2   #6 0x5242ce in main /home/mtowalski/Fuzzing/Programs/perl-git/perlmain.c​:121​:18   #7 0x7f209dc513f0 in __libc_start_main /build/glibc-jxM2Ev/glibc-2.24/csu/../csu/libc-start.c​:291   #8 0x4356f9 in _start (/home/mtowalski/Fuzzing/Programs/perl-git/perl+0x4356f9)

0x60200000113f is located 6 bytes to the right of 9-byte region [0x602000001130\,0x602000001139) allocated by thread T0 here​:   #0 0x4eb0a8 in malloc (/home/mtowalski/Fuzzing/Programs/perl-git/perl+0x4eb0a8)   #1 0x5548ac in Perl_block_start /home/mtowalski/Fuzzing/Programs/perl-git/op.c​:4106​:33   #2 0x5e3dc6 in S_parse_body /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:2377​:9   #3 0x5db300 in perl_parse /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:1692​:2   #4 0x5242ce in main /home/mtowalski/Fuzzing/Programs/perl-git/perlmain.c​:121​:18   #5 0x7f209dc513f0 in __libc_start_main /build/glibc-jxM2Ev/glibc-2.24/csu/../csu/libc-start.c​:291

SUMMARY​: AddressSanitizer​: heap-buffer-overflow /home/mtowalski/Fuzzing/Programs/perl-git/util.c​:2027​:6 in S_ckwarn_common Shadow bytes around the buggy address​:   0x0c047fff81d0​: fa fa 00 01 fa fa 00 01 fa fa 00 00 fa fa 00 00   0x0c047fff81e0​: fa fa 00 02 fa fa 07 fa fa fa 02 fa fa fa 00 04   0x0c047fff81f0​: fa fa fd fd fa fa fd fd fa fa fd fd fa fa 00 02   0x0c047fff8200​: fa fa fd fa fa fa fd fd fa fa fd fd fa fa fd fd   0x0c047fff8210​: fa fa 00 02 fa fa fd fd fa fa 00 05 fa fa 00 02 =>0x0c047fff8220​: fa fa 00 02 fa fa 00[01]fa fa fa fa fa fa fa fa   0x0c047fff8230​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8240​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8250​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8260​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8270​: 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   Freed heap region​: fd   Stack left redzone​: f1   Stack mid redzone​: f2   Stack right redzone​: f3   Stack after return​: f5   Stack use after scope​: f8   Global redzone​: f9   Global init order​: f6   Poisoned by user​: f7   Container overflow​: fc   Array cookie​: ac   Intra object redzone​: bb   ASan internal​: fe   Left alloca redzone​: ca   Right alloca redzone​: cb ==11610==ABORTING

p5pRT commented 7 years ago

From @khwilliamson

On 03/04/2017 06​:03 AM\, (via RT) wrote​:

# New Ticket Created by # Please include the string​: [perl #130916] # in the subject line of all future correspondence about this issue. # \<URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=130916 >

Hello\,

I've attached the poc and the asan log. Tested on git version of perl.

Configure options​:

“./Configure -des -Dusedevel -DDEBUGGING -Dcc=clang -Doptimize=-O2 -Accflags="-fsanitize=address -fsanitize-coverage=edge" -Aldflags="-fsanitize=address -fsanitize-coverage=edge" -Alddlflags=-shared"

Information about configuration​:

Distributor ID​: Ubuntu Description​: Ubuntu 16.10 Release​: 16.10 Codename​: yakkety Arch​: x86_64

Best Regards\, Marcin T.

Hello\,

I've attached the poc and the asan log. Tested on git version of perl.

Configure options​:

“./Configure -des -Dusedevel -DDEBUGGING -Dcc=clang -Doptimize=-O2 -Accflags="-fsanitize=address -fsanitize-coverage=edge" -Aldflags="-fsanitize=address -fsanitize-coverage=edge" -Alddlflags=-shared"

Information about configuration​:

Distributor ID​: Ubuntu Description​: Ubuntu 16.10 Release​: 16.10 Codename​: yakkety Arch​: x86_64

Best Regards\, Marcin T.

All these are weird around the locale setting. Could you run this with the environment variable PERL_DEBUG_LOCALE_INIT=1 and send the output.

p5pRT commented 7 years ago

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

p5pRT commented 7 years ago

From mtowalski@pentest.net.pl

Hello\,

Here is the output from the command - "PERL_DEBUG_LOCALE_INIT=1 ./perl perl-heap-buffer-overflow-9cb-ce6-ce6”

Best Regards\, Marcin T.

On 5 Mar 2017\, at 05​:51\, karl williamson via RT \perl5\-security\-report@&#8203;perl\.org wrote​:

On 03/04/2017 06​:03 AM\, (via RT) wrote​:

# New Ticket Created by # Please include the string​: [perl #130916] # in the subject line of all future correspondence about this issue. # \<URL​: https​://rt.perl.org/Ticket/Display.html?id=130916 \https://rt-archive.perl.org/perl5/Ticket/Display.html?id=130916 >

Hello\,

I've attached the poc and the asan log. Tested on git version of perl.

Configure options​:

“./Configure -des -Dusedevel -DDEBUGGING -Dcc=clang -Doptimize=-O2 -Accflags="-fsanitize=address -fsanitize-coverage=edge" -Aldflags="-fsanitize=address -fsanitize-coverage=edge" -Alddlflags=-shared"

Information about configuration​:

Distributor ID​: Ubuntu Description​: Ubuntu 16.10 Release​: 16.10 Codename​: yakkety Arch​: x86_64

Best Regards\, Marcin T.

Hello\,

I've attached the poc and the asan log. Tested on git version of perl.

Configure options​:

“./Configure -des -Dusedevel -DDEBUGGING -Dcc=clang -Doptimize=-O2 -Accflags="-fsanitize=address -fsanitize-coverage=edge" -Aldflags="-fsanitize=address -fsanitize-coverage=edge" -Alddlflags=-shared"

Information about configuration​:

Distributor ID​: Ubuntu Description​: Ubuntu 16.10 Release​: 16.10 Codename​: yakkety Arch​: x86_64

Best Regards\, Marcin T.

All these are weird around the locale setting. Could you run this with the environment variable PERL_DEBUG_LOCALE_INIT=1 and send the output.

p5pRT commented 7 years ago

From mtowalski@pentest.net.pl

locale.c​:1105​: setlocale(LC_ALL\, "") returned NULL perl​: warning​: Setting locale failed. perl​: warning​: Please check that your locale settings​:   LANGUAGE = (unset)\,   LC_ALL = (unset)\,   LC_CTYPE = "UTF-8"\,   LANG = "en_US.UTF-8"   are supported and installed on your system. locale.c​:1105​: setlocale(LC_ALL\, "en_US.UTF-8") returned "en_US.UTF-8" locale.c​:1125​: setlocale(LC_CTYPE\, NULL) returned "en_US.UTF-8" locale.c​:1134​: setlocale(LC_COLLATE\, NULL) returned "en_US.UTF-8" locale.c​:1143​: setlocale(LC_NUMERIC\, NULL) returned "en_US.UTF-8" locale.c​:1151​: setlocale(LC_MESSAGES\, NULL) returned "en_US.UTF-8" locale.c​:1157​: setlocale(LC_MONETARY\, NULL) returned "en_US.UTF-8" perl​: warning​: Falling back to a fallback locale ("en_US.UTF-8"). _mem_collxfrm[1]​: returning 80 for locale 'en_US.UTF-8'\, string='ABCDEFGHIJKLMnopqrstuvwxyz' Its xfrm is​: 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 01 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 01 10 10 10 10 10 10 10 10 10 10 10 10 10 09 09 09 09 09 09 09 09 09 09 09 09 09 _mem_collxfrm[1]​: returning 77 for locale 'en_US.UTF-8'\, string='BCDEFGHIJKLMnopqrstuvwxyz' Its xfrm is​: 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 01 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 01 10 10 10 10 10 10 10 10 10 10 10 10 09 09 09 09 09 09 09 09 09 09 09 09 09 locale.c​:689​: ?UTF-8 locale=1; x_len_shorter=77\, x_len_longer=80\, collate multipler=3\, collate base=3 Locale radix is 'NULL'\, ?UTF-8=0 Underlying LC_NUMERIC locale now is C Locale radix is 'NULL'\, ?UTF-8=0 Unquoted string "pected" may clash with future reserved word at perl-heap-buffer-overflow-9cb-ce6-ce6 line 21. Useless use of a constant ("pected") in void context at perl-heap-buffer-overflow-9cb-ce6-ce6 line 21.

==12872==ERROR​: AddressSanitizer​: heap-buffer-overflow on address 0x6020000033ff at pc 0x00000080b9cc bp 0x7ffe22920dd0 sp 0x7ffe22920dc8 READ of size 1 at 0x6020000033ff thread T0   #0 0x80b9cb in S_ckwarn_common /home/mtowalski/Fuzzing/Programs/perl-git/util.c​:2027​:6   #1 0x655ce6 in S_pending_ident /home/mtowalski/Fuzzing/Programs/perl-git/toke.c​:8971​:9   #2 0x655ce6 in Perl_yylex /home/mtowalski/Fuzzing/Programs/perl-git/toke.c​:4811   #3 0x6e834d in Perl_yyparse /home/mtowalski/Fuzzing/Programs/perl-git/perly.c​:340​:34   #4 0x5e3dc6 in S_parse_body /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:2377​:9   #5 0x5db300 in perl_parse /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:1692​:2   #6 0x5242ce in main /home/mtowalski/Fuzzing/Programs/perl-git/perlmain.c​:121​:18   #7 0x7f368e7173f0 in __libc_start_main /build/glibc-jxM2Ev/glibc-2.24/csu/../csu/libc-start.c​:291   #8 0x4356f9 in _start (/home/mtowalski/Fuzzing/Programs/perl-git/perl+0x4356f9)

0x6020000033ff is located 6 bytes to the right of 9-byte region [0x6020000033f0\,0x6020000033f9) allocated by thread T0 here​:   #0 0x4eb0a8 in malloc (/home/mtowalski/Fuzzing/Programs/perl-git/perl+0x4eb0a8)   #1 0x5548ac in Perl_block_start /home/mtowalski/Fuzzing/Programs/perl-git/op.c​:4106​:33   #2 0x5e3dc6 in S_parse_body /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:2377​:9   #3 0x5db300 in perl_parse /home/mtowalski/Fuzzing/Programs/perl-git/perl.c​:1692​:2   #4 0x5242ce in main /home/mtowalski/Fuzzing/Programs/perl-git/perlmain.c​:121​:18   #5 0x7f368e7173f0 in __libc_start_main /build/glibc-jxM2Ev/glibc-2.24/csu/../csu/libc-start.c​:291

SUMMARY​: AddressSanitizer​: heap-buffer-overflow /home/mtowalski/Fuzzing/Programs/perl-git/util.c​:2027​:6 in S_ckwarn_common Shadow bytes around the buggy address​:   0x0c047fff8620​: fa fa fd fa fa fa 00 02 fa fa fd fd fa fa fd fd   0x0c047fff8630​: fa fa fd fd fa fa 00 03 fa fa fd fd fa fa 00 02   0x0c047fff8640​: fa fa fd fd fa fa fd fa fa fa 00 00 fa fa fd fd   0x0c047fff8650​: fa fa fd fd fa fa 00 02 fa fa fd fa fa fa fd fd   0x0c047fff8660​: fa fa fd fd fa fa fd fd fa fa 00 02 fa fa fd fd =>0x0c047fff8670​: fa fa 00 05 fa fa fd fd fa fa 00 02 fa fa 00[01]   0x0c047fff8680​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8690​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff86a0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff86b0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff86c0​: 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   Freed heap region​: fd   Stack left redzone​: f1   Stack mid redzone​: f2   Stack right redzone​: f3   Stack after return​: f5   Stack use after scope​: f8   Global redzone​: f9   Global init order​: f6   Poisoned by user​: f7   Container overflow​: fc   Array cookie​: ac   Intra object redzone​: bb   ASan internal​: fe   Left alloca redzone​: ca   Right alloca redzone​: cb ==12872==ABORTING

p5pRT commented 7 years ago

From @iabyn

On Sat\, Mar 04\, 2017 at 05​:03​:32AM -0800\, via RT wrote​:

BEGIN{$x=${;};${^WARNING_BITS}="x"}{$

This​:

  ${^WARNING_BITS}="x"

sets\, in Perl_magic_set()\, PL_curcop->cop_warnings to point to a malloced U8 buffer of size 0x19\, containing​:   * an 8 byte length field (set to the value 1)\,   * followed by the one byte 'x'\,   * followed by 16 bytes of padding

Later\, Perl_block_start() does​:

  PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);

but DUP_WARNINGS() only copies the actual length\, so the new buffer is malloced with size 0x9\, containing the length and just the 'x'\, with no padding.

Then later\, S_ckwarn_common() checks which warnings are enabled\, and assumes the buffer is big enough to index into to check for any enabled warning bit. This triggers the ASAN error.

I don't understand the warning bits code well enough (and especially the meaning of the length word\, and why its sometimes treated as a STRLEN*) to know whether​:

a) Perl_magic_set should have set the length to 0x11 rather than 0x1; or b) DUP_WARNINGS should have allocated a larger buffer even though   the length field has the value 0x1; or c) whether S_ckwarn_common() and other code which accesses the warnings   array should honour the length field and not check for bits beyond the   end of it.

Of the three\, (c) seems the least desirable as it could have the biggest runtime overhead.

In any event\, I don't think its a security issue\, because it will only occur if perl-level code deliberately sets ${^WARNING_BITS} to a short string\, which normal code is exceedingly unlikely to do\, and the read beyond the end of the buffer then only affects which warnings are interpreted as being enabled.

So I propose moving this to the public queue.

-- The Enterprise successfully ferries an alien VIP from one place to another without serious incident.   -- Things That Never Happen in "Star Trek" #7

p5pRT commented 7 years ago

From @iabyn

On Fri\, Mar 17\, 2017 at 04​:12​:23PM +0000\, Dave Mitchell wrote​:

On Sat\, Mar 04\, 2017 at 05​:03​:32AM -0800\, via RT wrote​:

BEGIN{$x=${;};${^WARNING_BITS}="x"}{$

This​:

$\{^WARNING\_BITS\}="x"

sets\, in Perl_magic_set()\, PL_curcop->cop_warnings to point to a malloced U8 buffer of size 0x19\, containing​: * an 8 byte length field (set to the value 1)\, * followed by the one byte 'x'\, * followed by 16 bytes of padding

Later\, Perl_block_start() does​:

PL\_compiling\.cop\_warnings = DUP\_WARNINGS\(PL\_compiling\.cop\_warnings\);

but DUP_WARNINGS() only copies the actual length\, so the new buffer is malloced with size 0x9\, containing the length and just the 'x'\, with no padding.

Then later\, S_ckwarn_common() checks which warnings are enabled\, and assumes the buffer is big enough to index into to check for any enabled warning bit. This triggers the ASAN error.

I don't understand the warning bits code well enough (and especially the meaning of the length word\, and why its sometimes treated as a STRLEN*) to know whether​:

a) Perl_magic_set should have set the length to 0x11 rather than 0x1; or b) DUP_WARNINGS should have allocated a larger buffer even though the length field has the value 0x1; or c) whether S_ckwarn_common() and other code which accesses the warnings array should honour the length field and not check for bits beyond the end of it.

Of the three\, (c) seems the least desirable as it could have the biggest runtime overhead.

In any event\, I don't think its a security issue\, because it will only occur if perl-level code deliberately sets ${^WARNING_BITS} to a short string\, which normal code is exceedingly unlikely to do\, and the read beyond the end of the buffer then only affects which warnings are interpreted as being enabled.

So I propose moving this to the public queue.

Which I've now done.

-- print+qq&$}$"$/$s$\,$a$d$g$s$@​$.$q$\,$​:$.$q$^$\,$@​$a$~$;$.$q$m&if+map{m\,^\d{0\\,}\,\,${$​::{$'}}=chr($"+=$&||1)}q&10m22\,42}6​:17a2~2.3@​3;^2dg3q/s"&=~m*\d\*.*g