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

regcomp: heap-buffer-overflow read utf8::= (perl-5.30.0) #17016

Closed
p5pRT opened this issue May 24, 2019 · 8 comments
Closed

regcomp: heap-buffer-overflow read utf8::= (perl-5.30.0) #17016

p5pRT opened this issue May 24, 2019 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented May 24, 2019

Migrated from rt.perl.org#134133 (status was 'pending release')

Searchable as RT134133$

@p5pRT
Copy link
Author

p5pRT commented May 24, 2019

From @Etsukata

PoC

```

[eiichi@​x1 ~]$ valgrind perl5/perlbrew/perls/perl-5.30.0/bin/perl -e
'qr/\p{utf8​::=}/'                            
==12715== Memcheck, a memory error detector
==12715== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12715== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==12715== Command​: perl5/perlbrew/perls/perl-5.30.0/bin/perl -e
qr/\\p{utf8​::=}/
==12715==
==12715== Invalid read of size 2
==12715==    at 0x488036​: Perl_parse_uniprop_string (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x48ED99​: S_regclass (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x492095​: S_regpiece (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x495E54​: S_regbranch (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x4963A7​: S_reg (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x49AE68​: Perl_re_op_compile (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x43928A​: Perl_pmruntime (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x46FEBD​: Perl_yyparse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x444AAC​: perl_parse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x42023F​: main (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==  Address 0x51c8026 is 6 bytes inside a block of size 7 alloc'd
==12715==    at 0x483880B​: malloc (vg_replace_malloc.c​:309)
==12715==    by 0x4A70D2​: Perl_safesysmalloc (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x487E98​: Perl_parse_uniprop_string (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x48ED99​: S_regclass (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x492095​: S_regpiece (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x495E54​: S_regbranch (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x4963A7​: S_reg (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x49AE68​: Perl_re_op_compile (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x43928A​: Perl_pmruntime (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x46FEBD​: Perl_yyparse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x444AAC​: perl_parse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x42023F​: main (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==
Illegal user-defined property name "utf8​::=" in regex; marked by <--
HERE in m/\p{utf8​::=} <-- HERE / at -e line 1.
==12715==
==12715== HEAP SUMMARY​:
==12715==     in use at exit​: 153,845 bytes in 675 blocks
==12715==   total heap usage​: 890 allocs, 215 frees, 190,688 bytes allocated
==12715==
==12715== LEAK SUMMARY​:
==12715==    definitely lost​: 0 bytes in 0 blocks
==12715==    indirectly lost​: 0 bytes in 0 blocks
==12715==      possibly lost​: 0 bytes in 0 blocks
==12715==    still reachable​: 153,845 bytes in 675 blocks
==12715==         suppressed​: 0 bytes in 0 blocks
==12715== Rerun with --leak-check=full to see details of leaked memory
==12715==
==12715== For lists of detected and suppressed errors, rerun with​: -s
==12715== ERROR SUMMARY​: 1 errors from 1 contexts (suppressed​: 0 from 0)

```

@p5pRT
Copy link
Author

p5pRT commented Jun 27, 2019

From @khwilliamson

Resending the below as it did not get attached to the ticket.

On 5/23/19 11​:52 PM, Eiichi Tsukata (via RT) wrote​:

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

PoC

```

[eiichi@​x1 ~]$ valgrind perl5/perlbrew/perls/perl-5.30.0/bin/perl -e
'qr/\p{utf8​::=}/'
==12715== Memcheck, a memory error detector
==12715== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12715== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==12715== Command​: perl5/perlbrew/perls/perl-5.30.0/bin/perl -e
qr/\\p{utf8​::=}/
==12715==
==12715== Invalid read of size 2
==12715==    at 0x488036​: Perl_parse_uniprop_string (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x48ED99​: S_regclass (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x492095​: S_regpiece (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x495E54​: S_regbranch (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x4963A7​: S_reg (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x49AE68​: Perl_re_op_compile (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x43928A​: Perl_pmruntime (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x46FEBD​: Perl_yyparse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x444AAC​: perl_parse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x42023F​: main (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==  Address 0x51c8026 is 6 bytes inside a block of size 7 alloc'd
==12715==    at 0x483880B​: malloc (vg_replace_malloc.c​:309)
==12715==    by 0x4A70D2​: Perl_safesysmalloc (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x487E98​: Perl_parse_uniprop_string (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x48ED99​: S_regclass (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x492095​: S_regpiece (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x495E54​: S_regbranch (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x4963A7​: S_reg (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x49AE68​: Perl_re_op_compile (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x43928A​: Perl_pmruntime (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x46FEBD​: Perl_yyparse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x444AAC​: perl_parse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x42023F​: main (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==
Illegal user-defined property name "utf8​::=" in regex; marked by <--
HERE in m/\p{utf8​::=} <-- HERE / at -e line 1.
==12715==
==12715== HEAP SUMMARY​:
==12715==     in use at exit​: 153,845 bytes in 675 blocks
==12715==   total heap usage​: 890 allocs, 215 frees, 190,688 bytes allocated
==12715==
==12715== LEAK SUMMARY​:
==12715==    definitely lost​: 0 bytes in 0 blocks
==12715==    indirectly lost​: 0 bytes in 0 blocks
==12715==      possibly lost​: 0 bytes in 0 blocks
==12715==    still reachable​: 153,845 bytes in 675 blocks
==12715==         suppressed​: 0 bytes in 0 blocks
==12715== Rerun with --leak-check=full to see details of leaked memory
==12715==
==12715== For lists of detected and suppressed errors, rerun with​: -s
==12715== ERROR SUMMARY​: 1 errors from 1 contexts (suppressed​: 0 from 0)

```

