diff --git a/SOURCES/XML-Parser-2.48-CVE-2006-10002.patch b/SOURCES/XML-Parser-2.48-CVE-2006-10002.patch new file mode 100644 index 0000000..03b4163 --- /dev/null +++ b/SOURCES/XML-Parser-2.48-CVE-2006-10002.patch @@ -0,0 +1,106 @@ +From 5361c2b7f48599718cdecbe50c5fdd88b28ffd79 Mon Sep 17 00:00:00 2001 +From: Toddr Bot +Date: Mon, 16 Mar 2026 20:55:31 +0000 +Subject: [PATCH] Fix buffer overflow in parse_stream when filehandle has :utf8 + layer + +When a filehandle has a :utf8 PerlIO layer, Perl's read() returns +decoded characters, but SvPV() gives back the UTF-8 byte +representation which can be larger than the pre-allocated XML buffer. +Previously this caused heap corruption (double free / buffer overflow), +and a later workaround (BUFSIZE * 6 + croak) prevented the corruption +but still crashed. + +Fix by re-obtaining the expat buffer at the actual byte size when the +read produces more bytes than initially allocated. This handles UTF-8 +streams gracefully without wasting memory on an oversized buffer. + +Fixes https://github.com/cpan-authors/XML-Parser/issues/64 +(migrated from rt.cpan.org #19859) + +Co-Authored-By: Claude Opus 4.6 +--- + Expat/Expat.xs | 15 +++++++++++---- + t/utf8_stream.t | 40 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+), 4 deletions(-) + create mode 100644 t/utf8_stream.t + +diff --git a/Expat/Expat.xs b/Expat/Expat.xs +index 32fdce5..3cd1154 100644 +--- a/Expat/Expat.xs ++++ b/Expat/Expat.xs +@@ -343,8 +343,8 @@ parse_stream(XML_Parser parser, SV * ioref) + } + else { + tbuff = newSV(0); +- tsiz = newSViv(BUFSIZE); /* in UTF-8 characters */ +- buffsize = BUFSIZE * 6; /* in bytes that encode an UTF-8 string */ ++ tsiz = newSViv(BUFSIZE); ++ buffsize = BUFSIZE; + } + + while (! done) +@@ -387,8 +387,15 @@ parse_stream(XML_Parser parser, SV * ioref) + + tb = SvPV(tbuff, br); + if (br > 0) { +- if (br > buffsize) +- croak("The input buffer is not large enough for read UTF-8 decoded string"); ++ if (br > buffsize) { ++ /* The byte count from SvPV can exceed buffsize when the ++ filehandle has a :utf8 layer, since Perl reads buffsize ++ characters but multi-byte UTF-8 chars produce more bytes. ++ Re-obtain the buffer at the required size. */ ++ buffer = XML_GetBuffer(parser, br); ++ if (! buffer) ++ croak("Ran out of memory for input buffer"); ++ } + Copy(tb, buffer, br, char); + } else + done = 1; +diff --git a/t/utf8_stream.t b/t/utf8_stream.t +new file mode 100644 +index 0000000..a7e55f7 +--- /dev/null ++++ b/t/utf8_stream.t +@@ -0,0 +1,40 @@ ++BEGIN { print "1..2\n"; } ++END { print "not ok 1\n" unless $loaded; } ++use XML::Parser; ++$loaded = 1; ++print "ok 1\n"; ++ ++################################################################ ++# Test parsing from a filehandle with :utf8 layer ++# Regression test for rt.cpan.org #19859 / GitHub issue #64 ++# A UTF-8 stream caused buffer overflow because SvPV byte count ++# could exceed the pre-allocated XML_GetBuffer size. ++ ++use File::Temp qw(tempfile); ++ ++# Create a temp file with UTF-8 XML content containing multi-byte chars ++my ($fh, $tmpfile) = tempfile(UNLINK => 1); ++binmode($fh, ':raw'); ++# Write raw UTF-8 bytes: XML with Chinese characters (3 bytes each in UTF-8) ++# U+4E16 U+754C (世界 = "world") repeated to create substantial multi-byte content ++my $body = "\xe4\xb8\x96\xe7\x95\x8c" x 20000; # 120000 bytes / 40000 chars of 3-byte UTF-8 ++print $fh qq(\n$body\n); ++close($fh); ++ ++my $text = ''; ++my $parser = XML::Parser->new( ++ Handlers => { ++ Char => sub { $text .= $_[1]; }, ++ } ++); ++ ++# Open with :utf8 layer - this is what triggers the bug ++open(my $in, '<:utf8', $tmpfile) or die "Cannot open $tmpfile: $!"; ++eval { $parser->parse($in); }; ++close($in); ++ ++if ($@ eq '' && length($text) > 0) { ++ print "ok 2\n"; ++} else { ++ print "not ok 2 # $@\n"; ++} diff --git a/SOURCES/XML-Parser-2.48-CVE-2006-10003.patch b/SOURCES/XML-Parser-2.48-CVE-2006-10003.patch new file mode 100644 index 0000000..ed2124c --- /dev/null +++ b/SOURCES/XML-Parser-2.48-CVE-2006-10003.patch @@ -0,0 +1,66 @@ +From 08dd37c35ec5e64e26aacb8514437f54708f7fd1 Mon Sep 17 00:00:00 2001 +From: Toddr Bot +Date: Mon, 16 Mar 2026 22:16:11 +0000 +Subject: [PATCH] fix: off-by-one heap buffer overflow in st_serial_stack + growth check + +When st_serial_stackptr == st_serial_stacksize - 1, the old check +(stackptr >= stacksize) would not trigger reallocation. The subsequent +++stackptr then writes at index stacksize, one element past the +allocated buffer. + +Fix by checking stackptr + 1 >= stacksize so the buffer is grown +before the pre-increment write. + +Add a deep nesting test (600 levels) to exercise this code path. + +Fixes #39 + +Co-Authored-By: Claude Opus 4.6 +--- + Expat/Expat.xs | 2 +- + t/deep_nesting.t | 22 ++++++++++++++++++++++ + 2 files changed, 23 insertions(+), 1 deletion(-) + create mode 100644 t/deep_nesting.t + +diff --git a/Expat/Expat.xs b/Expat/Expat.xs +index 5f9b193..0226a24 100644 +--- a/Expat/Expat.xs ++++ b/Expat/Expat.xs +@@ -514,7 +514,7 @@ startElement(void *userData, const char *name, const char **atts) + } + } + +- if (cbv->st_serial_stackptr >= cbv->st_serial_stacksize) { ++ if (cbv->st_serial_stackptr + 1 >= cbv->st_serial_stacksize) { + unsigned int newsize = cbv->st_serial_stacksize + 512; + + Renew(cbv->st_serial_stack, newsize, unsigned int); +diff --git a/t/deep_nesting.t b/t/deep_nesting.t +new file mode 100644 +index 0000000..8237b5f +--- /dev/null ++++ b/t/deep_nesting.t +@@ -0,0 +1,22 @@ ++BEGIN { print "1..1\n"; } ++ ++# Test for deeply nested elements to exercise st_serial_stack reallocation. ++# This catches off-by-one errors in the stack growth check (GH #39). ++ ++use XML::Parser; ++ ++my $depth = 600; ++ ++my $xml = ''; ++for my $i (1 .. $depth) { ++ $xml .= ""; ++} ++for my $i (reverse 1 .. $depth) { ++ $xml .= ""; ++} ++ ++my $p = XML::Parser->new; ++eval { $p->parse($xml) }; ++ ++print "not " if $@; ++print "ok 1\n"; diff --git a/SPECS/perl-XML-Parser.spec b/SPECS/perl-XML-Parser.spec index 969a178..68c4510 100644 --- a/SPECS/perl-XML-Parser.spec +++ b/SPECS/perl-XML-Parser.spec @@ -1,11 +1,17 @@ Name: perl-XML-Parser Version: 2.46 -Release: 9%{?dist} +Release: 9.1.0.1%{?dist} Summary: Perl module for parsing XML documents License: GPL+ or Artistic Url: https://metacpan.org/release/XML-Parser Source0: https://cpan.metacpan.org/authors/id/T/TO/TODDR/XML-Parser-%{version}.tar.gz +# Fix buffer overflow in parse_stream when filehandle has :utf8 +# CVE-2006-10002 +Patch0: XML-Parser-2.48-CVE-2006-10002.patch +# Fix off-by-one heap buffer overflow in st_serial_stack growth check +# CVE-2006-10003 +Patch1: XML-Parser-2.48-CVE-2006-10003.patch # Build BuildRequires: coreutils @@ -37,6 +43,7 @@ BuildRequires: perl(URI) BuildRequires: perl(URI::file) BuildRequires: perl(XSLoader) # Tests +BuildRequires: perl(File::Temp) BuildRequires: perl(if) BuildRequires: perl(Test) BuildRequires: perl(Test::More) @@ -44,6 +51,9 @@ BuildRequires: perl(warnings) Requires: perl(:MODULE_COMPAT_%(eval "`perl -V:version`"; echo $version)) Requires: perl(IO::File) Requires: perl(IO::Handle) +Requires: perl(LWP) +Requires: perl(URI) +Requires: perl(URI::file) %{?perl_default_filter} @@ -60,8 +70,19 @@ parse call. They can also be given as extra arguments to the parse methods, in which case they override options given at XML::Parser creation time. +%package tests +Summary: Tests for %{name} +Requires: %{name} = %{?epoch:%{epoch}:}%{version}-%{release} +Requires: perl-Test-Harness + +%description tests +Tests from %{name}. Execute them +with "%{_libexecdir}/%{name}/test". + %prep %setup -q -n XML-Parser-%{version} +%patch -P0 -p1 +%patch -P1 -p1 chmod 644 samples/{canonical,xml*} perl -MConfig -pi -e 's|^#!/usr/local/bin/perl\b|$Config{startperl}|' samples/{canonical,xml*} @@ -69,6 +90,12 @@ perl -MConfig -pi -e 's|^#!/usr/local/bin/perl\b|$Config{startperl}|' samples/{c rm -r inc perl -i -ne 'print $_ unless m{^inc/}' MANIFEST +# Help generators to recognize Perl scripts +for F in t/*.t; do + perl -i -MConfig -ple 'print $Config{startperl} if $. == 1 && !s{\A#!.*perl\b}{$Config{startperl}}' "$F" + chmod +x "$F" +done + %build perl Makefile.PL INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 OPTIMIZE="$RPM_OPT_FLAGS" %{make_build} @@ -84,17 +111,43 @@ for file in samples/REC-xml-19980210.xml; do perl -i -pe "s/encoding='ISO-8859-1'/encoding='UTF-8'/" "$file" done +# Install tests +mkdir -p %{buildroot}%{_libexecdir}/%{name} +cp -a t samples %{buildroot}%{_libexecdir}/%{name} +cat > %{buildroot}%{_libexecdir}/%{name}/test << 'EOF' +#!/bin/bash +set -e +# Some tests write into temporary files/directories. The easiest solution +# is to copy the tests into a writable directory and execute them from there. +DIR=$(mktemp -d) +pushd "$DIR" +cp -a %{_libexecdir}/%{name}/* ./ +prove -I . -j "$(getconf _NPROCESSORS_ONLN)" +popd +rm -rf "$DIR" +EOF +chmod +x %{buildroot}%{_libexecdir}/%{name}/test + %check +export HARNESS_OPTIONS=j$(perl -e 'if ($ARGV[0] =~ /.*-j([0-9][0-9]*).*/) {print $1} else {print 1}' -- '%{?_smp_mflags}') make test %files %doc README Changes samples/ %{perl_vendorarch}/XML/ %{perl_vendorarch}/auto/XML/ -%{_mandir}/man3/*.3* +%{_mandir}/man3/XML::Parser*.3* +%files tests +%{_libexecdir}/%{name} %changelog +* Sun Apr 12 2026 EL Errata - 2.46-9.1.0.1 +- Add perl(LWP), perl(URI), perl(URI::file) Requires + +* Thu Mar 26 2026 Jitka Plesnikova - 2.46-9.1 +- Fix CVE-2006-10002, CVE-2006-10003 + * Mon Aug 09 2021 Mohan Boddu - 2.46-9 - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags Related: rhbz#1991688