Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

heap-buffer-overflow in Perl_sv_vcatpvfn_flags #16087

Closed
p5pRT opened this issue Jul 25, 2017 · 16 comments
Closed

heap-buffer-overflow in Perl_sv_vcatpvfn_flags #16087

p5pRT opened this issue Jul 25, 2017 · 16 comments

Comments

@p5pRT
Copy link

p5pRT commented Jul 25, 2017

Migrated from rt.perl.org#131793 (status was 'resolved')

Searchable as RT131793$

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2017

From gy741.kim@gmail.com

Hi.

I found a heap-buffer-overflow bug in perl.

Please confirm.
Thanks.

Version​: This is perl 5, version 27, subversion 2 (v5.27.2) built for
i686-linux
OS​: Ubuntu 16.04.2 32bit
Steps to reproduce​:
1.Download the PoC files.
2.Compile the source code with ASan.
3.Execute the following command
  : ./perl $PoC

==18930==ERROR​: AddressSanitizer​: heap-buffer-overflow on address
0xb5302bb9 at pc 0x08102b95 bp 0xbf8d9d08 sp 0xbf8d98e0
READ of size 10 at 0xb5302bb9 thread T0
  #0 0x8102b94 in __asan_memcpy (/root/perl5-blead/perl+0x8102b94)
  #1 0x86bab6a in Perl_sv_vcatpvfn_flags /root/perl5-blead/sv.c​:13346​:17
  #2 0x869dc07 in Perl_sv_vsetpvfn /root/perl5-blead/sv.c​:10961​:5
  #3 0x84e2d2a in Perl_vmess /root/perl5-blead/util.c​:1487​:5
  #4 0x84e2d2a in Perl_vcroak /root/perl5-blead/util.c​:1716
  #5 0x84e2d2a in Perl_croak /root/perl5-blead/util.c​:1763
  #6 0x82dc5cc in Perl_yylex /root/perl5-blead/toke.c​:5167​:9
  #7 0x835df10 in Perl_yyparse /root/perl5-blead/perly.c​:340​:34
  #8 0x8232350 in S_parse_body /root/perl5-blead/perl.c​:2401​:9
  #9 0x82285e3 in perl_parse /root/perl5-blead/perl.c​:1719​:2
  #10 0x81494a6 in main /root/perl5-blead/perlmain.c​:121​:18
  #11 0xb747d636 in __libc_start_main
/build/glibc-KM3i_a/glibc-2.23/csu/../csu/libc-start.c​:291
  #12 0x8075847 in _start (/root/perl5-blead/perl+0x8075847)

0xb5302bb9 is located 7 bytes to the left of 120-byte region
[0xb5302bc0,0xb5302c38)
allocated by thread T0 here​:
  #0 0x8119ef4 in realloc (/root/perl5-blead/perl+0x8119ef4)
  #1 0x84e3394 in Perl_safesysrealloc /root/perl5-blead/util.c​:274​:18

SUMMARY​: AddressSanitizer​: heap-buffer-overflow
(/root/perl5-blead/perl+0x8102b94) in __asan_memcpy
Shadow bytes around the buggy address​:
  0x36a60520​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a60530​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a60540​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a60550​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a60560​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x36a60570​: fa fa fa fa fa fa fa[fa]00 00 00 00 00 00 00 00
  0x36a60580​: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
  0x36a60590​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
  0x36a605a0​: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x36a605b0​: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x36a605c0​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Array cookie​: ac
  Intra object redzone​: bb
  ASan internal​: fe
  Left alloca redzone​: ca
  Right alloca redzone​: cb
==18930==ABORTING

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2017

From gy741.kim@gmail.com

PoC_07_25

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2017

From @iabyn

On Mon, Jul 24, 2017 at 09​:23​:22PM -0700, GwanYeong Kim wrote​:

I found a heap-buffer-overflow bug in perl.

Please confirm.
Thanks.

Version​: This is perl 5, version 27, subversion 2 (v5.27.2) built for
i686-linux
OS​: Ubuntu 16.04.2 32bit
Steps to reproduce​:
1.Download the PoC files.
2.Compile the source code with ASan.
3.Execute the following command
: ./perl $PoC

