libxml2-2.9.4: Fix CVE-2016-4658 [No upstream tracking] -- https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-4658 xpointer: Disallow namespace nodes in XPointer points and 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. Upstream-Status: Backported - [https://git.gnome.org/browse/libxml2/commit/?id=c1d1f7121194036608bf555f08d3062a36fd344b] - [https://git.gnome.org/browse/libxml2/commit/?id=3f8a91036d338e51c059d54397a42d645f019c65] CVE: CVE-2016-4658 Signed-off-by: Andrej Valek Signed-off-by: Pascal Bach diff --git a/xpointer.c b/xpointer.c index 676c510..911680d 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); } @@ -1835,8 +1798,8 @@ xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { case XPATH_RANGE: { xmlNodePtr node = tmp->user; if (node != NULL) { - if (node->type == XML_ATTRIBUTE_NODE) { - /* TODO: Namespace Nodes ??? */ + if ((node->type == XML_ATTRIBUTE_NODE) || + (node->type == XML_NAMESPACE_DECL)) { xmlXPathFreeObject(obj); xmlXPtrFreeLocationSet(newset); XP_ERROR(XPTR_SYNTAX_ERROR); @@ -1931,8 +1894,8 @@ xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { case XPATH_RANGE: { xmlNodePtr node = tmp->user2; if (node != NULL) { - if (node->type == XML_ATTRIBUTE_NODE) { - /* TODO: Namespace Nodes ??? */ + if ((node->type == XML_ATTRIBUTE_NODE) || + (node->type == XML_NAMESPACE_DECL)) { xmlXPathFreeObject(obj); xmlXPtrFreeLocationSet(newset); XP_ERROR(XPTR_SYNTAX_ERROR);