Blob Blame History Raw
From 439a3bfe85749ea9eca31372daec5705acaa3db1 Mon Sep 17 00:00:00 2001
From: Karl Williamson <khw@cpan.org>
Date: Sat, 24 Aug 2019 19:17:19 -0600
Subject: [PATCH] PATCH: [perl #134325] Heap buffer overflow
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This was the result of trying to continue to parse after realizing that
we were going to have to reparse using long jumps.  This continuing only
happened when we realized we were going to have to reparse in order to
count parentheses anyway, and it was an attempt to save a pass in the
regex compiler, as without doing the continuing we'd restart the parse
to use long jumps from the beginning, and then when finished, would
restart the parse to count the parentheses.

However, in most cases this doesn't help, as when we get towards the end
of the parse (as in the test case in this ticket), we need the long
jump, and will segfault because we don't have it.  So we need the extra
pass anyway.

So this commit restarts the parse as soon as we discover we are going to
need longjumps

Signed-off-by: Petr Písař <ppisar@redhat.com>
---
 regcomp.c  |  8 ++------
 t/re/pat.t | 14 ++++++++++++--
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/regcomp.c b/regcomp.c
index 05dd9a5e7b..abb029f8c0 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -377,12 +377,8 @@ struct RExC_state_t {
 #define REQUIRE_BRANCHJ(flagp, restart_retval)                              \
     STMT_START {                                                            \
                 RExC_use_BRANCHJ = 1;                                       \
-                if (LIKELY(! IN_PARENS_PASS)) {                             \
-                    /* No need to restart the parse immediately if we're    \
-                     * going to reparse anyway to count parens */           \
-                    *flagp |= RESTART_PARSE;                                \
-                    return restart_retval;                                  \
-                }                                                           \
+                *flagp |= RESTART_PARSE;                                    \
+                return restart_retval;                                      \
     } STMT_END
 
 /* Until we have completed the parse, we leave RExC_total_parens at 0 or
diff --git a/t/re/pat.t b/t/re/pat.t
index e54affcd94..6a868f4bcd 100644
--- a/t/re/pat.t
+++ b/t/re/pat.t
@@ -25,7 +25,7 @@ BEGIN {
 skip_all('no re module') unless defined &DynaLoader::boot_DynaLoader;
 skip_all_without_unicode_tables();
 
-plan tests => 863;  # Update this when adding/deleting tests.
+plan tests => 864;  # Update this when adding/deleting tests.
 
 run_tests() unless caller;
 
@@ -33,7 +33,6 @@ run_tests() unless caller;
 # Tests start here.
 #
 sub run_tests {
-
     my $sharp_s = uni_to_native("\xdf");
 
     {
@@ -2105,6 +2104,17 @@ x{0c!}\;\;îçÿ /0f/!F/;îçÿù\Qxÿÿÿÿù`x{0c!};ù\Q
                         eval $z;:, "", {}, 'foo');
     }
 
+    {   # [perl #134325]
+        my $quote="\\Q";
+        my $back="\\\\";
+        my $ff="\xff";
+        my $s = sprintf "/\\1|(|%s)%s%s   /i",
+                        $quote x 8 . $back x 69,
+                        $quote x 5 . $back x 4,
+                        $ff x 48;
+        like(runperl(prog => "$s", stderr => 1), qr/Unmatched \(/);
+   }
+
 } # End of sub run_tests
 
 1;
-- 
2.21.0