==18930==ERROR​: AddressSanitizer​: heap-buffer-overflow on address
0xb5302bb9 at pc 0x08102b95 bp 0xbf8d9d08 sp 0xbf8d98e0
READ of size 10 at 0xb5302bb9 thread T0
#0 0x8102b94 in __asan_memcpy (/root/perl5-blead/perl+0x8102b94)
#1 0x86bab6a in Perl_sv_vcatpvfn_flags /root/perl5-blead/sv.c​:13346​:17

I've had a quick look, and it's a lexer issue rather than a problem
in _sv_vcatpvfn_flags().

yylex is doing this​:

  Perl_croak(aTHX_ "Unrecognized character %s; marked by <-- HERE after %" UTF8f "<-- HERE near column %d", c,
  UTF8fARG(UTF, (s - d), d),
  (int) len + 1);

where d and s are supposed to delineate part of the src code, but
according to valgrind, d at this point is a wild pointer 7 bytes before
the start of a malloced buffer.

Since it probably requires feeding attacker-controlled src code into the
lexer, I suspect that it isn't a security issue.

I *hate* the lexer. If anyone else wants to fix this, feel free.

--
The Enterprise is involved in a bizarre time-warp experience which is in
some way unconnected with the Late 20th Century.
  -- Things That Never Happen in "Star Trek" #14

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2017

From @tonycoz

On Tue, 25 Jul 2017 03​:44​:14 -0700, davem wrote​:

On Mon, Jul 24, 2017 at 09​:23​:22PM -0700, GwanYeong Kim wrote​:

I found a heap-buffer-overflow bug in perl.

Please confirm.
Thanks.

Version​: This is perl 5, version 27, subversion 2 (v5.27.2) built for
i686-linux
OS​: Ubuntu 16.04.2 32bit
Steps to reproduce​:
1.Download the PoC files.
2.Compile the source code with ASan.
3.Execute the following command
: ./perl $PoC

==18930==ERROR​: AddressSanitizer​: heap-buffer-overflow on address
0xb5302bb9 at pc 0x08102b95 bp 0xbf8d9d08 sp 0xbf8d98e0
READ of size 10 at 0xb5302bb9 thread T0
#0 0x8102b94 in __asan_memcpy (/root/perl5-blead/perl+0x8102b94)
#1 0x86bab6a in Perl_sv_vcatpvfn_flags /root/perl5-
blead/sv.c​:13346​:17

I've had a quick look, and it's a lexer issue rather than a problem
in _sv_vcatpvfn_flags().

yylex is doing this​:

Perl_croak(aTHX_ "Unrecognized character %s; marked by <-- HERE after
%" UTF8f "<-- HERE near column %d", c,
UTF8fARG(UTF, (s - d), d),
(int) len + 1);

where d and s are supposed to delineate part of the src code, but
according to valgrind, d at this point is a wild pointer 7 bytes
before
the start of a malloced buffer.

d gets that value because PL_linestart is after s (aka PL_bufptr at this point), which happens due to a failed attempt to parse a ${identifier} (identifier in this case starts with a "\xd5", supported presumably for ${^Xxxx} reasons.)

Since it probably requires feeding attacker-controlled src code into
the
lexer, I suspect that it isn't a security issue.

Agreed, this ticket is now public.

I *hate* the lexer. If anyone else wants to fix this, feel free.

The attached fixes the symptom, I don't know if scan_ident() should be working harder to avoid advancing PL_linestart when it fails to parse an identifier.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2017

From @tonycoz

