Blame SOURCES/XML-Parser-2.44_01-Fix-a-buffer-overwrite-in-parse_stream.patch

cc57d3
From 53e71571fc0b1f8dbad5f7ff6e9eeeb233496c13 Mon Sep 17 00:00:00 2001
cc57d3
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
cc57d3
Date: Thu, 13 Dec 2018 13:05:07 +0100
cc57d3
Subject: [PATCH] Fix a buffer overwrite in parse_stream()
cc57d3
cc57d3
The parse_stream() function allocates BUFSIZE-byte long output buffer. Then it
cc57d3
reads a string using PerlIO's read() with a maximal string length tsiz=BUFSIZE
cc57d3
characters into a temporary buffer. And then it retrieves a length of the string
cc57d3
in the temporary buffer in bytes and copies the strings from the temporary
cc57d3
buffer to the output buffer.
cc57d3
cc57d3
While it works for byte-stream file handles, when using UTF-8 handles, length
cc57d3
in bytes can be greater than length in characters, thus the temporary buffer
cc57d3
can contain more bytes than the size of the output buffer and we have a buffer
cc57d3
overwrite. This corrupts memory, especially metadata for libc memory
cc57d3
management and subsequent free() aborts with "free(): invalid next size
cc57d3
(normal)".
cc57d3
cc57d3
Minimal reproducer: Execute this code with an UTF-8 encoded file with non-ASCII
cc57d3
charcters on the standard input:
cc57d3
cc57d3
use XML::XPath;
cc57d3
use open ':std', ':encoding(UTF-8)';
cc57d3
my $xpath = XML::XPath->new(ioref => \*STDIN);
cc57d3
$xpath->find('/');
cc57d3
cc57d3
https://bugzilla.redhat.com/show_bug.cgi?id=1473368
cc57d3
https://bugzilla.redhat.com/show_bug.cgi?id=1658512
cc57d3
---
cc57d3
 Expat/Expat.xs | 10 ++++++----
cc57d3
 1 file changed, 6 insertions(+), 4 deletions(-)
cc57d3
cc57d3
diff --git a/Expat/Expat.xs b/Expat/Expat.xs
cc57d3
index ed66531..dbad380 100644
cc57d3
--- a/Expat/Expat.xs
cc57d3
+++ b/Expat/Expat.xs
cc57d3
@@ -343,8 +343,8 @@ parse_stream(XML_Parser parser, SV * ioref)
cc57d3
   }
cc57d3
   else {
cc57d3
     tbuff = newSV(0);
cc57d3
-    tsiz = newSViv(BUFSIZE);
cc57d3
-    buffsize = BUFSIZE;
cc57d3
+    tsiz = newSViv(BUFSIZE); /* in UTF-8 characters */
cc57d3
+    buffsize = BUFSIZE * 6; /* in bytes that encode an UTF-8 string */
cc57d3
   }
cc57d3
 
cc57d3
   while (! done)
cc57d3
@@ -386,9 +386,11 @@ parse_stream(XML_Parser parser, SV * ioref)
cc57d3
 	  croak("read error");
cc57d3
 
cc57d3
 	tb = SvPV(tbuff, br);
cc57d3
-	if (br > 0)
cc57d3
+	if (br > 0) {
cc57d3
+	  if (br > buffsize)
cc57d3
+	    croak("The input buffer is not large enough for read UTF-8 decoded string");
cc57d3
 	  Copy(tb, buffer, br, char);
cc57d3
-	else
cc57d3
+	} else
cc57d3
 	  done = 1;
cc57d3
 
cc57d3
 	PUTBACK ;
cc57d3
-- 
cc57d3
2.18.1
cc57d3