* [PATCH 1/1] gnu: libxml: Fix CVE-2016-{4658,5131}.
2016-12-23 21:24 [PATCH 0/1] Libxml2 CVE-2016-4658 and CVE-2016-5131 Leo Famulari
@ 2016-12-23 21:24 ` Leo Famulari
2016-12-24 14:39 ` [PATCH 0/1] Libxml2 CVE-2016-4658 and CVE-2016-5131 Marius Bakke
1 sibling, 0 replies; 5+ messages in thread
From: Leo Famulari @ 2016-12-23 21:24 UTC (permalink / raw)
To: guix-devel
* gnu/packages/patches/libxml2-CVE-2016-4658.patch,
gnu/packages/patches/libxml2-CVE-2016-5131.patch: New files.
* gnu/local.mk (dist_patch_DATA): Add them.
* gnu/packages/xml.scm (libxml2)[source]: Use them.
---
gnu/local.mk | 2 +
gnu/packages/patches/libxml2-CVE-2016-4658.patch | 257 +++++++++++++++++++++++
gnu/packages/patches/libxml2-CVE-2016-5131.patch | 218 +++++++++++++++++++
gnu/packages/xml.scm | 2 +
4 files changed, 479 insertions(+)
create mode 100644 gnu/packages/patches/libxml2-CVE-2016-4658.patch
create mode 100644 gnu/packages/patches/libxml2-CVE-2016-5131.patch
diff --git a/gnu/local.mk b/gnu/local.mk
index ee8f1e591..106adb235 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -696,6 +696,8 @@ dist_patch_DATA = \
%D%/packages/patches/libwmf-CVE-2015-0848+CVE-2015-4588.patch \
%D%/packages/patches/libwmf-CVE-2015-4695.patch \
%D%/packages/patches/libwmf-CVE-2015-4696.patch \
+ %D%/packages/patches/libxml2-CVE-2016-4658.patch \
+ %D%/packages/patches/libxml2-CVE-2016-5131.patch \
%D%/packages/patches/libxslt-generated-ids.patch \
%D%/packages/patches/libxslt-CVE-2016-4738.patch \
%D%/packages/patches/linux-pam-no-setfsuid.patch \
diff --git a/gnu/packages/patches/libxml2-CVE-2016-4658.patch b/gnu/packages/patches/libxml2-CVE-2016-4658.patch
new file mode 100644
index 000000000..a4e1f31fa
--- /dev/null
+++ b/gnu/packages/patches/libxml2-CVE-2016-4658.patch
@@ -0,0 +1,257 @@
+Fix CVE-2016-4658:
+
+https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4658
+
+Patch copied from upstream source repository:
+
+https://git.gnome.org/browse/libxml2/commit/?id=c1d1f7121194036608bf555f08d3062a36fd344b
+
+From c1d1f7121194036608bf555f08d3062a36fd344b Mon Sep 17 00:00:00 2001
+From: Nick Wellnhofer <wellnhofer@aevum.de>
+Date: Tue, 28 Jun 2016 18:34:52 +0200
+Subject: [PATCH] Disallow namespace nodes in XPointer ranges
+
+Namespace nodes must be copied to avoid use-after-free errors.
+But they don't necessarily have a physical representation in a
+document, so simply disallow them in XPointer ranges.
+
+Found with afl-fuzz.
+
+Fixes CVE-2016-4658.
+---
+ xpointer.c | 149 +++++++++++++++++++++++--------------------------------------
+ 1 file changed, 56 insertions(+), 93 deletions(-)
+
+diff --git a/xpointer.c b/xpointer.c
+index a7b03fbd..694d120e 100644
+--- a/xpointer.c
++++ b/xpointer.c
+@@ -320,6 +320,45 @@ xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
+ }
+
+ /**
++ * xmlXPtrNewRangeInternal:
++ * @start: the starting node
++ * @startindex: the start index
++ * @end: the ending point
++ * @endindex: the ending index
++ *
++ * Internal function to create a new xmlXPathObjectPtr of type range
++ *
++ * Returns the newly created object.
++ */
++static xmlXPathObjectPtr
++xmlXPtrNewRangeInternal(xmlNodePtr start, int startindex,
++ xmlNodePtr end, int endindex) {
++ xmlXPathObjectPtr ret;
++
++ /*
++ * Namespace nodes must be copied (see xmlXPathNodeSetDupNs).
++ * Disallow them for now.
++ */
++ if ((start != NULL) && (start->type == XML_NAMESPACE_DECL))
++ return(NULL);
++ if ((end != NULL) && (end->type == XML_NAMESPACE_DECL))
++ return(NULL);
++
++ ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
++ if (ret == NULL) {
++ xmlXPtrErrMemory("allocating range");
++ return(NULL);
++ }
++ memset(ret, 0, sizeof(xmlXPathObject));
++ ret->type = XPATH_RANGE;
++ ret->user = start;
++ ret->index = startindex;
++ ret->user2 = end;
++ ret->index2 = endindex;
++ return(ret);
++}
++
++/**
+ * xmlXPtrNewRange:
+ * @start: the starting node
+ * @startindex: the start index
+@@ -344,17 +383,7 @@ xmlXPtrNewRange(xmlNodePtr start, int startindex,
+ if (endindex < 0)
+ return(NULL);
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start;
+- ret->index = startindex;
+- ret->user2 = end;
+- ret->index2 = endindex;
++ ret = xmlXPtrNewRangeInternal(start, startindex, end, endindex);
+ xmlXPtrRangeCheckOrder(ret);
+ return(ret);
+ }
+@@ -381,17 +410,8 @@ xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
+ if (end->type != XPATH_POINT)
+ return(NULL);
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start->user;
+- ret->index = start->index;
+- ret->user2 = end->user;
+- ret->index2 = end->index;
++ ret = xmlXPtrNewRangeInternal(start->user, start->index, end->user,
++ end->index);
+ xmlXPtrRangeCheckOrder(ret);
+ return(ret);
+ }
+@@ -416,17 +436,7 @@ xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
+ if (start->type != XPATH_POINT)
+ return(NULL);
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start->user;
+- ret->index = start->index;
+- ret->user2 = end;
+- ret->index2 = -1;
++ ret = xmlXPtrNewRangeInternal(start->user, start->index, end, -1);
+ xmlXPtrRangeCheckOrder(ret);
+ return(ret);
+ }
+@@ -453,17 +463,7 @@ xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
+ if (end->type != XPATH_POINT)
+ return(NULL);
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start;
+- ret->index = -1;
+- ret->user2 = end->user;
+- ret->index2 = end->index;
++ ret = xmlXPtrNewRangeInternal(start, -1, end->user, end->index);
+ xmlXPtrRangeCheckOrder(ret);
+ return(ret);
+ }
+@@ -486,17 +486,7 @@ xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
+ if (end == NULL)
+ return(NULL);
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start;
+- ret->index = -1;
+- ret->user2 = end;
+- ret->index2 = -1;
++ ret = xmlXPtrNewRangeInternal(start, -1, end, -1);
+ xmlXPtrRangeCheckOrder(ret);
+ return(ret);
+ }
+@@ -516,17 +506,7 @@ xmlXPtrNewCollapsedRange(xmlNodePtr start) {
+ if (start == NULL)
+ return(NULL);
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start;
+- ret->index = -1;
+- ret->user2 = NULL;
+- ret->index2 = -1;
++ ret = xmlXPtrNewRangeInternal(start, -1, NULL, -1);
+ return(ret);
+ }
+
+@@ -541,6 +521,8 @@ xmlXPtrNewCollapsedRange(xmlNodePtr start) {
+ */
+ xmlXPathObjectPtr
+ xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
++ xmlNodePtr endNode;
++ int endIndex;
+ xmlXPathObjectPtr ret;
+
+ if (start == NULL)
+@@ -549,7 +531,12 @@ xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
+ return(NULL);
+ switch (end->type) {
+ case XPATH_POINT:
++ endNode = end->user;
++ endIndex = end->index;
++ break;
+ case XPATH_RANGE:
++ endNode = end->user2;
++ endIndex = end->index2;
+ break;
+ case XPATH_NODESET:
+ /*
+@@ -557,39 +544,15 @@ xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
+ */
+ if (end->nodesetval->nodeNr <= 0)
+ return(NULL);
++ endNode = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
++ endIndex = -1;
+ break;
+ default:
+ /* TODO */
+ return(NULL);
+ }
+
+- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+- if (ret == NULL) {
+- xmlXPtrErrMemory("allocating range");
+- return(NULL);
+- }
+- memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+- ret->type = XPATH_RANGE;
+- ret->user = start;
+- ret->index = -1;
+- switch (end->type) {
+- case XPATH_POINT:
+- ret->user2 = end->user;
+- ret->index2 = end->index;
+- break;
+- case XPATH_RANGE:
+- ret->user2 = end->user2;
+- ret->index2 = end->index2;
+- break;
+- case XPATH_NODESET: {
+- ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
+- ret->index2 = -1;
+- break;
+- }
+- default:
+- STRANGE
+- return(NULL);
+- }
++ ret = xmlXPtrNewRangeInternal(start, -1, endNode, endIndex);
+ xmlXPtrRangeCheckOrder(ret);
+ return(ret);
+ }
+--
+2.11.0
+
diff --git a/gnu/packages/patches/libxml2-CVE-2016-5131.patch b/gnu/packages/patches/libxml2-CVE-2016-5131.patch
new file mode 100644
index 000000000..38938c8e3
--- /dev/null
+++ b/gnu/packages/patches/libxml2-CVE-2016-5131.patch
@@ -0,0 +1,218 @@
+Fix CVE-2016-5131:
+
+https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5131
+
+Patches copied from upstream source repository (the test suite fails
+without the 2nd patch):
+
+https://git.gnome.org/browse/libxml2/commit/?id=9ab01a277d71f54d3143c2cf333c5c2e9aaedd9e
+https://git.gnome.org/browse/libxml2/commit/?id=a005199330b86dada19d162cae15ef9bdcb6baa8
+
+From 9ab01a277d71f54d3143c2cf333c5c2e9aaedd9e Mon Sep 17 00:00:00 2001
+From: Nick Wellnhofer <wellnhofer@aevum.de>
+Date: Tue, 28 Jun 2016 14:22:23 +0200
+Subject: [PATCH] Fix XPointer paths beginning with range-to
+
+The old code would invoke the broken xmlXPtrRangeToFunction. range-to
+isn't really a function but a special kind of location step. Remove
+this function and always handle range-to in the XPath code.
+
+The old xmlXPtrRangeToFunction could also be abused to trigger a
+use-after-free error with the potential for remote code execution.
+
+Found with afl-fuzz.
+
+Fixes CVE-2016-5131.
+---
+ result/XPath/xptr/vidbase | 13 ++++++++
+ test/XPath/xptr/vidbase | 1 +
+ xpath.c | 7 ++++-
+ xpointer.c | 76 ++++-------------------------------------------
+ 4 files changed, 26 insertions(+), 71 deletions(-)
+
+diff --git a/result/XPath/xptr/vidbase b/result/XPath/xptr/vidbase
+index 8b9e92d6..f19193e7 100644
+--- a/result/XPath/xptr/vidbase
++++ b/result/XPath/xptr/vidbase
+@@ -17,3 +17,16 @@ Object is a Location Set:
+ To node
+ ELEMENT p
+
++
++========================
++Expression: xpointer(range-to(id('chapter2')))
++Object is a Location Set:
++1 : Object is a range :
++ From node
++ /
++ To node
++ ELEMENT chapter
++ ATTRIBUTE id
++ TEXT
++ content=chapter2
++
+diff --git a/test/XPath/xptr/vidbase b/test/XPath/xptr/vidbase
+index b1463830..884b1065 100644
+--- a/test/XPath/xptr/vidbase
++++ b/test/XPath/xptr/vidbase
+@@ -1,2 +1,3 @@
+ xpointer(id('chapter1')/p)
+ xpointer(id('chapter1')/p[1]/range-to(following-sibling::p[2]))
++xpointer(range-to(id('chapter2')))
+diff --git a/xpath.c b/xpath.c
+index d992841e..5a01b1b3 100644
+--- a/xpath.c
++++ b/xpath.c
+@@ -10691,13 +10691,18 @@ xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
+ lc = 1;
+ break;
+ } else if ((NXT(len) == '(')) {
+- /* Note Type or Function */
++ /* Node Type or Function */
+ if (xmlXPathIsNodeType(name)) {
+ #ifdef DEBUG_STEP
+ xmlGenericError(xmlGenericErrorContext,
+ "PathExpr: Type search\n");
+ #endif
+ lc = 1;
++#ifdef LIBXML_XPTR_ENABLED
++ } else if (ctxt->xptr &&
++ xmlStrEqual(name, BAD_CAST "range-to")) {
++ lc = 1;
++#endif
+ } else {
+ #ifdef DEBUG_STEP
+ xmlGenericError(xmlGenericErrorContext,
+diff --git a/xpointer.c b/xpointer.c
+index 676c5105..d74174a3 100644
+--- a/xpointer.c
++++ b/xpointer.c
+@@ -1332,8 +1332,6 @@ xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
+ ret->here = here;
+ ret->origin = origin;
+
+- xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
+- xmlXPtrRangeToFunction);
+ xmlXPathRegisterFunc(ret, (xmlChar *)"range",
+ xmlXPtrRangeFunction);
+ xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
+@@ -2243,76 +2241,14 @@ xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+ * @nargs: the number of args
+ *
+ * Implement the range-to() XPointer function
++ *
++ * Obsolete. range-to is not a real function but a special type of location
++ * step which is handled in xpath.c.
+ */
+ void
+-xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+- xmlXPathObjectPtr range;
+- const xmlChar *cur;
+- xmlXPathObjectPtr res, obj;
+- xmlXPathObjectPtr tmp;
+- xmlLocationSetPtr newset = NULL;
+- xmlNodeSetPtr oldset;
+- int i;
+-
+- if (ctxt == NULL) return;
+- CHECK_ARITY(1);
+- /*
+- * Save the expression pointer since we will have to evaluate
+- * it multiple times. Initialize the new set.
+- */
+- CHECK_TYPE(XPATH_NODESET);
+- obj = valuePop(ctxt);
+- oldset = obj->nodesetval;
+- ctxt->context->node = NULL;
+-
+- cur = ctxt->cur;
+- newset = xmlXPtrLocationSetCreate(NULL);
+-
+- for (i = 0; i < oldset->nodeNr; i++) {
+- ctxt->cur = cur;
+-
+- /*
+- * Run the evaluation with a node list made of a single item
+- * in the nodeset.
+- */
+- ctxt->context->node = oldset->nodeTab[i];
+- tmp = xmlXPathNewNodeSet(ctxt->context->node);
+- valuePush(ctxt, tmp);
+-
+- xmlXPathEvalExpr(ctxt);
+- CHECK_ERROR;
+-
+- /*
+- * The result of the evaluation need to be tested to
+- * decided whether the filter succeeded or not
+- */
+- res = valuePop(ctxt);
+- range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
+- if (range != NULL) {
+- xmlXPtrLocationSetAdd(newset, range);
+- }
+-
+- /*
+- * Cleanup
+- */
+- if (res != NULL)
+- xmlXPathFreeObject(res);
+- if (ctxt->value == tmp) {
+- res = valuePop(ctxt);
+- xmlXPathFreeObject(res);
+- }
+-
+- ctxt->context->node = NULL;
+- }
+-
+- /*
+- * The result is used as the new evaluation set.
+- */
+- xmlXPathFreeObject(obj);
+- ctxt->context->node = NULL;
+- ctxt->context->contextSize = -1;
+- ctxt->context->proximityPosition = -1;
+- valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
++xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt,
++ int nargs ATTRIBUTE_UNUSED) {
++ XP_ERROR(XPATH_EXPR_ERROR);
+ }
+
+ /**
+--
+2.11.0
+
+From a005199330b86dada19d162cae15ef9bdcb6baa8 Mon Sep 17 00:00:00 2001
+From: Nick Wellnhofer <wellnhofer@aevum.de>
+Date: Tue, 28 Jun 2016 14:19:58 +0200
+Subject: [PATCH] Fix comparison with root node in xmlXPathCmpNodes
+
+This change has already been made in xmlXPathCmpNodesExt but not in
+xmlXPathCmpNodes.
+---
+ xpath.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/xpath.c b/xpath.c
+index 751665b8..d992841e 100644
+--- a/xpath.c
++++ b/xpath.c
+@@ -3342,13 +3342,13 @@ xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
+ * compute depth to root
+ */
+ for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
+- if (cur == node1)
++ if (cur->parent == node1)
+ return(1);
+ depth2++;
+ }
+ root = cur;
+ for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
+- if (cur == node2)
++ if (cur->parent == node2)
+ return(-1);
+ depth1++;
+ }
+--
+2.11.0
+
diff --git a/gnu/packages/xml.scm b/gnu/packages/xml.scm
index 594a1a471..79d97579c 100644
--- a/gnu/packages/xml.scm
+++ b/gnu/packages/xml.scm
@@ -79,6 +79,8 @@ things the parser might find in the XML document (like start tags).")
(method url-fetch)
(uri (string-append "ftp://xmlsoft.org/libxml2/libxml2-"
version ".tar.gz"))
+ (patches (search-patches "libxml2-CVE-2016-4658.patch"
+ "libxml2-CVE-2016-5131.patch"))
(sha256
(base32
"0g336cr0bw6dax1q48bblphmchgihx9p1pjmxdnrd6sh3qci3fgz"))))
--
2.11.0
^ permalink raw reply related [flat|nested] 5+ messages in thread