From b0254cedee2517d2705070839549189cf9f72db4 Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Fri, 16 Jun 2017 15:46:19 +0100 Subject: [PATCH] don't call Perl_fbm_instr() with negative length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ported to 5.24.1: commit bb152a4b442f7718fd37d32cc558be675e8ae1ae Author: David Mitchell Date: Fri Jun 16 15:46:19 2017 +0100 don't call Perl_fbm_instr() with negative length RT #131575 re_intuit_start() could calculate a maximum end position less than the current start position. This used to get rejected by fbm_intr(), until v5.23.3-110-g147f21b, which made fbm_intr() faster and removed unnecessary checks. This commits fixes re_intuit_start(), and adds an assert to fbm_intr(). Signed-off-by: Petr Písař --- regexec.c | 17 +++++++++++------ t/re/pat.t | 13 ++++++++++++- util.c | 2 ++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/regexec.c b/regexec.c index f1a52ab..3080880 100644 --- a/regexec.c +++ b/regexec.c @@ -127,13 +127,16 @@ static const char* const non_utf8_target_but_utf8_required (U8*)(off >= 0 ? reginfo->strend : reginfo->strbeg)) \ : (U8*)(pos + off)) -#define HOPBACKc(pos, off) \ - (char*)(reginfo->is_utf8_target \ - ? reghopmaybe3((U8*)pos, (SSize_t)0-off, (U8*)(reginfo->strbeg)) \ - : (pos - off >= reginfo->strbeg) \ - ? (U8*)pos - off \ +/* like HOPMAYBE3 but backwards. lim must be +ve. Returns NULL on overshoot */ +#define HOPBACK3(pos, off, lim) \ + (reginfo->is_utf8_target \ + ? reghopmaybe3((U8*)pos, (SSize_t)0-off, (U8*)(lim)) \ + : (pos - off >= lim) \ + ? (U8*)pos - off \ : NULL) +#define HOPBACKc(pos, off) ((char*)HOPBACK3(pos, off, reginfo->strbeg)) + #define HOP3(pos,off,lim) (reginfo->is_utf8_target ? reghop3((U8*)(pos), off, (U8*)(lim)) : (U8*)(pos + off)) #define HOP3c(pos,off,lim) ((char*)HOP3(pos,off,lim)) @@ -871,7 +874,9 @@ Perl_re_intuit_start(pTHX_ (IV)prog->check_end_shift); }); - end_point = HOP3(strend, -end_shift, strbeg); + end_point = HOPBACK3(strend, end_shift, rx_origin); + if (!end_point) + goto fail_finish; start_point = HOPMAYBE3(rx_origin, start_shift, end_point); if (!start_point) goto fail_finish; diff --git a/t/re/pat.t b/t/re/pat.t index 50529b8..007f11d 100644 --- a/t/re/pat.t +++ b/t/re/pat.t @@ -23,7 +23,7 @@ BEGIN { skip_all_without_unicode_tables(); } -plan tests => 793; # Update this when adding/deleting tests. +plan tests => 794; # Update this when adding/deleting tests. run_tests() unless caller; @@ -1783,6 +1783,17 @@ EOP # [perl #129281] buffer write overflow, detected by ASAN, valgrind fresh_perl_is('/0(?0)|^*0(?0)|^*(^*())0|/', '', {}, "don't bump whilem_c too much"); } + + { + # RT #131575 intuit skipping back from the end to find the highest + # possible start point, was potentially hopping back beyond pos() + # and crashing by calling fbm_instr with a negative length + + my $text = "=t=\x{5000}"; + pos($text) = 3; + ok(scalar($text !~ m{(~*=[a-z]=)}g), "RT #131575"); + } + } # End of sub run_tests 1; diff --git a/util.c b/util.c index df75db0..bc265f5 100644 --- a/util.c +++ b/util.c @@ -806,6 +806,8 @@ Perl_fbm_instr(pTHX_ unsigned char *big, unsigned char *bigend, SV *littlestr, U PERL_ARGS_ASSERT_FBM_INSTR; + assert(bigend >= big); + if ((STRLEN)(bigend - big) < littlelen) { if ( SvTAIL(littlestr) && ((STRLEN)(bigend - big) == littlelen - 1) -- 2.9.4