(perl #131836) avoid a use-after-free after parsing a "sub" keyword
authorTony Cook <tony@develop-help.com>
Mon, 7 Aug 2017 01:27:50 +0000 (11:27 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 28 Aug 2017 06:05:47 +0000 (16:05 +1000)
The:

  d = skipspace(d);

can reallocate linestr in the test case, invalidating s.  This would
end up in PL_bufptr from the embedded (PL_bufptr = s) in the TOKEN()
macro.

Assigning s to PL_bufptr and restoring s from PL_bufptr allows
lex_next_chunk() to adjust the pointer to the reallocated buffer.

t/comp/parser_run.t
toke.c

index 0fca5b2..a2cc27d 100644 (file)
@@ -10,7 +10,7 @@ BEGIN {
 }
 
 require './test.pl';
 }
 
 require './test.pl';
-plan(2);
+plan(3);
 
 # [perl #130814] can reallocate lineptr while looking ahead for
 # "Missing $ on loop variable" diagnostic.
 
 # [perl #130814] can reallocate lineptr while looking ahead for
 # "Missing $ on loop variable" diagnostic.
@@ -31,5 +31,13 @@ EOS
 Unrecognized character \xD5; marked by <-- HERE after ${ <-- HERE near column 4 at - line 1.
 EXPECT
 
 Unrecognized character \xD5; marked by <-- HERE after ${ <-- HERE near column 4 at - line 1.
 EXPECT
 
+fresh_perl_is(<<'EOS', <<'EXPECTED', {}, "use after free (#131836)");
+${sub#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+EOS
+Missing right curly or square bracket at - line 1, at end of line
+syntax error at - line 1, at EOF
+Execution of - aborted due to compilation errors.
+EXPECTED
+
 __END__
 # ex: set ts=8 sts=4 sw=4 et:
 __END__
 # ex: set ts=8 sts=4 sw=4 et:
diff --git a/toke.c b/toke.c
index 99b737b..591b169 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -6222,8 +6222,10 @@ Perl_yylex(pTHX)
                        break;
                    }
                    if (strEQs(s, "sub")) {
                        break;
                    }
                    if (strEQs(s, "sub")) {
+                        PL_bufptr = s;
                        d = s + 3;
                        d = skipspace(d);
                        d = s + 3;
                        d = skipspace(d);
+                        s = PL_bufptr;
                        if (*d == ':') {
                            PL_expect = XTERM;
                            break;
                        if (*d == ':') {
                            PL_expect = XTERM;
                            break;