Control: tags -1 patch
thanks

On 28.05.2016 17:50, Dominic Hargreaves wrote:
On Thu, May 26, 2016 at 04:47:07PM +0100, Dominic Hargreaves wrote:
On Thu, May 26, 2016 at 04:22:45PM +0300, Yuriy M. Kaminskiy wrote:
Dear Maintainer,

I've made typo in code, and found that it freezes perl on attempt to parse:
             perl -ce 's{foo}{$h->X({->aaa=>"b"},$d)}ge'
( it was meant to be 's{foo}{$h->X({-aaa=>"b"},$d)}ge' )

Thanks for the report!

[snip backtrace]

(Theoretically, this can be called "potential DoS on parsing untrusted
code", but I'm pretty sure parsing untrusted perl code is not safe anyway).

It seems only jessie version affected, perl binaries extracted from
perl-base packages from wheezy and squeeze seems correctly report error:

Just to note that I can confirm that it we get a syntax error on
wheezy (so this is a regression for jessie).

$ ./perl5.22.2 -ce 's{foo}{$h->X({->aaa=>"b"},$d)}ge'
syntax error at -e line 1, near "{->aaa"
syntax error at -e line 1, near ")}"
-e had compilation errors.

It seems no changes in 5.20.2-3+deb8u5 (from jessie-proposed-updates) (also
freezes).

Thanks for the report!

I bisected this using something like:

cat ../test_prog.sh
#!/bin/sh

./perl -e 's{foo}{$h->X({->aaa=>"b"},$d)}ge;'

if [ $? = 255 ]; then
     exit 0
fi

../perl/Porting/bisect.pl --expect-fail --start v5.20.0 --end v5.22.0 --timeout 
2 -- ../test_prog.sh

This was fixed upstream by f8a7ccebba5637bf0cf5a23cea563b2ccd62312d[1],
which as you observed was first included in 5.22.0. It may be a candidate
for backporting to jessie / maint-5.20 upstream, but the patch doesn't
apply as-is.

Just to add to this: since perl 5.20 is out of support upstream, and
this isn't a critical issue, I suspect not much more will happen on
this bug from me. If someone else wants to backport the patch, I'd
happily consider it for inclusion in a future stable update.

Something like attached? (only complication: lack of op_sibling_splice in 5.20). Compiled with pbuilder (BTW, needed USENETWORK=yes; otherwise it failed two tests for IO::Socket::IP; looks like #759799?), minimally tested, seems work.
Disclaimer: use with care/review carefully/IANAPH.
diff -Nru perl-5.20.2/debian/changelog perl-5.20.2/debian/changelog
--- perl-5.20.2/debian/changelog        2016-05-24 01:42:25.000000000 +0300
+++ perl-5.20.2/debian/changelog        2016-05-28 18:04:59.000000000 +0300
@@ -1,3 +1,10 @@
+perl (5.20.2-3+deb8u5.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * Backported fix for freeze on parsing invalid code (Closes: #825378)
+
+ -- Yuriy M. Kaminskiy <yumkam+deb...@gmail.com>  Sat, 28 May 2016 18:04:02 
+0300
+
 perl (5.20.2-3+deb8u5) jessie; urgency=medium
 
   * Apply patch from Niko Tyni fixing debugperl crashes with XS
diff -Nru 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch
 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch
--- 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch
    1970-01-01 03:00:00.000000000 +0300
+++ 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch
    2016-05-28 18:33:37.000000000 +0300
@@ -0,0 +1,70 @@
+From f8a7ccebba5637bf0cf5a23cea563b2ccd62312d Mon Sep 17 00:00:00 2001
+From: Father Chrysostomos <spr...@cpan.org>
+Date: Fri, 3 Oct 2014 22:40:36 -0700
+Subject: [PATCH] Fix assertion failure/hang with / (?{(^{})/
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf8
+Content-Transfer-Encoding: 8bit
+
+When this invalid construct is parsed, the resulting op tree for the
+pattern has a code block with no constant item following it, breaking
+the assumptions made by pmruntime.
+
+Fixing this was not so easy.
+
+You can’t just adjust the assertions, because the hang that non-debug-
+ging builds exhibited is still there.
+
+You can’t just return NULL from pmruntime when encounting the bad op
+tree, because the parser will crash on the null pointer.
+
+You can’t just return the empty pmop, because the wrong pad is
+active, and other functions in op.c will try to access nonexistent
+pad entries.
+
+You can’t just LEAVE_SCOPE and return the pmop, because then PL_parser
+will be null in yyerror.  Changing yyerror to account is not suffi-
+cient, because then you get double-freed SVs.  At that point I gave up
+with that approach.
+
+The easiest solution turned out to be to fake up the op that we were
+expecting to see.
+---
+ op.c          | 10 +++++++++-
+ t/re/re_tests |  1 +
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+Bug-Debian: https://bugs.debian.org/825378
+
+Index: perl-5.20.2/op.c
+===================================================================
+--- perl-5.20.2.orig/op.c
++++ perl-5.20.2/op.c
+@@ -4846,7 +4846,14 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bo
+       for (o = cLISTOPx(expr)->op_first; o; o = o->op_sibling) {
+           if (o->op_type == OP_NULL && (o->op_flags & OPf_SPECIAL)) {
+               has_code = 1;
+-              assert(!o->op_next && o->op_sibling);
++              assert(!o->op_next);
++              if (UNLIKELY(!o->op_sibling)) {
++                  assert(PL_parser && PL_parser->error_count);
++                  /* This can happen with qr/ (?{(^{})/.  Just fake up
++                     the op we were expecting to see, to avoid crashing
++                     elsewhere.  */
++                    o->op_sibling = newSVOP(OP_CONST, 0, &PL_sv_no);
++              }
+               o->op_next = o->op_sibling;
+           }
+           else if (o->op_type != OP_CONST && o->op_type != OP_PUSHMARK)
+Index: perl-5.20.2/t/re/re_tests
+===================================================================
+--- perl-5.20.2.orig/t/re/re_tests
++++ perl-5.20.2/t/re/re_tests
+@@ -538,6 +538,7 @@ foo\w*\d{4}baz     foobar1234baz   y       $&      foobar
+ a(?{})b       cabd    y       $&      ab
+ a(?{f()+      -       c       -       Missing right curly or square bracket
+ a(?{{1}+      -       c       -       Missing right curly or square bracket
++ (?{(^{})     -       c       -       syntax error
+ a(?{}})b      -       c       -       
+ a(?{"{"})b    ab      y       -       -
+ a(?{"\{"})b   cabd    y       $&      ab
diff -Nru 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch.save
 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch.save
--- 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch.save
       1970-01-01 03:00:00.000000000 +0300
+++ 
perl-5.20.2/debian/patches/fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch.save
       2016-05-28 17:53:39.000000000 +0300
@@ -0,0 +1,72 @@
+From f8a7ccebba5637bf0cf5a23cea563b2ccd62312d Mon Sep 17 00:00:00 2001
+From: Father Chrysostomos <spr...@cpan.org>
+Date: Fri, 3 Oct 2014 22:40:36 -0700
+Subject: [PATCH] Fix assertion failure/hang with / (?{(^{})/
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf8
+Content-Transfer-Encoding: 8bit
+
+When this invalid construct is parsed, the resulting op tree for the
+pattern has a code block with no constant item following it, breaking
+the assumptions made by pmruntime.
+
+Fixing this was not so easy.
+
+You can’t just adjust the assertions, because the hang that non-debug-
+ging builds exhibited is still there.
+
+You can’t just return NULL from pmruntime when encounting the bad op
+tree, because the parser will crash on the null pointer.
+
+You can’t just return the empty pmop, because the wrong pad is
+active, and other functions in op.c will try to access nonexistent
+pad entries.
+
+You can’t just LEAVE_SCOPE and return the pmop, because then PL_parser
+will be null in yyerror.  Changing yyerror to account is not suffi-
+cient, because then you get double-freed SVs.  At that point I gave up
+with that approach.
+
+The easiest solution turned out to be to fake up the op that we were
+expecting to see.
+---
+ op.c          | 10 +++++++++-
+ t/re/re_tests |  1 +
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/op.c b/op.c
+index 930df2d..c864a26 100644
+--- a/op.c
++++ b/op.c
+@@ -4922,7 +4922,15 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 
floor)
+       for (o = cLISTOPx(expr)->op_first; o; o = OP_SIBLING(o)) {
+           if (o->op_type == OP_NULL && (o->op_flags & OPf_SPECIAL)) {
+               has_code = 1;
+-              assert(!o->op_next && OP_HAS_SIBLING(o));
++              assert(!o->op_next);
++              if (UNLIKELY(!OP_HAS_SIBLING(o))) {
++                  assert(PL_parser && PL_parser->error_count);
++                  /* This can happen with qr/ (?{(^{})/.  Just fake up
++                     the op we were expecting to see, to avoid crashing
++                     elsewhere.  */
++                  op_sibling_splice(expr, o, 0,
++                                    newSVOP(OP_CONST, 0, &PL_sv_no));
++              }
+               o->op_next = OP_SIBLING(o);
+           }
+           else if (o->op_type != OP_CONST && o->op_type != OP_PUSHMARK)
+diff --git a/t/re/re_tests b/t/re/re_tests
+index 964360d..2c40e85 100644
+--- a/t/re/re_tests
++++ b/t/re/re_tests
+@@ -539,6 +539,7 @@ foo\w*\d{4}baz     foobar1234baz   y       $&      
foobar1234baz
+ a(?{})b       cabd    y       $&      ab
+ a(?{f()+      -       c       -       Missing right curly or square bracket
+ a(?{{1}+      -       c       -       Missing right curly or square bracket
++ (?{(^{})     -       c       -       syntax error
+ a(?{}})b      -       c       -       
+ a(?{"{"})b    ab      y       -       -
+ a(?{"\{"})b   cabd    y       $&      ab
+-- 
+2.9.0-rc0-220-g588f76c
+
diff -Nru perl-5.20.2/debian/patches/series perl-5.20.2/debian/patches/series
--- perl-5.20.2/debian/patches/series   2016-05-24 01:41:19.000000000 +0300
+++ perl-5.20.2/debian/patches/series   2016-05-28 17:56:15.000000000 +0300
@@ -79,3 +79,4 @@
 fixes/5.20.3/docs/perlunicook_typos.diff
 fixes/5.20.3/docs/ook_example.diff
 fixes/5.20.3/docs/study_noop.diff
+fixes/perl.git-f8a7ccebba5637bf0cf5a23cea563b2ccd62312d.patch

Reply via email to