This is fixed by the attached file

@p5pRT
Copy link
Author

p5pRT commented Jun 27, 2019

From @khwilliamson

0001-PATCH-perl-134133-read-beyond-end-of-buffer.patch
>From ee6f83153ea3eca198f39b966057339418840a7f Mon Sep 17 00:00:00 2001
From: Karl Williamson <khw@cpan.org>
Date: Fri, 24 May 2019 09:01:46 -0600
Subject: [PATCH 1/2] PATCH: [perl #134133] read beyond end of buffer

The code was using the wrong limit variable.
---
 regcomp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/regcomp.c b/regcomp.c
index 9bd6dd3739..51e286bc20 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -22857,7 +22857,7 @@ Perl_parse_uniprop_string(pTHX_
         /* Certain properties whose values are numeric need special handling.
          * They may optionally be prefixed by 'is'.  Ignore that prefix for the
          * purposes of checking if this is one of those properties */
-        if (memBEGINPs(lookup_name, name_len, "is")) {
+        if (memBEGINPs(lookup_name, j, "is")) {
             lookup_offset = 2;
         }
 
-- 
2.17.1


@p5pRT
Copy link
Author

p5pRT commented Jun 27, 2019

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

@p5pRT
Copy link
Author

p5pRT commented Jun 27, 2019

From @khwilliamson

On 6/27/19 12​:26 PM, Karl Williamson wrote​:

Resending the below as it did not get attached to the ticket.

On 5/23/19 11​:52 PM, Eiichi Tsukata (via RT) wrote​:

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

PoC

```

[eiichi@​x1 ~]$ valgrind perl5/perlbrew/perls/perl-5.30.0/bin/perl -e
'qr/\p{utf8​::=}/'
==12715== Memcheck, a memory error detector
==12715== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12715== Using Valgrind-3.15.0 and LibVEX; rerun with -h for
copyright info
==12715== Command​: perl5/perlbrew/perls/perl-5.30.0/bin/perl -e
qr/\\p{utf8​::=}/
==12715==
==12715== Invalid read of size 2
==12715==    at 0x488036​: Perl_parse_uniprop_string (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x48ED99​: S_regclass (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x492095​: S_regpiece (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x495E54​: S_regbranch (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x4963A7​: S_reg (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x49AE68​: Perl_re_op_compile (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x43928A​: Perl_pmruntime (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x46FEBD​: Perl_yyparse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x444AAC​: perl_parse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x42023F​: main (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==  Address 0x51c8026 is 6 bytes inside a block of size 7 alloc'd
==12715==    at 0x483880B​: malloc (vg_replace_malloc.c​:309)
==12715==    by 0x4A70D2​: Perl_safesysmalloc (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x487E98​: Perl_parse_uniprop_string (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x48ED99​: S_regclass (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x492095​: S_regpiece (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x495E54​: S_regbranch (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x4963A7​: S_reg (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x49AE68​: Perl_re_op_compile (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x43928A​: Perl_pmruntime (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x46FEBD​: Perl_yyparse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x444AAC​: perl_parse (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==    by 0x42023F​: main (in
/home/eiichi/perl5/perlbrew/perls/perl-5.30.0/bin/perl)
==12715==
Illegal user-defined property name "utf8​::=" in regex; marked by <--
HERE in m/\p{utf8​::=} <-- HERE / at -e line 1.
==12715==
==12715== HEAP SUMMARY​:
==12715==     in use at exit​: 153,845 bytes in 675 blocks
==12715==   total heap usage​: 890 allocs, 215 frees, 190,688 bytes
allocated
==12715==
==12715== LEAK SUMMARY​:
==12715==    definitely lost​: 0 bytes in 0 blocks
==12715==    indirectly lost​: 0 bytes in 0 blocks
==12715==      possibly lost​: 0 bytes in 0 blocks
==12715==    still reachable​: 153,845 bytes in 675 blocks
==12715==         suppressed​: 0 bytes in 0 blocks
==12715== Rerun with --leak-check=full to see details of leaked memory
==12715==
==12715== For lists of detected and suppressed errors, rerun with​: -s
==12715== ERROR SUMMARY​: 1 errors from 1 contexts (suppressed​: 0 from 0)

```

This is fixed by the attached file

I'm trying to figure out if this is a real potential attack vector.
This is malloc'd space at the top of the function. It's mallocd to
name_len bytes, but isn't necessarily initialized to the full amount.

I don't understand how this actually is generating this valgrind error.
The underlying macro expands to a memcmp of name_len bytes, which
shouldn't go off the end of the mallocd space. But it could certainly
read data that didn't get initialized.

On #irc, people said this kind of error only comes from reading an
invalid address.

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2019

From @hvds

On Thu, 27 Jun 2019 12​:31​:30 -0700, public@​khwilliamson.com wrote​:

I'm trying to figure out if this is a real potential attack vector.
This is malloc'd space at the top of the function. It's mallocd to
name_len bytes, but isn't necessarily initialized to the full amount.

I don't understand how this actually is generating this valgrind error.
The underlying macro expands to a memcmp of name_len bytes, which
shouldn't go off the end of the mallocd space. But it could certainly
read data that didn't get initialized.

I think lookup_name has been moved since it was malloced, probably by​:
  lookup_name += STRLENs("utf8​::");

.. which would explain valgrind's diagnosis​:
  Address 0x51c8026 is 6 bytes inside a block of size 7

In any case, reading (but not leaking information about) some bytes of malloc bookkeeping doesn't sound to me like much of an attack vector. I think worst case is that we get unlucky with the bookkeeping bytes causing the memBEGINPs to return TRUE; I'd expect that to be only a bug though, not a security issue.

Briefly looking at other uses of name_len, this one might also be dodgy​:

  /* If the original input began with 'In' or 'Is', it could be a subroutine
  * call to a user-defined property instead of a Unicode property name. */
  if ( non_pkg_begin + name_len > 2

Shouldn't that be "if (name_len - non_pkg_begin > 2"?

Hugo

@p5pRT
Copy link
Author

p5pRT commented Aug 22, 2019

From @khwilliamson

On 7/5/19 7​:23 AM, Hugo van der Sanden via RT wrote​:

On Thu, 27 Jun 2019 12​:31​:30 -0700, public@​khwilliamson.com wrote​:

I'm trying to figure out if this is a real potential attack vector.
This is malloc'd space at the top of the function. It's mallocd to
name_len bytes, but isn't necessarily initialized to the full amount.

I don't understand how this actually is generating this valgrind error.
The underlying macro expands to a memcmp of name_len bytes, which
shouldn't go off the end of the mallocd space. But it could certainly
read data that didn't get initialized.

I think lookup_name has been moved since it was malloced, probably by​:
lookup_name += STRLENs("utf8​::");

.. which would explain valgrind's diagnosis​:
Address 0x51c8026 is 6 bytes inside a block of size 7

In any case, reading (but not leaking information about) some bytes of malloc bookkeeping doesn't sound to me like much of an attack vector. I think worst case is that we get unlucky with the bookkeeping bytes causing the memBEGINPs to return TRUE; I'd expect that to be only a bug though, not a security issue.

Briefly looking at other uses of name_len, this one might also be dodgy​:

 /\* If the original input began with 'In' or 'Is'\, it could be a subroutine
  \* call to a user\-defined property instead of a Unicode property name\. \*/
 if \(    non\_pkg\_begin \+ name\_len > 2

Shouldn't that be "if (name_len - non_pkg_begin > 2"?

Yes it should, thank you. Fixed in 8d3e023

Since no one has disagreed with Hugo's assessment that this isn't a
security issue, I have pushed a fix in
c6f37d6

and moved this to the public queue, marking it pending release.

Is a test needed, since this only surfaces under valgrind?

@p5pRT
Copy link
Author

p5pRT commented Aug 22, 2019

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

@p5pRT p5pRT closed this as completed Aug 22, 2019
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