summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Williamson <khw@cpan.org>2019-04-27 14:04:58 -0600
committerKarl Williamson <khw@cpan.org>2019-05-03 10:58:50 -0600
commit3fdfceb306b900b57c3ce5ad662aea091cfb53a6 (patch)
treeb6a6ae82e0d422eb1ba8e1fd7a04178e0b017eb2
parentabf787ba980b7d12a799dc22b830524bed5e028d (diff)
downloadperl-3fdfceb306b900b57c3ce5ad662aea091cfb53a6.tar.gz
PATCH: [perl #134067] heap buffer overflow in lexing
This bug happens under tr///. In some circumstances, a byte is inserted in the output that wasn't in the input, and it did not check that there was space available for this character. The result could be a write after the buffer end. I suspect that this bug has been there all along, and the blamed commit rearranged things so that it is more likely to happen; it depends on needing to malloc in just the wrong place.
-rw-r--r--MANIFEST1
-rw-r--r--t/op/tr_latin1.t20
-rw-r--r--toke.c12
3 files changed, 32 insertions, 1 deletions
diff --git a/MANIFEST b/MANIFEST
index f058168722..bec5b5f171 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -5805,6 +5805,7 @@ t/op/tiehandle.t See if tie for handles works
t/op/time.t See if time functions work
t/op/time_loop.t Test that very large values don't hang gmtime and localtime.
t/op/tr.t See if tr works
+t/op/tr_latin1.t See if tr works, but file isn't encoded in UTF-8
t/op/undef.t See if undef works
t/op/universal.t See if UNIVERSAL class works
t/op/unlink.t See if unlink works
diff --git a/t/op/tr_latin1.t b/t/op/tr_latin1.t
new file mode 100644
index 0000000000..e01477c422
--- /dev/null
+++ b/t/op/tr_latin1.t
@@ -0,0 +1,20 @@
+# Tests for tr, but the test file is not utf8.
+
+BEGIN {
+ chdir 't' if -d 't';
+ require './test.pl';
+ set_up_inc('../lib');
+}
+
+plan tests => 1;
+
+{ # This test is malloc senstive. Right now on some platforms anyway, space
+ # for the final \xff needs to be mallocd, and that's what caused the
+ # problem, because the '-' had already been parsed and was later added
+ # without making space for it
+ fresh_perl_is('print "\x8c" =~ y o\x{100}ÄŒÿÿ€€-ÿoo', "1", { },
+ 'RT #134067 heap-buffer-overflow in S_scan_const');
+
+}
+
+1;
diff --git a/toke.c b/toke.c
index 5dca9de4b2..b409628ca4 100644
--- a/toke.c
+++ b/toke.c
@@ -3194,11 +3194,21 @@ S_scan_const(pTHX_ char *start)
&& (range_min > 255 || ! convert_unicode)
#endif
) {
+ const STRLEN off = d - SvPVX(sv);
+ const STRLEN extra = 1 + (send - s) + 1;
+ char *e;
+
/* Move the high character one byte to the right; then
* insert between it and the range begin, an illegal
* byte which serves to indicate this is a range (using
* a '-' would be ambiguous). */
- char *e = d++;
+
+ if (off + extra > SvLEN(sv)) {
+ d = off + SvGROW(sv, off + extra);
+ max_ptr = d - off + offset_to_max;
+ }
+
+ e = d++;
while (e-- > max_ptr) {
*(e + 1) = *e;
}