0001-perl-131793-sanely-handle-PL_linestart-PL_bufptr.patch
From 77a3e1e5a81d1492a86bac337a93a1247994837d Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 26 Jul 2017 12:04:18 +1000
Subject: (perl #131793) sanely handle PL_linestart > PL_bufptr

In the test case, scan_ident() ends up fetching another line
(updating PL_linestart), and since in this case we don't
successfully parse ${identifier} s (and PL_bufptr) end up being
before PL_linestart.
---
 t/comp/parser_run.t |  9 ++++++++-
 toke.c              | 19 +++++++++++++++----
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/t/comp/parser_run.t b/t/comp/parser_run.t
index e74644d..0fca5b2 100644
--- a/t/comp/parser_run.t
+++ b/t/comp/parser_run.t
@@ -10,7 +10,7 @@ BEGIN {
 }
 
 require './test.pl';
-plan(1);
+plan(2);
 
 # [perl #130814] can reallocate lineptr while looking ahead for
 # "Missing $ on loop variable" diagnostic.
@@ -24,5 +24,12 @@ syntax error at - line 3, near "foreach m0
 Identifier too long at - line 3.
 EXPECT
 
+fresh_perl_is(<<EOS, <<'EXPECT', {}, "linestart before bufptr");
+\${ \xD5eeeeeeeeeeee
+'x
+EOS
+Unrecognized character \xD5; marked by <-- HERE after ${ <-- HERE near column 4 at - line 1.
+EXPECT
+
 __END__
 # ex: set ts=8 sts=4 sw=4 et:
diff --git a/toke.c b/toke.c
index 6aa5f26..1b203cd 100644
--- a/toke.c
+++ b/toke.c
@@ -5158,12 +5158,23 @@ Perl_yylex(pTHX)
         else {
             c = Perl_form(aTHX_ "\\x%02X", (unsigned char)*s);
         }
-        len = UTF ? Perl_utf8_length(aTHX_ (U8 *) PL_linestart, (U8 *) s) : (STRLEN) (s - PL_linestart);
-        if (len > UNRECOGNIZED_PRECEDE_COUNT) {
-            d = UTF ? (char *) utf8_hop_back((U8 *) s, -UNRECOGNIZED_PRECEDE_COUNT, (U8 *)PL_linestart) : s - UNRECOGNIZED_PRECEDE_COUNT;
-        } else {
+
+        if (s >= PL_linestart) {
             d = PL_linestart;
         }
+        else {
+            /* somehow (probably due to a parse failure), PL_linestart has advanced
+             * pass PL_bufptr, get a reasonable beginning of line
+             */
+            d = s;
+            while (d > SvPVX(PL_linestr) && d[-1] && d[-1] != '\n')
+                --d;
+        }
+        len = UTF ? Perl_utf8_length(aTHX_ (U8 *) d, (U8 *) s) : (STRLEN) (s - d);
+        if (len > UNRECOGNIZED_PRECEDE_COUNT) {
+            d = UTF ? (char *) utf8_hop_back((U8 *) s, -UNRECOGNIZED_PRECEDE_COUNT, (U8 *)d) : s - UNRECOGNIZED_PRECEDE_COUNT;
+        }
+
         Perl_croak(aTHX_  "Unrecognized character %s; marked by <-- HERE after %" UTF8f "<-- HERE near column %d", c,
                           UTF8fARG(UTF, (s - d), d),
                          (int) len + 1);
-- 
2.1.4

@p5pRT
Copy link
Author

p5pRT commented Aug 16, 2017

From quangnh89@gmail.com

The attached script triggers a heap-buffer-overflow Perl_sv_vcatpvfn
(sv.c​:13353​:17). This was found with ASAN.

=================================================================
==1380==ERROR​: AddressSanitizer​: heap-buffer-overflow on address
0x602000000fa8 at pc 0x0000004c6337 bp 0x7ffc3713f3f0 sp 0x7ffc3713eba0
READ of size 10 at 0x602000000fa8 thread T0
  #0 0x4c6336 in __asan_memcpy
/scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc​:453​:3
  #1 0xd46667 in Perl_sv_vcatpvfn_flags
/root/fuzz/perl5/perl-new/sv.c​:13353​:17
  #2 0xd16cd2 in Perl_sv_vsetpvfn /root/fuzz/perl5/perl-new/sv.c​:10970​:5
  #3 0xa405dd in Perl_vmess /root/fuzz/perl5/perl-new/util.c​:1487​:5
  #4 0xa45bda in Perl_vcroak /root/fuzz/perl5/perl-new/util.c​:1716​:14
  #5 0xa36cfb in Perl_croak /root/fuzz/perl5/perl-new/util.c​:1763​:5
  #6 0x71f7d6 in Perl_yylex /root/fuzz/perl5/perl-new/toke.c​:5167​:9
  #7 0x80cb4c in Perl_yyparse /root/fuzz/perl5/perl-new/perly.c​:340​:34
  #8 0x631f27 in S_parse_body /root/fuzz/perl5/perl-new/perl.c​:2414​:9
  #9 0x627a05 in perl_parse /root/fuzz/perl5/perl-new/perl.c​:1732​:2
  #10 0x5095f8 in main /root/fuzz/perl5/perl-new/perlmain.c​:121​:18
  #11 0x7f8e7d94782f in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
  #12 0x4359f8 in _start (/root/fuzz/perl5/perl-asan/perl+0x4359f8)

0x602000000fa8 is located 8 bytes to the left of 10-byte region
[0x602000000fb0,0x602000000fba)
allocated by thread T0 here​:
  #0 0x4dc6fc in malloc
/scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc​:66​:3
  #1 0xa3684f in Perl_safesysmalloc
/root/fuzz/perl5/perl-new/util.c​:153​:21
  #2 0xc03d09 in Perl_sv_grow /root/fuzz/perl5/perl-new/sv.c​:1603​:17
  #3 0xc3a983 in Perl_sv_setpvn /root/fuzz/perl5/perl-new/sv.c​:5000​:12
  #4 0xd0d99d in Perl_newSVpvn /root/fuzz/perl5/perl-new/sv.c​:9395​:5
  #5 0x6f658b in Perl_lex_start /root/fuzz/perl5/perl-new/toke.c​:762​:20
  #6 0x631e15 in S_parse_body /root/fuzz/perl5/perl-new/perl.c​:2403​:5
  #7 0x627a05 in perl_parse /root/fuzz/perl5/perl-new/perl.c​:1732​:2
  #8 0x5095f8 in main /root/fuzz/perl5/perl-new/perlmain.c​:121​:18
  #9 0x7f8e7d94782f in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY​: AddressSanitizer​: heap-buffer-overflow
/scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc​:453​:3
in __asan_memcpy
Shadow bytes around the buggy address​:
  0x0c047fff81a0​: fa fa 00 01 fa fa 00 02 fa fa 06 fa fa fa 00 02
  0x0c047fff81b0​: fa fa 05 fa fa fa 00 02 fa fa 00 fa fa fa 00 07
  0x0c047fff81c0​: fa fa 00 01 fa fa 00 05 fa fa 00 00 fa fa 00 02
  0x0c047fff81d0​: fa fa 00 02 fa fa 00 fa fa fa 00 02 fa fa 00 fa
  0x0c047fff81e0​: fa fa 00 00 fa fa 02 fa fa fa 00 04 fa fa 07 fa
=>0x0c047fff81f0​: fa fa 00 04 fa[fa]00 02 fa fa 00 02 fa fa 00 02
  0x0c047fff8200​: fa fa 00 02 fa fa fd fd fa fa fa fa fa fa fa fa
  0x0c047fff8210​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8220​: fa fa fa fa fa fa fa fa 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
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
==1380==ABORTING

toke.c​:5161​:9​:

  len = UTF ? Perl_utf8_length(aTHX_ (U8 *) PL_linestart, (U8 *) s) :
(STRLEN) (s - PL_linestart);
  if (len > UNRECOGNIZED_PRECEDE_COUNT) {
  d = UTF ? (char *) utf8_hop_back((U8 *) s,
-UNRECOGNIZED_PRECEDE_COUNT, (U8 *)PL_linestart) : s -
UNRECOGNIZED_PRECEDE_COUNT;
  } else {
  d = PL_linestart;
  }

if `UTF` is equal to false, the `len` will be `(STRLEN) (s -
PL_linestart)`. Due to `s` is less than `PL_linestart`, the difference is
negative. `len` is huge and a heap-buffer-overflow occurs.

*Best regards,*

*Nguyễn Hồng Quang*

@p5pRT
Copy link
Author

p5pRT commented Aug 16, 2017

From quangnh89@gmail.com

a.pl

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2017

From @tonycoz

On Tue, 15 Aug 2017 19​:44​:10 -0700, quangnh89@​gmail.com wrote​:

The attached script triggers a heap-buffer-overflow Perl_sv_vcatpvfn
(sv.c​:13353​:17). This was found with ASAN.

=================================================================
==1380==ERROR​: AddressSanitizer​: heap-buffer-overflow on address
0x602000000fa8 at pc 0x0000004c6337 bp 0x7ffc3713f3f0 sp
0x7ffc3713eba0
READ of size 10 at 0x602000000fa8 thread T0
#0 0x4c6336 in __asan_memcpy
/scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-
rt/lib/asan/asan_interceptors.cc​:453​:3
#1 0xd46667 in Perl_sv_vcatpvfn_flags
/root/fuzz/perl5/perl-new/sv.c​:13353​:17

This is a duplicate of #131793 and is fixed by my patch there.

As with #131793 this isn't a security issue and is now public.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2017

From @tonycoz

On Wed, 16 Aug 2017 17​:58​:23 -0700, tonyc wrote​:

On Tue, 15 Aug 2017 19​:44​:10 -0700, quangnh89@​gmail.com wrote​:

The attached script triggers a heap-buffer-overflow Perl_sv_vcatpvfn
(sv.c​:13353​:17). This was found with ASAN.

=================================================================
==1380==ERROR​: AddressSanitizer​: heap-buffer-overflow on address
0x602000000fa8 at pc 0x0000004c6337 bp 0x7ffc3713f3f0 sp
0x7ffc3713eba0
READ of size 10 at 0x602000000fa8 thread T0
#0 0x4c6336 in __asan_memcpy
/scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-
rt/lib/asan/asan_interceptors.cc​:453​:3
#1 0xd46667 in Perl_sv_vcatpvfn_flags
/root/fuzz/perl5/perl-new/sv.c​:13353​:17

This is a duplicate of #131793 and is fixed by my patch there.

Which I've now applied to blead as 36000cd.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 22, 2017

From perl@profvince.com

toke.c​:5161​:9​:

     len = UTF ? Perl\_utf8\_length\(aTHX\_ \(U8 \*\) PL\_linestart\, \(U8 \*\) s\) :

(STRLEN) (s - PL_linestart);
if (len > UNRECOGNIZED_PRECEDE_COUNT) {
d = UTF ? (char *) utf8_hop_back((U8 *) s,
-UNRECOGNIZED_PRECEDE_COUNT, (U8 *)PL_linestart) : s -
UNRECOGNIZED_PRECEDE_COUNT;
} else {
d = PL_linestart;
}

This has probably been fixed by commit 36000cd, which was included in
yesterday's release of perl 5.27.3.

Vincent

@p5pRT
Copy link
Author

p5pRT commented Aug 25, 2017

From @tonycoz

On Tue, 22 Aug 2017 05​:42​:52 -0700, perl@​profvince.com wrote​:

toke.c​:5161​:9​:

len = UTF ? Perl_utf8_length(aTHX_ (U8 *) PL_linestart, (U8 *) s) :
(STRLEN) (s - PL_linestart);
if (len > UNRECOGNIZED_PRECEDE_COUNT) {
d = UTF ? (char *) utf8_hop_back((U8 *) s,
-UNRECOGNIZED_PRECEDE_COUNT, (U8 *)PL_linestart) : s -
UNRECOGNIZED_PRECEDE_COUNT;
} else {
d = PL_linestart;
}

This has probably been fixed by commit 36000cd, which was included
in
yesterday's release of perl 5.27.3.

Yes, I forgot to close it.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 25, 2017

@tonycoz - Status changed from 'open' to 'pending release'

@p5pRT
Copy link
Author

p5pRT commented Jun 23, 2018

From @khwilliamson

Thank you for filing this report. You have helped make Perl better.

With the release yesterday of Perl 5.28.0, this and 185 other issues have been
resolved.

Perl 5.28.0 may be downloaded via​:
https://metacpan.org/release/XSAWYERX/perl-5.28.0

If you find that the problem persists, feel free to reopen this ticket.

@p5pRT p5pRT closed this as completed Jun 23, 2018
@p5pRT
Copy link
Author

p5pRT commented Jun 23, 2018

@khwilliamson - Status changed from 'pending release' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant