diff --git a/SOURCES/libxslt-1.1.34-CVE-2023-40403.patch b/SOURCES/libxslt-1.1.34-CVE-2023-40403.patch new file mode 100644 index 0000000..0012cc8 --- /dev/null +++ b/SOURCES/libxslt-1.1.34-CVE-2023-40403.patch @@ -0,0 +1,1142 @@ +From 2d66370173d200bc84bea6823c50edf963f6d522 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:29:57 +0200 +Subject: [PATCH 1/6] Infrastructure to store extra data in source nodes + +Provide a mechanism to store bit flags in nodes from the source +document. This will later be used to store key and id status. + +Provide a function to find the psvi member of a node. + +Revert any changes to the source document after the transformation. +--- + libxslt/transform.c | 34 ++++++++++ + libxslt/xsltInternals.h | 1 + + libxslt/xsltutils.c | 135 ++++++++++++++++++++++++++++++++++++++++ + libxslt/xsltutils.h | 15 +++++ + 4 files changed, 185 insertions(+) + +diff --git a/libxslt/transform.c b/libxslt/transform.c +index d1c47932..c806cad0 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -5849,6 +5849,37 @@ xsltCountKeys(xsltTransformContextPtr ctxt) + return(ctxt->nbKeys); + } + ++/** ++ * xsltCleanupSourceDoc: ++ * @doc: Document ++ * ++ * Resets source node flags and ids stored in 'psvi' member. ++ */ ++static void ++xsltCleanupSourceDoc(xmlDocPtr doc) { ++ xmlNodePtr cur = (xmlNodePtr) doc; ++ void **psviPtr; ++ ++ while (1) { ++ xsltClearSourceNodeFlags(cur, XSLT_SOURCE_NODE_MASK); ++ psviPtr = xsltGetPSVIPtr(cur); ++ if (psviPtr) ++ *psviPtr = NULL; ++ ++ if (cur->children != NULL && cur->type != XML_ENTITY_REF_NODE) { ++ cur = cur->children; ++ } else { ++ while (cur->next == NULL) { ++ cur = cur->parent; ++ if (cur == (xmlNodePtr) doc) ++ return; ++ } ++ ++ cur = cur->next; ++ } ++ } ++} ++ + /** + * xsltApplyStylesheetInternal: + * @style: a parsed XSLT stylesheet +@@ -6247,6 +6278,9 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, + printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); + #endif + ++ if (ctxt->sourceDocDirty) ++ xsltCleanupSourceDoc(doc); ++ + if ((ctxt != NULL) && (userCtxt == NULL)) + xsltFreeTransformContext(ctxt); + +diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h +index 14a971aa..963c1417 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1782,6 +1782,7 @@ struct _xsltTransformContext { + int maxTemplateVars; + unsigned long opLimit; + unsigned long opCount; ++ int sourceDocDirty; + }; + + /** +diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c +index 94097b9d..2590dc7c 100644 +--- a/libxslt/xsltutils.c ++++ b/libxslt/xsltutils.c +@@ -1798,6 +1798,141 @@ xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, + return 0; + } + ++/** ++ * xsltGetSourceNodeFlags: ++ * @node: Node from source document ++ * ++ * Returns the flags for a source node. ++ */ ++int ++xsltGetSourceNodeFlags(xmlNodePtr node) { ++ /* ++ * Squeeze the bit flags into the upper bits of ++ * ++ * - 'int properties' member in struct _xmlDoc ++ * - 'xmlAttributeType atype' member in struct _xmlAttr ++ * - 'unsigned short extra' member in struct _xmlNode ++ */ ++ switch (node->type) { ++ case XML_DOCUMENT_NODE: ++ case XML_HTML_DOCUMENT_NODE: ++ return ((xmlDocPtr) node)->properties >> 27; ++ ++ case XML_ATTRIBUTE_NODE: ++ return ((xmlAttrPtr) node)->atype >> 27; ++ ++ case XML_ELEMENT_NODE: ++ case XML_TEXT_NODE: ++ case XML_CDATA_SECTION_NODE: ++ case XML_PI_NODE: ++ case XML_COMMENT_NODE: ++ return node->extra >> 12; ++ ++ default: ++ return 0; ++ } ++} ++ ++/** ++ * xsltSetSourceNodeFlags: ++ * @node: Node from source document ++ * @flags: Flags ++ * ++ * Sets the specified flags to 1. ++ * ++ * Returns 0 on success, -1 on error. ++ */ ++int ++xsltSetSourceNodeFlags(xsltTransformContextPtr ctxt, xmlNodePtr node, ++ int flags) { ++ if (node->doc == ctxt->initialContextDoc) ++ ctxt->sourceDocDirty = 1; ++ ++ switch (node->type) { ++ case XML_DOCUMENT_NODE: ++ case XML_HTML_DOCUMENT_NODE: ++ ((xmlDocPtr) node)->properties |= flags << 27; ++ return 0; ++ ++ case XML_ATTRIBUTE_NODE: ++ ((xmlAttrPtr) node)->atype |= flags << 27; ++ return 0; ++ ++ case XML_ELEMENT_NODE: ++ case XML_TEXT_NODE: ++ case XML_CDATA_SECTION_NODE: ++ case XML_PI_NODE: ++ case XML_COMMENT_NODE: ++ node->extra |= flags << 12; ++ return 0; ++ ++ default: ++ return -1; ++ } ++} ++ ++/** ++ * xsltClearSourceNodeFlags: ++ * @node: Node from source document ++ * @flags: Flags ++ * ++ * Sets the specified flags to 0. ++ * ++ * Returns 0 on success, -1 on error. ++ */ ++int ++xsltClearSourceNodeFlags(xmlNodePtr node, int flags) { ++ switch (node->type) { ++ case XML_DOCUMENT_NODE: ++ case XML_HTML_DOCUMENT_NODE: ++ ((xmlDocPtr) node)->properties &= ~(flags << 27); ++ return 0; ++ ++ case XML_ATTRIBUTE_NODE: ++ ((xmlAttrPtr) node)->atype &= ~(flags << 27); ++ return 0; ++ ++ case XML_ELEMENT_NODE: ++ case XML_TEXT_NODE: ++ case XML_CDATA_SECTION_NODE: ++ case XML_PI_NODE: ++ case XML_COMMENT_NODE: ++ node->extra &= ~(flags << 12); ++ return 0; ++ ++ default: ++ return -1; ++ } ++} ++ ++/** ++ * xsltGetPSVIPtr: ++ * @cur: Node ++ * ++ * Returns a pointer to the psvi member of a node or NULL on error. ++ */ ++void ** ++xsltGetPSVIPtr(xmlNodePtr cur) { ++ switch (cur->type) { ++ case XML_DOCUMENT_NODE: ++ case XML_HTML_DOCUMENT_NODE: ++ return &((xmlDocPtr) cur)->psvi; ++ ++ case XML_ATTRIBUTE_NODE: ++ return &((xmlAttrPtr) cur)->psvi; ++ ++ case XML_ELEMENT_NODE: ++ case XML_TEXT_NODE: ++ case XML_CDATA_SECTION_NODE: ++ case XML_PI_NODE: ++ case XML_COMMENT_NODE: ++ return &cur->psvi; ++ ++ default: ++ return NULL; ++ } ++} ++ + #ifdef WITH_PROFILER + + /************************************************************************ +diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h +index ea6c3740..defc1596 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -247,6 +247,20 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + const xmlChar *str, + int flags); + ++#ifdef IN_LIBXSLT ++#define XSLT_SOURCE_NODE_MASK 15 ++int ++xsltGetSourceNodeFlags(xmlNodePtr node); ++int ++xsltSetSourceNodeFlags(xsltTransformContextPtr ctxt, xmlNodePtr node, ++ int flags); ++int ++xsltClearSourceNodeFlags(xmlNodePtr node, int flags); ++void ** ++xsltGetPSVIPtr(xmlNodePtr cur); ++#endif ++ ++#ifdef WITH_PROFILER + /* + * Profiling. + */ +@@ -260,6 +274,7 @@ XSLTPUBFUN long XSLTCALL + xsltTimestamp (void); + XSLTPUBFUN void XSLTCALL + xsltCalibrateAdjust (long delta); ++#endif /* WITH_PROFILER */ + + /** + * XSLT_TIMESTAMP_TICS_PER_SEC: +-- +2.53.0 + + +From 9d667a7404e5576ed3c1653db32691c3eaa3f560 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:34:47 +0200 +Subject: [PATCH 2/6] Store key status of source nodes as bit flag + +This frees up the psvi member. +--- + libxslt/keys.c | 19 +------------------ + libxslt/pattern.c | 37 ++----------------------------------- + libxslt/xsltutils.h | 1 + + 3 files changed, 4 insertions(+), 53 deletions(-) + +diff --git a/libxslt/keys.c b/libxslt/keys.c +index ecef5382..3a134ab5 100644 +--- a/libxslt/keys.c ++++ b/libxslt/keys.c +@@ -834,24 +834,7 @@ fprintf(stderr, "xsltInitCtxtKey %s : %d\n", keyDef->name, ctxt->keyInitLevel); + */ + xmlXPathNodeSetAdd(keylist, cur); + } +- switch (cur->type) { +- case XML_ELEMENT_NODE: +- case XML_TEXT_NODE: +- case XML_CDATA_SECTION_NODE: +- case XML_PI_NODE: +- case XML_COMMENT_NODE: +- cur->psvi = keyDef; +- break; +- case XML_ATTRIBUTE_NODE: +- ((xmlAttrPtr) cur)->psvi = keyDef; +- break; +- case XML_DOCUMENT_NODE: +- case XML_HTML_DOCUMENT_NODE: +- ((xmlDocPtr) cur)->psvi = keyDef; +- break; +- default: +- break; +- } ++ xsltSetSourceNodeFlags(ctxt, cur, XSLT_SOURCE_NODE_HAS_KEY); + xmlFree(str); + str = NULL; + +diff --git a/libxslt/pattern.c b/libxslt/pattern.c +index c6496732..7c745bc2 100644 +--- a/libxslt/pattern.c ++++ b/libxslt/pattern.c +@@ -2368,7 +2368,6 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, + const xmlChar *name = NULL; + xsltCompMatchPtr list = NULL; + float priority; +- int keyed = 0; + + if ((ctxt == NULL) || (node == NULL)) + return(NULL); +@@ -2446,37 +2445,25 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, + list = curstyle->rootMatch; + else + list = curstyle->elemMatch; +- if (node->psvi != NULL) keyed = 1; + break; + case XML_ATTRIBUTE_NODE: { +- xmlAttrPtr attr; +- + list = curstyle->attrMatch; +- attr = (xmlAttrPtr) node; +- if (attr->psvi != NULL) keyed = 1; + break; + } + case XML_PI_NODE: + list = curstyle->piMatch; +- if (node->psvi != NULL) keyed = 1; + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: { +- xmlDocPtr doc; +- + list = curstyle->rootMatch; +- doc = (xmlDocPtr) node; +- if (doc->psvi != NULL) keyed = 1; + break; + } + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + list = curstyle->textMatch; +- if (node->psvi != NULL) keyed = 1; + break; + case XML_COMMENT_NODE: + list = curstyle->commentMatch; +- if (node->psvi != NULL) keyed = 1; + break; + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: +@@ -2537,7 +2524,7 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, + } + + keyed_match: +- if (keyed) { ++ if (xsltGetSourceNodeFlags(node) & XSLT_SOURCE_NODE_HAS_KEY) { + list = curstyle->keyMatch; + while ((list != NULL) && + ((ret == NULL) || (list->priority > priority))) { +@@ -2562,27 +2549,7 @@ keyed_match: + if (xsltComputeAllKeys(ctxt, node) == -1) + goto error; + +- switch (node->type) { +- case XML_ELEMENT_NODE: +- if (node->psvi != NULL) keyed = 1; +- break; +- case XML_ATTRIBUTE_NODE: +- if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1; +- break; +- case XML_TEXT_NODE: +- case XML_CDATA_SECTION_NODE: +- case XML_COMMENT_NODE: +- case XML_PI_NODE: +- if (node->psvi != NULL) keyed = 1; +- break; +- case XML_DOCUMENT_NODE: +- case XML_HTML_DOCUMENT_NODE: +- if (((xmlDocPtr) node)->psvi != NULL) keyed = 1; +- break; +- default: +- break; +- } +- if (keyed) ++ if (xsltGetSourceNodeFlags(node) & XSLT_SOURCE_NODE_HAS_KEY) + goto keyed_match; + } + if (ret != NULL) +diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h +index defc1596..d72fc470 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -249,6 +249,7 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + + #ifdef IN_LIBXSLT + #define XSLT_SOURCE_NODE_MASK 15 ++#define XSLT_SOURCE_NODE_HAS_KEY 1 + int + xsltGetSourceNodeFlags(xmlNodePtr node); + int +-- +2.53.0 + + +From 1b4179ca28db463ab9196e60a6774d7ab38f12d4 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:35:37 +0200 +Subject: [PATCH 3/6] Store RVT ownership in 'compression' member + +'compression' is another unused member in struct _xmlDoc which is even +better suited to store ownership status. More importantly, this frees up +the 'psvi' member. + +This changes the public API but this feature is only required to +implement EXSLT functions. +--- + libexslt/functions.c | 2 +- + libxslt/transform.c | 8 ++++---- + libxslt/variables.c | 44 ++++++++++++++++++++--------------------- + libxslt/variables.h | 6 +++--- + libxslt/xsltInternals.h | 2 +- + 5 files changed, 31 insertions(+), 31 deletions(-) + +diff --git a/libexslt/functions.c b/libexslt/functions.c +index 2f744311..43c2aa36 100644 +--- a/libexslt/functions.c ++++ b/libexslt/functions.c +@@ -781,7 +781,7 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, + } + /* Mark as function result. */ + xsltRegisterLocalRVT(ctxt, container); +- container->psvi = XSLT_RVT_FUNC_RESULT; ++ container->compression = XSLT_RVT_FUNC_RESULT; + + oldInsert = ctxt->insert; + ctxt->insert = (xmlNodePtr) container; +diff --git a/libxslt/transform.c b/libxslt/transform.c +index c806cad0..8a9fa294 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -2317,17 +2317,17 @@ xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) + do { + tmp = cur; + cur = (xmlDocPtr) cur->next; +- if (tmp->psvi == XSLT_RVT_LOCAL) { ++ if (tmp->compression == XSLT_RVT_LOCAL) { + xsltReleaseRVT(ctxt, tmp); +- } else if (tmp->psvi == XSLT_RVT_GLOBAL) { ++ } else if (tmp->compression == XSLT_RVT_GLOBAL) { + xsltRegisterPersistRVT(ctxt, tmp); +- } else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) { ++ } else if (tmp->compression == XSLT_RVT_FUNC_RESULT) { + /* + * This will either register the RVT again or move it to the + * context variable. + */ + xsltRegisterLocalRVT(ctxt, tmp); +- tmp->psvi = XSLT_RVT_FUNC_RESULT; ++ tmp->compression = XSLT_RVT_FUNC_RESULT; + } else { + xmlGenericError(xmlGenericErrorContext, + "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", +diff --git a/libxslt/variables.c b/libxslt/variables.c +index 4c972a41..dab0bab2 100644 +--- a/libxslt/variables.c ++++ b/libxslt/variables.c +@@ -123,7 +123,7 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + return(-1); + + RVT->prev = NULL; +- RVT->psvi = XSLT_RVT_LOCAL; ++ RVT->compression = XSLT_RVT_LOCAL; + + /* + * We'll restrict the lifetime of user-created fragments +@@ -163,7 +163,7 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + return(-1); + + RVT->prev = NULL; +- RVT->psvi = XSLT_RVT_LOCAL; ++ RVT->compression = XSLT_RVT_LOCAL; + + /* + * When evaluating "select" expressions of xsl:variable +@@ -255,7 +255,7 @@ xsltExtensionInstructionResultRegister( + * Returns 0 in case of success and -1 in case of error. + */ + int +-xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) { ++xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) { + int i; + xmlNodePtr cur; + xmlDocPtr doc; +@@ -302,34 +302,34 @@ xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) { + return(-1); + } + if (doc->name && (doc->name[0] == ' ') && +- doc->psvi != XSLT_RVT_GLOBAL) { ++ doc->compression != XSLT_RVT_GLOBAL) { + /* + * This is a result tree fragment. +- * We store ownership information in the @psvi field. ++ * We store ownership information in the @compression field. + * TODO: How do we know if this is a doc acquired via the + * document() function? + */ + #ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, +- "Flagging RVT %p: %p -> %p\n", doc, doc->psvi, val)); ++ "Flagging RVT %p: %d -> %d\n", doc, doc->compression, val)); + #endif + + if (val == XSLT_RVT_LOCAL) { +- if (doc->psvi == XSLT_RVT_FUNC_RESULT) +- doc->psvi = XSLT_RVT_LOCAL; ++ if (doc->compression == XSLT_RVT_FUNC_RESULT) ++ doc->compression = XSLT_RVT_LOCAL; + } else if (val == XSLT_RVT_GLOBAL) { +- if (doc->psvi != XSLT_RVT_LOCAL) { ++ if (doc->compression != XSLT_RVT_LOCAL) { + xmlGenericError(xmlGenericErrorContext, +- "xsltFlagRVTs: Invalid transition %p => GLOBAL\n", +- doc->psvi); +- doc->psvi = XSLT_RVT_GLOBAL; ++ "xsltFlagRVTs: Invalid transition %d => GLOBAL\n", ++ doc->compression); ++ doc->compression = XSLT_RVT_GLOBAL; + return(-1); + } + + /* Will be registered as persistant in xsltReleaseLocalRVTs. */ +- doc->psvi = XSLT_RVT_GLOBAL; ++ doc->compression = XSLT_RVT_GLOBAL; + } else if (val == XSLT_RVT_FUNC_RESULT) { +- doc->psvi = val; ++ doc->compression = val; + } + } + } +@@ -382,7 +382,7 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + /* + * Reset the ownership information. + */ +- RVT->psvi = NULL; ++ RVT->compression = 0; + + RVT->next = (xmlNodePtr) ctxt->cache->RVT; + ctxt->cache->RVT = RVT; +@@ -421,7 +421,7 @@ xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + { + if ((ctxt == NULL) || (RVT == NULL)) return(-1); + +- RVT->psvi = XSLT_RVT_GLOBAL; ++ RVT->compression = XSLT_RVT_GLOBAL; + RVT->prev = NULL; + RVT->next = (xmlNodePtr) ctxt->persistRVT; + if (ctxt->persistRVT != NULL) +@@ -580,15 +580,15 @@ xsltFreeStackElem(xsltStackElemPtr elem) { + cur = elem->fragment; + elem->fragment = (xmlDocPtr) cur->next; + +- if (cur->psvi == XSLT_RVT_LOCAL) { ++ if (cur->compression == XSLT_RVT_LOCAL) { + xsltReleaseRVT(elem->context, cur); +- } else if (cur->psvi == XSLT_RVT_FUNC_RESULT) { ++ } else if (cur->compression == XSLT_RVT_FUNC_RESULT) { + xsltRegisterLocalRVT(elem->context, cur); +- cur->psvi = XSLT_RVT_FUNC_RESULT; ++ cur->compression = XSLT_RVT_FUNC_RESULT; + } else { + xmlGenericError(xmlGenericErrorContext, +- "xsltFreeStackElem: Unexpected RVT flag %p\n", +- cur->psvi); ++ "xsltFreeStackElem: Unexpected RVT flag %d\n", ++ cur->compression); + } + } + } +@@ -989,7 +989,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, + * the Result Tree Fragment. + */ + variable->fragment = container; +- container->psvi = XSLT_RVT_LOCAL; ++ container->compression = XSLT_RVT_LOCAL; + + oldOutput = ctxt->output; + oldInsert = ctxt->insert; +diff --git a/libxslt/variables.h b/libxslt/variables.h +index 039288fb..e2adee0f 100644 +--- a/libxslt/variables.h ++++ b/libxslt/variables.h +@@ -43,7 +43,7 @@ extern "C" { + * + * RVT is destroyed after the current instructions ends. + */ +-#define XSLT_RVT_LOCAL ((void *)1) ++#define XSLT_RVT_LOCAL 1 + + /** + * XSLT_RVT_FUNC_RESULT: +@@ -52,14 +52,14 @@ extern "C" { + * destroyed after exiting a template and will be reset to XSLT_RVT_LOCAL or + * XSLT_RVT_VARIABLE in the template that receives the return value. + */ +-#define XSLT_RVT_FUNC_RESULT ((void *)2) ++#define XSLT_RVT_FUNC_RESULT 2 + + /** + * XSLT_RVT_GLOBAL: + * + * RVT is part of a global variable. + */ +-#define XSLT_RVT_GLOBAL ((void *)3) ++#define XSLT_RVT_GLOBAL 3 + + /* + * Interfaces for the variable module. +diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h +index 963c1417..8bf4da35 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1912,7 +1912,7 @@ XSLTPUBFUN int XSLTCALL + xsltFlagRVTs( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj, +- void *val); ++ int val); + XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); + XSLTPUBFUN void XSLTCALL +-- +2.53.0 + + +From a0ffe3696fc422f5d4471dd5c2a60f9b6786430a Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 13:35:23 +0200 +Subject: [PATCH 4/6] Make generate-id() deterministic + +Rework the generate-id() function to return deterministic values. We use +a simple incrementing counter and store ids in the 'psvi' member of +nodes which was freed up by previous commits. The presence of an id is +indicated by a new "source node" flag. + +This fixes long-standing problems with reproducible builds, see +https://bugzilla.gnome.org/show_bug.cgi?id=751621 + +This also hardens security, as the old implementation leaked the +difference between a heap and a global pointer, see +https://bugs.chromium.org/p/chromium/issues/detail?id=1356211 + +The old implementation could also generate the same id for dynamically +created nodes which happened to reuse the same memory. Ids for namespace +nodes were completely broken. They now use the id of the parent element +together with the hex-encoded namespace prefix. +--- + libxslt/functions.c | 107 +++++++++++++++++++++++++----- + libxslt/xsltInternals.h | 1 + + libxslt/xsltutils.h | 1 + + tests/REC/test-12.4-1.out | 11 +++ + tests/REC/test-12.4-1.xml | 6 ++ + tests/REC/test-12.4-1.xsl | 38 +++++++++++ + tests/exslt/common/dynamic-id.out | 13 ++++ + tests/exslt/common/dynamic-id.xml | 1 + + tests/exslt/common/dynamic-id.xsl | 29 ++++++++ + 9 files changed, 191 insertions(+), 16 deletions(-) + create mode 100644 tests/REC/test-12.4-1.out + create mode 100644 tests/REC/test-12.4-1.xml + create mode 100644 tests/REC/test-12.4-1.xsl + create mode 100644 tests/exslt/common/dynamic-id.out + create mode 100644 tests/exslt/common/dynamic-id.xml + create mode 100644 tests/exslt/common/dynamic-id.xsl + +diff --git a/libxslt/functions.c b/libxslt/functions.c +index b350545a..dd8bf7af 100644 +--- a/libxslt/functions.c ++++ b/libxslt/functions.c +@@ -681,11 +681,16 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) + */ + void + xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ +- static char base_address; ++ xsltTransformContextPtr tctxt; + xmlNodePtr cur = NULL; + xmlXPathObjectPtr obj = NULL; +- long val; +- xmlChar str[30]; ++ char *str; ++ const xmlChar *nsPrefix = NULL; ++ void **psviPtr; ++ unsigned long id; ++ size_t size, nsPrefixSize; ++ ++ tctxt = xsltXPathGetTransformContext(ctxt); + + if (nargs == 0) { + cur = ctxt->context->node; +@@ -695,16 +700,15 @@ xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ + + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { + ctxt->error = XPATH_INVALID_TYPE; +- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, ++ xsltTransformError(tctxt, NULL, NULL, + "generate-id() : invalid arg expecting a node-set\n"); +- return; ++ goto out; + } + obj = valuePop(ctxt); + nodelist = obj->nodesetval; + if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { +- xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPathNewCString("")); +- return; ++ goto out; + } + cur = nodelist->nodeTab[0]; + for (i = 1;i < nodelist->nodeNr;i++) { +@@ -713,22 +717,93 @@ xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ + cur = nodelist->nodeTab[i]; + } + } else { +- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, ++ xsltTransformError(tctxt, NULL, NULL, + "generate-id() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; +- return; ++ goto out; ++ } ++ ++ size = 30; /* for "id%lu" */ ++ ++ if (cur->type == XML_NAMESPACE_DECL) { ++ xmlNsPtr ns = (xmlNsPtr) cur; ++ ++ nsPrefix = ns->prefix; ++ if (nsPrefix == NULL) ++ nsPrefix = BAD_CAST ""; ++ nsPrefixSize = xmlStrlen(nsPrefix); ++ /* For "ns" and hex-encoded string */ ++ size += nsPrefixSize * 2 + 2; ++ ++ /* Parent is stored in 'next'. */ ++ cur = (xmlNodePtr) ns->next; ++ } ++ ++ psviPtr = xsltGetPSVIPtr(cur); ++ if (psviPtr == NULL) { ++ xsltTransformError(tctxt, NULL, NULL, ++ "generate-id(): invalid node type %d\n", cur->type); ++ ctxt->error = XPATH_INVALID_TYPE; ++ goto out; + } + +- if (obj) +- xmlXPathFreeObject(obj); ++ if (xsltGetSourceNodeFlags(cur) & XSLT_SOURCE_NODE_HAS_ID) { ++ id = (unsigned long) *psviPtr; ++ } else { ++ if (cur->type == XML_TEXT_NODE && cur->line == USHRT_MAX) { ++ /* Text nodes store big line numbers in psvi. */ ++ cur->line = 0; ++ } else if (*psviPtr != NULL) { ++ xsltTransformError(tctxt, NULL, NULL, ++ "generate-id(): psvi already set\n"); ++ ctxt->error = XPATH_MEMORY_ERROR; ++ goto out; ++ } ++ ++ if (tctxt->currentId == ULONG_MAX) { ++ xsltTransformError(tctxt, NULL, NULL, ++ "generate-id(): id overflow\n"); ++ ctxt->error = XPATH_MEMORY_ERROR; ++ goto out; ++ } ++ ++ id = ++tctxt->currentId; ++ *psviPtr = (void *) id; ++ xsltSetSourceNodeFlags(tctxt, cur, XSLT_SOURCE_NODE_HAS_ID); ++ } + +- val = (long)((char *)cur - (char *)&base_address); +- if (val >= 0) { +- snprintf((char *)str, sizeof(str), "idp%ld", val); ++ str = xmlMalloc(size); ++ if (str == NULL) { ++ xsltTransformError(tctxt, NULL, NULL, ++ "generate-id(): out of memory\n"); ++ ctxt->error = XPATH_MEMORY_ERROR; ++ goto out; ++ } ++ if (nsPrefix == NULL) { ++ snprintf(str, size, "id%lu", id); + } else { +- snprintf((char *)str, sizeof(str), "idm%ld", -val); ++ size_t i, j; ++ ++ snprintf(str, size, "id%luns", id); ++ ++ /* ++ * Only ASCII alphanumerics are allowed, so we hex-encode the prefix. ++ */ ++ j = strlen(str); ++ for (i = 0; i < nsPrefixSize; i++) { ++ int v; ++ ++ v = nsPrefix[i] >> 4; ++ str[j++] = v < 10 ? '0' + v : 'A' + (v - 10); ++ v = nsPrefix[i] & 15; ++ str[j++] = v < 10 ? '0' + v : 'A' + (v - 10); ++ } ++ str[j] = '\0'; + } +- valuePush(ctxt, xmlXPathNewString(str)); ++ valuePush(ctxt, xmlXPathWrapString(BAD_CAST str)); ++ ++out: ++ xmlXPathFreeObject(obj); + } + + /** +diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h +index 8bf4da35..a5c62d96 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1783,6 +1783,7 @@ struct _xsltTransformContext { + unsigned long opLimit; + unsigned long opCount; + int sourceDocDirty; ++ unsigned long currentId; /* For generate-id() */ + }; + + /** +diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h +index d72fc470..4ac4640e 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -250,6 +250,7 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + #ifdef IN_LIBXSLT + #define XSLT_SOURCE_NODE_MASK 15 + #define XSLT_SOURCE_NODE_HAS_KEY 1 ++#define XSLT_SOURCE_NODE_HAS_ID 2 + int + xsltGetSourceNodeFlags(xmlNodePtr node); + int +diff --git a/tests/REC/test-12.4-1.out b/tests/REC/test-12.4-1.out +new file mode 100644 +index 00000000..237a9f27 +--- /dev/null ++++ b/tests/REC/test-12.4-1.out +@@ -0,0 +1,11 @@ ++ ++ ++ id1 ++ id2 ++ id3 ++ id2ns ++ id2nsC3A4C3B6C3BC ++ id4 ++ id5 ++ id6 ++ +diff --git a/tests/REC/test-12.4-1.xml b/tests/REC/test-12.4-1.xml +new file mode 100644 +index 00000000..84484f66 +--- /dev/null ++++ b/tests/REC/test-12.4-1.xml +@@ -0,0 +1,6 @@ ++ ++ ++ text ++ ++ ++ +diff --git a/tests/REC/test-12.4-1.xsl b/tests/REC/test-12.4-1.xsl +new file mode 100644 +index 00000000..5cf5dd33 +--- /dev/null ++++ b/tests/REC/test-12.4-1.xsl +@@ -0,0 +1,38 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/exslt/common/dynamic-id.out b/tests/exslt/common/dynamic-id.out +new file mode 100644 +index 00000000..1b7b7bad +--- /dev/null ++++ b/tests/exslt/common/dynamic-id.out +@@ -0,0 +1,13 @@ ++ ++ ++ id1 ++ id2 ++ id3 ++ id4 ++ id5 ++ id6 ++ id7 ++ id8 ++ id9 ++ id10 ++ +diff --git a/tests/exslt/common/dynamic-id.xml b/tests/exslt/common/dynamic-id.xml +new file mode 100644 +index 00000000..69d62f2c +--- /dev/null ++++ b/tests/exslt/common/dynamic-id.xml +@@ -0,0 +1 @@ ++ +diff --git a/tests/exslt/common/dynamic-id.xsl b/tests/exslt/common/dynamic-id.xsl +new file mode 100644 +index 00000000..8478f6af +--- /dev/null ++++ b/tests/exslt/common/dynamic-id.xsl +@@ -0,0 +1,29 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +2.53.0 + + +From 2ea8289b99ff73d6614fab56b70957ff8b7bdec8 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 21:37:44 +0200 +Subject: [PATCH 5/6] Clean up attributes in source doc + +Also make bit flag constants unsigned to avoid implicit-conversion +warnings. +--- + libxslt/transform.c | 10 ++++++++++ + libxslt/xsltutils.h | 6 +++--- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/libxslt/transform.c b/libxslt/transform.c +index 8a9fa294..6c5f048f 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -5866,6 +5866,16 @@ xsltCleanupSourceDoc(xmlDocPtr doc) { + if (psviPtr) + *psviPtr = NULL; + ++ if (cur->type == XML_ELEMENT_NODE) { ++ xmlAttrPtr prop = cur->properties; ++ ++ while (prop) { ++ prop->atype &= ~(XSLT_SOURCE_NODE_MASK << 27); ++ prop->psvi = NULL; ++ prop = prop->next; ++ } ++ } ++ + if (cur->children != NULL && cur->type != XML_ENTITY_REF_NODE) { + cur = cur->children; + } else { +diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h +index 4ac4640e..341d2512 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -248,9 +248,9 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + int flags); + + #ifdef IN_LIBXSLT +-#define XSLT_SOURCE_NODE_MASK 15 +-#define XSLT_SOURCE_NODE_HAS_KEY 1 +-#define XSLT_SOURCE_NODE_HAS_ID 2 ++#define XSLT_SOURCE_NODE_MASK 15u ++#define XSLT_SOURCE_NODE_HAS_KEY 1u ++#define XSLT_SOURCE_NODE_HAS_ID 2u + int + xsltGetSourceNodeFlags(xmlNodePtr node); + int +-- +2.53.0 + + +From 1b90c3fc073bc00b016abe12b66e663d780fc1e0 Mon Sep 17 00:00:00 2001 +From: David Kilzer +Date: Sat, 24 May 2025 15:06:42 -0700 +Subject: [PATCH 6/6] libxslt: Type confusion in xmlNode.psvi between + stylesheet and source nodes + +* libxslt/functions.c: +(xsltDocumentFunctionLoadDocument): +- Implement fix suggested by Ivan Fratric. This copies the xmlDoc, + calls xsltCleanupSourceDoc() to remove pvsi fields, then adds the + xmlDoc to tctxt->docList. +- Add error handling for functions that may return NULL. +* libxslt/transform.c: +- Remove static keyword so this can be called from + xsltDocumentFunctionLoadDocument(). +* libxslt/transformInternals.h: Add. +(xsltCleanupSourceDoc): Add declaration. + +Fixes #139. +--- + libxslt/functions.c | 16 +++++++++++++++- + libxslt/transform.c | 3 ++- + libxslt/transformInternals.h | 9 +++++++++ + 3 files changed, 26 insertions(+), 2 deletions(-) + create mode 100644 libxslt/transformInternals.h + +diff --git a/libxslt/functions.c b/libxslt/functions.c +index dd8bf7af..e821e3cd 100644 +--- a/libxslt/functions.c ++++ b/libxslt/functions.c +@@ -41,6 +41,7 @@ + #include "numbersInternals.h" + #include "keys.h" + #include "documents.h" ++#include "transformInternals.h" + + #ifdef WITH_XSLT_DEBUG + #define WITH_XSLT_DEBUG_FUNCTION +@@ -152,7 +153,20 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI) + /* + * This selects the stylesheet's doc itself. + */ +- doc = tctxt->style->doc; ++ doc = xmlCopyDoc(tctxt->style->doc, 1); ++ if (doc == NULL) { ++ xsltTransformError(tctxt, NULL, NULL, ++ "document() : failed to copy style doc\n"); ++ goto out_fragment; ++ } ++ xsltCleanupSourceDoc(doc); /* Remove psvi fields. */ ++ idoc = xsltNewDocument(tctxt, doc); ++ if (idoc == NULL) { ++ xsltTransformError(tctxt, NULL, NULL, ++ "document() : failed to create xsltDocument\n"); ++ xmlFreeDoc(doc); ++ goto out_fragment; ++ } + } else { + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + +diff --git a/libxslt/transform.c b/libxslt/transform.c +index 6c5f048f..74a3b590 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -42,6 +42,7 @@ + #include "xsltutils.h" + #include "pattern.h" + #include "transform.h" ++#include "transformInternals.h" + #include "variables.h" + #include "numbersInternals.h" + #include "namespaces.h" +@@ -5855,7 +5856,7 @@ xsltCountKeys(xsltTransformContextPtr ctxt) + * + * Resets source node flags and ids stored in 'psvi' member. + */ +-static void ++void + xsltCleanupSourceDoc(xmlDocPtr doc) { + xmlNodePtr cur = (xmlNodePtr) doc; + void **psviPtr; +diff --git a/libxslt/transformInternals.h b/libxslt/transformInternals.h +new file mode 100644 +index 00000000..d0f42823 +--- /dev/null ++++ b/libxslt/transformInternals.h +@@ -0,0 +1,9 @@ ++/* ++ * Summary: set of internal interfaces for the XSLT engine transformation part. ++ * ++ * Copy: See Copyright for the status of this software. ++ * ++ * Author: David Kilzer ++ */ ++ ++void xsltCleanupSourceDoc(xmlDocPtr doc); +-- +2.53.0 + diff --git a/SOURCES/libxslt-1.1.34-CVE-2024-55549.patch b/SOURCES/libxslt-1.1.34-CVE-2024-55549.patch new file mode 100644 index 0000000..64c0b91 --- /dev/null +++ b/SOURCES/libxslt-1.1.34-CVE-2024-55549.patch @@ -0,0 +1,103 @@ +From 5b3b3151e4af0f6c234c97e01e05cf6edc9eceab Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Tue, 21 Mar 2023 12:19:50 +0100 +Subject: [PATCH 1/2] malloc-fail: Fix memory leak in exclPrefixPush + +Found by OSS-Fuzz, see #84. +--- + libxslt/xslt.c | 24 ++++++++---------------- + 1 file changed, 8 insertions(+), 16 deletions(-) + +diff --git a/libxslt/xslt.c b/libxslt/xslt.c +index 7a1ce011..6d4126a1 100644 +--- a/libxslt/xslt.c ++++ b/libxslt/xslt.c +@@ -157,31 +157,23 @@ exclPrefixPush(xsltStylesheetPtr style, xmlChar * value) + { + int i; + +- if (style->exclPrefixMax == 0) { +- style->exclPrefixMax = 4; +- style->exclPrefixTab = +- (xmlChar * *)xmlMalloc(style->exclPrefixMax * +- sizeof(style->exclPrefixTab[0])); +- if (style->exclPrefixTab == NULL) { +- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); +- return (-1); +- } +- } + /* do not push duplicates */ + for (i = 0;i < style->exclPrefixNr;i++) { + if (xmlStrEqual(style->exclPrefixTab[i], value)) + return(-1); + } + if (style->exclPrefixNr >= style->exclPrefixMax) { +- style->exclPrefixMax *= 2; +- style->exclPrefixTab = +- (xmlChar * *)xmlRealloc(style->exclPrefixTab, +- style->exclPrefixMax * +- sizeof(style->exclPrefixTab[0])); +- if (style->exclPrefixTab == NULL) { ++ xmlChar **tmp; ++ size_t max = style->exclPrefixMax ? style->exclPrefixMax * 2 : 4; ++ ++ tmp = xmlRealloc(style->exclPrefixTab, ++ max * sizeof(style->exclPrefixTab[0])); ++ if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return (-1); + } ++ style->exclPrefixTab = tmp; ++ style->exclPrefixMax = max; + } + style->exclPrefixTab[style->exclPrefixNr] = value; + style->exclPrefix = value; +-- +2.49.0 + + +From 43c2b70b12717940ff9141c3bc2dc7f3a49df2b5 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Thu, 5 Dec 2024 12:43:19 +0100 +Subject: [PATCH 2/2] [CVE-2024-55549] Fix UAF related to excluded namespaces + +Definitions of excluded namespaces could be deleted in +xsltParseTemplateContent. Store excluded namespace URIs in the +stylesheet's dictionary instead of referencing the namespace definition. + +Thanks to Ivan Fratric for the report! + +Fixes #127. +--- + libxslt/xslt.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/libxslt/xslt.c b/libxslt/xslt.c +index 6d4126a1..11681a13 100644 +--- a/libxslt/xslt.c ++++ b/libxslt/xslt.c +@@ -153,10 +153,20 @@ xsltParseContentError(xsltStylesheetPtr style, + * in case of error + */ + static int +-exclPrefixPush(xsltStylesheetPtr style, xmlChar * value) ++exclPrefixPush(xsltStylesheetPtr style, xmlChar * orig) + { ++ xmlChar *value; + int i; + ++ /* ++ * orig can come from a namespace definition on a node which ++ * could be deleted later, for example in xsltParseTemplateContent. ++ * Store the string in stylesheet's dict to avoid use after free. ++ */ ++ value = (xmlChar *) xmlDictLookup(style->dict, orig, -1); ++ if (value == NULL) ++ return(-1); ++ + /* do not push duplicates */ + for (i = 0;i < style->exclPrefixNr;i++) { + if (xmlStrEqual(style->exclPrefixTab[i], value)) +-- +2.49.0 + diff --git a/SOURCES/libxslt-1.1.34-CVE-2025-10911.patch b/SOURCES/libxslt-1.1.34-CVE-2025-10911.patch new file mode 100644 index 0000000..c892fd4 --- /dev/null +++ b/SOURCES/libxslt-1.1.34-CVE-2025-10911.patch @@ -0,0 +1,711 @@ +From 27c7c5bb710b094a75d7f0cf6dc1363182ae0c78 Mon Sep 17 00:00:00 2001 +From: Daniel Cheng +Date: Thu, 5 Jun 2025 09:43:53 -0700 +Subject: [PATCH] Use a dedicated node type to maintain the list of cached RVTs + +While evaluating a stylesheet, result value trees (result tree fragments +in the XSLT spec) are represented as xmlDocs and cached on the transform +context in a linked list, using xmlDoc's prev and next pointers to +maintain the list. + +However, XPath evaluations can inadvertently traverse these links, which +are an implementation detail and do not reflect the actual document +structure. Using a dedicated node type avoids these unintended +traversals. + +Fixes #144. +--- + libxslt/transform.c | 87 ++++++++-------- + libxslt/variables.c | 224 +++++++++++++++++++++++++--------------- + libxslt/xsltInternals.h | 23 +++-- + 3 files changed, 199 insertions(+), 135 deletions(-) + +diff --git a/libxslt/transform.c b/libxslt/transform.c +index 74a3b590..7b13ee97 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -526,19 +526,20 @@ xsltTransformCacheFree(xsltTransformCachePtr cache) + /* + * Free tree fragments. + */ +- if (cache->RVT) { +- xmlDocPtr tmp, cur = cache->RVT; ++ if (cache->rvtList) { ++ xsltRVTListPtr tmp, cur = cache->rvtList; + while (cur) { + tmp = cur; +- cur = (xmlDocPtr) cur->next; +- if (tmp->_private != NULL) { ++ cur = cur->next; ++ if (tmp->RVT->_private != NULL) { + /* +- * Tree the document info. ++ * Free the document info. + */ +- xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private); +- xmlFree(tmp->_private); ++ xsltFreeDocumentKeys((xsltDocumentPtr) tmp->RVT->_private); ++ xmlFree(tmp->RVT->_private); + } +- xmlFreeDoc(tmp); ++ xmlFreeDoc(tmp->RVT); ++ xmlFree(tmp); + } + } + /* +@@ -2301,38 +2302,36 @@ xsltLocalVariablePush(xsltTransformContextPtr ctxt, + * are preserved; all other fragments are freed/cached. + */ + static void +-xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) ++xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xsltRVTListPtr base) + { +- xmlDocPtr cur = ctxt->localRVT, tmp; ++ xsltRVTListPtr cur = ctxt->localRVTList, tmp; + + if (cur == base) + return; +- if (cur->prev != NULL) +- xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n"); + +- /* Reset localRVT early because some RVTs might be registered again. */ +- ctxt->localRVT = base; +- if (base != NULL) +- base->prev = NULL; ++ /* Reset localRVTList early because some RVTs might be registered again. */ ++ ctxt->localRVTList = base; + + do { + tmp = cur; +- cur = (xmlDocPtr) cur->next; +- if (tmp->compression == XSLT_RVT_LOCAL) { +- xsltReleaseRVT(ctxt, tmp); +- } else if (tmp->compression == XSLT_RVT_GLOBAL) { +- xsltRegisterPersistRVT(ctxt, tmp); +- } else if (tmp->compression == XSLT_RVT_FUNC_RESULT) { ++ cur = cur->next; ++ if (tmp->RVT->compression == XSLT_RVT_LOCAL) { ++ xsltReleaseRVTList(ctxt, tmp); ++ } else if (tmp->RVT->compression == XSLT_RVT_GLOBAL) { ++ xsltRegisterPersistRVT(ctxt, tmp->RVT); ++ xmlFree(tmp); ++ } else if (tmp->RVT->compression == XSLT_RVT_FUNC_RESULT) { + /* + * This will either register the RVT again or move it to the + * context variable. + */ +- xsltRegisterLocalRVT(ctxt, tmp); +- tmp->compression = XSLT_RVT_FUNC_RESULT; ++ xsltRegisterLocalRVT(ctxt, tmp->RVT); ++ tmp->RVT->compression = XSLT_RVT_FUNC_RESULT; ++ xmlFree(tmp); + } else { + xmlGenericError(xmlGenericErrorContext, +- "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", +- tmp->psvi); ++ "xsltReleaseLocalRVTs: Unexpected RVT flag %d\n", ++ tmp->RVT->compression); + } + } while (cur != base); + } +@@ -2360,7 +2359,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; + xmlNodePtr cur, insert, copy = NULL; + int level = 0, oldVarsNr; +- xmlDocPtr oldLocalFragmentTop; ++ xsltRVTListPtr oldLocalFragmentTop; + + #ifdef XSLT_REFACTORED + xsltStylePreCompPtr info; +@@ -2406,7 +2405,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + } + ctxt->depth++; + +- oldLocalFragmentTop = ctxt->localRVT; ++ oldLocalFragmentTop = ctxt->localRVTList; + oldInsert = insert = ctxt->insert; + oldInst = oldCurInst = ctxt->inst; + oldContextNode = ctxt->node; +@@ -2640,7 +2639,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -2735,7 +2734,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -2801,7 +2800,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -2931,7 +2930,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -3110,7 +3109,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + int oldVarsBase = 0; + xmlNodePtr cur; + xsltStackElemPtr tmpParam = NULL; +- xmlDocPtr oldUserFragmentTop; ++ xsltRVTListPtr oldUserFragmentTop; + #ifdef WITH_PROFILER + long start = 0; + #endif +@@ -3158,8 +3157,8 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + return; + } + +- oldUserFragmentTop = ctxt->tmpRVT; +- ctxt->tmpRVT = NULL; ++ oldUserFragmentTop = ctxt->tmpRVTList; ++ ctxt->tmpRVTList = NULL; + + /* + * Initiate a distinct scope of local params/variables. +@@ -3270,16 +3269,16 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + * user code should now use xsltRegisterLocalRVT() instead + * of the obsolete xsltRegisterTmpRVT(). + */ +- if (ctxt->tmpRVT) { +- xmlDocPtr curdoc = ctxt->tmpRVT, tmp; ++ if (ctxt->tmpRVTList) { ++ xsltRVTListPtr curRVTList = ctxt->tmpRVTList, tmp; + +- while (curdoc != NULL) { +- tmp = curdoc; +- curdoc = (xmlDocPtr) curdoc->next; +- xsltReleaseRVT(ctxt, tmp); ++ while (curRVTList != NULL) { ++ tmp = curRVTList; ++ curRVTList = curRVTList->next; ++ xsltReleaseRVTList(ctxt, tmp); + } + } +- ctxt->tmpRVT = oldUserFragmentTop; ++ ctxt->tmpRVTList = oldUserFragmentTop; + + /* + * Pop the xsl:template declaration from the stack. +@@ -5418,7 +5417,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + + #ifdef XSLT_FAST_IF + { +- xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; ++ xsltRVTListPtr oldLocalFragmentTop = ctxt->localRVTList; + + res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp); + +@@ -5426,7 +5425,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + * Cleanup fragments created during evaluation of the + * "select" expression. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + } + +diff --git a/libxslt/variables.c b/libxslt/variables.c +index dab0bab2..f27c9cde 100644 +--- a/libxslt/variables.c ++++ b/libxslt/variables.c +@@ -47,6 +47,21 @@ static const xmlChar *xsltComputingGlobalVarMarker = + #define XSLT_VAR_IN_SELECT (1<<1) + #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) + ++static xsltRVTListPtr ++xsltRVTListCreate(void) ++{ ++ xsltRVTListPtr ret; ++ ++ ret = (xsltRVTListPtr) xmlMalloc(sizeof(xsltRVTList)); ++ if (ret == NULL) { ++ xsltTransformError(NULL, NULL, NULL, ++ "xsltRVTListCreate: malloc failed\n"); ++ return(NULL); ++ } ++ memset(ret, 0, sizeof(xsltRVTList)); ++ return(ret); ++} ++ + /************************************************************************ + * * + * Result Value Tree (Result Tree Fragment) interfaces * +@@ -64,6 +79,7 @@ static const xmlChar *xsltComputingGlobalVarMarker = + xmlDocPtr + xsltCreateRVT(xsltTransformContextPtr ctxt) + { ++ xsltRVTListPtr rvtList; + xmlDocPtr container; + + /* +@@ -76,12 +92,11 @@ xsltCreateRVT(xsltTransformContextPtr ctxt) + /* + * Reuse a RTF from the cache if available. + */ +- if (ctxt->cache->RVT) { +- container = ctxt->cache->RVT; +- ctxt->cache->RVT = (xmlDocPtr) container->next; +- /* clear the internal pointers */ +- container->next = NULL; +- container->prev = NULL; ++ if (ctxt->cache->rvtList) { ++ rvtList = ctxt->cache->rvtList; ++ container = ctxt->cache->rvtList->RVT; ++ ctxt->cache->rvtList = rvtList->next; ++ xmlFree(rvtList); + if (ctxt->cache->nbRVT > 0) + ctxt->cache->nbRVT--; + #ifdef XSLT_DEBUG_PROFILE_CACHE +@@ -119,11 +134,16 @@ xsltCreateRVT(xsltTransformContextPtr ctxt) + int + xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + { ++ xsltRVTListPtr list; ++ + if ((ctxt == NULL) || (RVT == NULL)) + return(-1); + +- RVT->prev = NULL; ++ list = xsltRVTListCreate(); ++ if (list == NULL) return(-1); ++ + RVT->compression = XSLT_RVT_LOCAL; ++ list->RVT = RVT; + + /* + * We'll restrict the lifetime of user-created fragments +@@ -131,15 +151,13 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + * var/param itself. + */ + if (ctxt->contextVariable != NULL) { +- RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; +- XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; ++ list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment; ++ XSLT_TCTXT_VARIABLE(ctxt)->fragment = list; + return(0); + } + +- RVT->next = (xmlNodePtr) ctxt->tmpRVT; +- if (ctxt->tmpRVT != NULL) +- ctxt->tmpRVT->prev = (xmlNodePtr) RVT; +- ctxt->tmpRVT = RVT; ++ list->next = ctxt->tmpRVTList; ++ ctxt->tmpRVTList = list; + return(0); + } + +@@ -159,11 +177,16 @@ int + xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + xmlDocPtr RVT) + { ++ xsltRVTListPtr list; ++ + if ((ctxt == NULL) || (RVT == NULL)) + return(-1); + +- RVT->prev = NULL; ++ list = xsltRVTListCreate(); ++ if (list == NULL) return(-1); ++ + RVT->compression = XSLT_RVT_LOCAL; ++ list->RVT = RVT; + + /* + * When evaluating "select" expressions of xsl:variable +@@ -174,8 +197,8 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + if ((ctxt->contextVariable != NULL) && + (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) + { +- RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; +- XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; ++ list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment; ++ XSLT_TCTXT_VARIABLE(ctxt)->fragment = list; + return(0); + } + /* +@@ -183,10 +206,8 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + * If not reference by a returning instruction (like EXSLT's function), + * then this fragment will be freed, when the instruction exits. + */ +- RVT->next = (xmlNodePtr) ctxt->localRVT; +- if (ctxt->localRVT != NULL) +- ctxt->localRVT->prev = (xmlNodePtr) RVT; +- ctxt->localRVT = RVT; ++ list->next = ctxt->localRVTList; ++ ctxt->localRVTList = list; + return(0); + } + +@@ -342,8 +363,9 @@ xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) { + * @ctxt: an XSLT transformation context + * @RVT: a result value tree (Result Tree Fragment) + * +- * Either frees the RVT (which is an xmlDoc) or stores +- * it in the context's cache for later reuse. ++ * Either frees the RVT (which is an xmlDoc) or stores it in the context's ++ * cache for later reuse. Preserved for ABI/API compatibility; internal use ++ * has all migrated to xsltReleaseRVTList(). + */ + void + xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +@@ -351,41 +373,64 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + if (RVT == NULL) + return; + ++ xsltRVTListPtr list = xsltRVTListCreate(); ++ if (list == NULL) { ++ if (RVT->_private != NULL) { ++ xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); ++ xmlFree(RVT->_private); ++ } ++ xmlFreeDoc(RVT); ++ return; ++ } ++ ++ xsltReleaseRVTList(ctxt, list); ++} ++ ++/** ++ * xsltReleaseRVTList: ++ * @ctxt: an XSLT transformation context ++ * @list: a list node containing a result value tree (Result Tree Fragment) ++ * ++ * Either frees the list node or stores it in the context's cache for later ++ * reuse. Optimization to avoid adding a fallible allocation path when the ++ * caller already has a RVT list node. ++ */ ++void ++xsltReleaseRVTList(xsltTransformContextPtr ctxt, xsltRVTListPtr list) ++{ ++ if (list == NULL) ++ return; ++ + if (ctxt && (ctxt->cache->nbRVT < 40)) { + /* + * Store the Result Tree Fragment. + * Free the document info. + */ +- if (RVT->_private != NULL) { +- xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); +- xmlFree(RVT->_private); +- RVT->_private = NULL; ++ if (list->RVT->_private != NULL) { ++ xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private); ++ xmlFree(list->RVT->_private); ++ list->RVT->_private = NULL; + } + /* + * Clear the document tree. +- * REVISIT TODO: Do we expect ID/IDREF tables to be existent? + */ +- if (RVT->children != NULL) { +- xmlFreeNodeList(RVT->children); +- RVT->children = NULL; +- RVT->last = NULL; ++ if (list->RVT->children != NULL) { ++ xmlFreeNodeList(list->RVT->children); ++ list->RVT->children = NULL; ++ list->RVT->last = NULL; + } +- if (RVT->ids != NULL) { +- xmlFreeIDTable((xmlIDTablePtr) RVT->ids); +- RVT->ids = NULL; +- } +- if (RVT->refs != NULL) { +- xmlFreeRefTable((xmlRefTablePtr) RVT->refs); +- RVT->refs = NULL; ++ if (list->RVT->ids != NULL) { ++ xmlFreeIDTable((xmlIDTablePtr) list->RVT->ids); ++ list->RVT->ids = NULL; + } + + /* + * Reset the ownership information. + */ +- RVT->compression = 0; ++ list->RVT->compression = 0; + +- RVT->next = (xmlNodePtr) ctxt->cache->RVT; +- ctxt->cache->RVT = RVT; ++ list->next = ctxt->cache->rvtList; ++ ctxt->cache->rvtList = list; + + ctxt->cache->nbRVT++; + +@@ -397,11 +442,12 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + /* + * Free it. + */ +- if (RVT->_private != NULL) { +- xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); +- xmlFree(RVT->_private); ++ if (list->RVT->_private != NULL) { ++ xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private); ++ xmlFree(list->RVT->_private); + } +- xmlFreeDoc(RVT); ++ xmlFreeDoc(list->RVT); ++ xmlFree(list); + } + + /** +@@ -419,14 +465,17 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + int + xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + { ++ xsltRVTListPtr list; ++ + if ((ctxt == NULL) || (RVT == NULL)) return(-1); + ++ list = xsltRVTListCreate(); ++ if (list == NULL) return(-1); ++ + RVT->compression = XSLT_RVT_GLOBAL; +- RVT->prev = NULL; +- RVT->next = (xmlNodePtr) ctxt->persistRVT; +- if (ctxt->persistRVT != NULL) +- ctxt->persistRVT->prev = (xmlNodePtr) RVT; +- ctxt->persistRVT = RVT; ++ list->RVT = RVT; ++ list->next = ctxt->persistRVTList; ++ ctxt->persistRVTList = list; + return(0); + } + +@@ -441,52 +490,55 @@ xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + void + xsltFreeRVTs(xsltTransformContextPtr ctxt) + { +- xmlDocPtr cur, next; ++ xsltRVTListPtr cur, next; + + if (ctxt == NULL) + return; + /* + * Local fragments. + */ +- cur = ctxt->localRVT; ++ cur = ctxt->localRVTList; + while (cur != NULL) { +- next = (xmlDocPtr) cur->next; +- if (cur->_private != NULL) { +- xsltFreeDocumentKeys(cur->_private); +- xmlFree(cur->_private); ++ next = cur->next; ++ if (cur->RVT->_private != NULL) { ++ xsltFreeDocumentKeys(cur->RVT->_private); ++ xmlFree(cur->RVT->_private); + } +- xmlFreeDoc(cur); ++ xmlFreeDoc(cur->RVT); ++ xmlFree(cur); + cur = next; + } +- ctxt->localRVT = NULL; ++ ctxt->localRVTList = NULL; + /* + * User-created per-template fragments. + */ +- cur = ctxt->tmpRVT; ++ cur = ctxt->tmpRVTList; + while (cur != NULL) { +- next = (xmlDocPtr) cur->next; +- if (cur->_private != NULL) { +- xsltFreeDocumentKeys(cur->_private); +- xmlFree(cur->_private); ++ next = cur->next; ++ if (cur->RVT->_private != NULL) { ++ xsltFreeDocumentKeys(cur->RVT->_private); ++ xmlFree(cur->RVT->_private); + } +- xmlFreeDoc(cur); ++ xmlFreeDoc(cur->RVT); ++ xmlFree(cur); + cur = next; + } +- ctxt->tmpRVT = NULL; ++ ctxt->tmpRVTList = NULL; + /* + * Global fragments. + */ +- cur = ctxt->persistRVT; ++ cur = ctxt->persistRVTList; + while (cur != NULL) { +- next = (xmlDocPtr) cur->next; +- if (cur->_private != NULL) { +- xsltFreeDocumentKeys(cur->_private); +- xmlFree(cur->_private); ++ next = cur->next; ++ if (cur->RVT->_private != NULL) { ++ xsltFreeDocumentKeys(cur->RVT->_private); ++ xmlFree(cur->RVT->_private); + } +- xmlFreeDoc(cur); ++ xmlFreeDoc(cur->RVT); ++ xmlFree(cur); + cur = next; + } +- ctxt->persistRVT = NULL; ++ ctxt->persistRVTList = NULL; + } + + /************************************************************************ +@@ -574,21 +626,22 @@ xsltFreeStackElem(xsltStackElemPtr elem) { + * Release the list of temporary Result Tree Fragments. + */ + if (elem->context) { +- xmlDocPtr cur; ++ xsltRVTListPtr cur; + + while (elem->fragment != NULL) { + cur = elem->fragment; +- elem->fragment = (xmlDocPtr) cur->next; +- +- if (cur->compression == XSLT_RVT_LOCAL) { +- xsltReleaseRVT(elem->context, cur); +- } else if (cur->compression == XSLT_RVT_FUNC_RESULT) { +- xsltRegisterLocalRVT(elem->context, cur); +- cur->compression = XSLT_RVT_FUNC_RESULT; ++ elem->fragment = cur->next; ++ ++ if (cur->RVT->compression == XSLT_RVT_LOCAL) { ++ xsltReleaseRVTList(elem->context, cur); ++ } else if (cur->RVT->compression == XSLT_RVT_FUNC_RESULT) { ++ xsltRegisterLocalRVT(elem->context, cur->RVT); ++ cur->RVT->compression = XSLT_RVT_FUNC_RESULT; ++ xmlFree(cur); + } else { + xmlGenericError(xmlGenericErrorContext, + "xsltFreeStackElem: Unexpected RVT flag %d\n", +- cur->compression); ++ cur->RVT->compression); + } + } + } +@@ -966,6 +1019,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, + } else { + if (variable->tree) { + xmlDocPtr container; ++ xsltRVTListPtr rvtList; + xmlNodePtr oldInsert; + xmlDocPtr oldOutput; + xsltStackElemPtr oldVar = ctxt->contextVariable; +@@ -988,7 +1042,11 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, + * when the variable is freed, it will also free + * the Result Tree Fragment. + */ +- variable->fragment = container; ++ rvtList = xsltRVTListCreate(); ++ if (rvtList == NULL) ++ goto error; ++ rvtList->RVT = container; ++ variable->fragment = rvtList; + container->compression = XSLT_RVT_LOCAL; + + oldOutput = ctxt->output; +@@ -2370,5 +2428,3 @@ local_variable_found: + + return(valueObj); + } +- +- +diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h +index a5c62d96..3a52c197 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1410,6 +1410,8 @@ struct _xsltStylePreComp { + + #endif /* XSLT_REFACTORED */ + ++typedef struct _xsltRVTList xsltRVTList; ++typedef xsltRVTList *xsltRVTListPtr; + + /* + * The in-memory structure corresponding to an XSLT Variable +@@ -1427,7 +1429,7 @@ struct _xsltStackElem { + xmlNodePtr tree; /* the sequence constructor if no eval + string or the location */ + xmlXPathObjectPtr value; /* The value if computed */ +- xmlDocPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) ++ xsltRVTListPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) + which are bound to the variable's lifetime. */ + int level; /* the depth in the tree; + -1 if persistent (e.g. a given xsl:with-param) */ +@@ -1635,10 +1637,15 @@ struct _xsltStylesheet { + xmlXPathContextPtr xpathCtxt; + }; + ++struct _xsltRVTList { ++ xmlDocPtr RVT; ++ xsltRVTListPtr next; ++}; ++ + typedef struct _xsltTransformCache xsltTransformCache; + typedef xsltTransformCache *xsltTransformCachePtr; + struct _xsltTransformCache { +- xmlDocPtr RVT; ++ xsltRVTListPtr rvtList; + int nbRVT; + xsltStackElemPtr stackItems; + int nbStackItems; +@@ -1738,8 +1745,8 @@ struct _xsltTransformContext { + * handling of temporary Result Value Tree + * (XSLT 1.0 term: "Result Tree Fragment") + */ +- xmlDocPtr tmpRVT; /* list of RVT without persistance */ +- xmlDocPtr persistRVT; /* list of persistant RVTs */ ++ xsltRVTListPtr tmpRVTList; /* list of RVT without persistance */ ++ xsltRVTListPtr persistRVTList; /* list of persistant RVTs */ + int ctxtflags; /* context processing flags */ + + /* +@@ -1772,7 +1779,7 @@ struct _xsltTransformContext { + xmlDocPtr initialContextDoc; + xsltTransformCachePtr cache; + void *contextVariable; /* the current variable item */ +- xmlDocPtr localRVT; /* list of local tree fragments; will be freed when ++ xsltRVTListPtr localRVTList; /* list of local tree fragments; will be freed when + the instruction which created the fragment + exits */ + xmlDocPtr localRVTBase; /* Obsolete */ +@@ -1917,8 +1924,11 @@ XSLTPUBFUN int XSLTCALL + XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); + XSLTPUBFUN void XSLTCALL +- xsltReleaseRVT (xsltTransformContextPtr ctxt, ++ xsltReleaseRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); ++XSLTPUBFUN void XSLTCALL ++ xsltReleaseRVTList (xsltTransformContextPtr ctxt, ++ xsltRVTListPtr list); + /* + * Extra functions for Attribute Value Templates + */ +@@ -1977,4 +1987,3 @@ XSLTPUBFUN int XSLTCALL + #endif + + #endif /* __XML_XSLT_H__ */ +- +-- +2.54.0 + diff --git a/SPECS/libxslt.spec b/SPECS/libxslt.spec index 0d8b538..e8d2982 100644 --- a/SPECS/libxslt.spec +++ b/SPECS/libxslt.spec @@ -1,7 +1,7 @@ Name: libxslt Summary: Library providing the Gnome XSLT engine Version: 1.1.34 -Release: 10%{?dist} +Release: 16%{?dist} License: MIT URL: http://xmlsoft.org/XSLT @@ -26,6 +26,12 @@ Patch4: libxslt-1.1.34-tutorial2-dtd.patch Patch5: libxslt-1.1.34-test-fuzz-build.patch # https://issues.redhat.com/browse/RHEL-83500 Patch6: libxslt-1.1.34-CVE-2025-24855.patch +# https://issues.redhat.com/browse/RHEL-83514 +Patch7: libxslt-1.1.34-CVE-2024-55549.patch +# https://issues.redhat.com/browse/RHEL-145943 +Patch8: libxslt-1.1.34-CVE-2023-40403.patch +# https://redhat.atlassian.net/browse/RHEL-171992 +Patch9: libxslt-1.1.34-CVE-2025-10911.patch %description This C library allows to transform XML files into other XML files @@ -132,6 +138,18 @@ rm -vrf %{buildroot}%{_docdir} %endif %changelog +* Tue May 19 2026 David King - 1.1.34-16 +- Fix CVE-2025-10911 (RHEL-171992) + +* Thu Feb 12 2026 David King - 1.1.34-15 +- Fix CVE-2023-40403 (RHEL-145943) + +* Thu Apr 03 2025 David King - 1.1.34-12 +- Include alloc changes into previous patch (RHEL-83514) + +* Wed Apr 02 2025 David King - 1.1.34-11 +- Fix CVE-2024-55549 (RHEL-83514) + * Thu Mar 20 2025 David King - 1.1.34-10 - Fix CVE-2025-24855 (RHEL-83500)