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

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