From e5ceeef8336bc7789c9700c8b1dc311ba3bd33d1 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Mon, 9 Jun 2025 13:55:56 +0000 Subject: [PATCH] import UBI libxslt-1.1.32-6.2.el8_10 --- SOURCES/libxslt-1.1.32-CVE-2023-40403.patch | 1061 +++++++++++++++++++ SPECS/libxslt.spec | 7 +- 2 files changed, 1067 insertions(+), 1 deletion(-) create mode 100644 SOURCES/libxslt-1.1.32-CVE-2023-40403.patch diff --git a/SOURCES/libxslt-1.1.32-CVE-2023-40403.patch b/SOURCES/libxslt-1.1.32-CVE-2023-40403.patch new file mode 100644 index 0000000..3d5477c --- /dev/null +++ b/SOURCES/libxslt-1.1.32-CVE-2023-40403.patch @@ -0,0 +1,1061 @@ +From e494220e4a57e87e8561e6798f57f4dcf91762b3 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:29:57 +0200 +Subject: [PATCH 1/5] 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 | 3 + + libxslt/xsltutils.c | 135 ++++++++++++++++++++++++++++++++++++++++ + libxslt/xsltutils.h | 15 ++++- + 4 files changed, 186 insertions(+), 1 deletion(-) + +diff --git a/libxslt/transform.c b/libxslt/transform.c +index f748f2df..8634b09e 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -5824,6 +5824,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 +@@ -6210,6 +6241,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 47125b36..39b488c0 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1789,6 +1789,9 @@ struct _xsltTransformContext { + int depth; /* Needed to catch recursions */ + int maxTemplateDepth; + int maxTemplateVars; ++ unsigned long opLimit; ++ unsigned long opCount; ++ int sourceDocDirty; + }; + + /** +diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c +index 2154b238..a0d9d331 100644 +--- a/libxslt/xsltutils.c ++++ b/libxslt/xsltutils.c +@@ -1788,6 +1788,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; ++ } ++} ++ + /************************************************************************ + * * + * Generating profiling informations * +diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h +index 789865a6..df89aeb1 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -247,6 +247,19 @@ 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 ++ + /* + * Profiling. + */ +@@ -267,6 +280,7 @@ XSLTPUBFUN void XSLTCALL + * Sampling precision for profiling + */ + #define XSLT_TIMESTAMP_TICS_PER_SEC 100000l ++#endif + + /* + * Hooks for the debugger. +@@ -306,7 +320,6 @@ XSLTPUBFUN void XSLTCALL + + #ifdef __cplusplus + } +-#endif + + #endif /* __XML_XSLTUTILS_H__ */ + +-- +2.49.0 + + +From 5895aaae58025fa35a540f6f922f9137505f1e27 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:34:47 +0200 +Subject: [PATCH 2/5] 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 85902b0d..6675903d 100644 +--- a/libxslt/keys.c ++++ b/libxslt/keys.c +@@ -826,24 +826,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 c094e974..11d8c3e5 100644 +--- a/libxslt/pattern.c ++++ b/libxslt/pattern.c +@@ -2328,7 +2328,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); +@@ -2405,37 +2404,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: +@@ -2496,7 +2483,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))) { +@@ -2521,27 +2508,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 df89aeb1..80194891 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.49.0 + + +From 5bdb3e5c9a0a4bc42dd14fe07cf594298a79edce Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:35:37 +0200 +Subject: [PATCH 3/5] 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 | 20 +++++++++---------- + libxslt/variables.c | 44 ++++++++++++++++++++--------------------- + libxslt/variables.h | 6 +++--- + libxslt/xsltInternals.h | 2 +- + 5 files changed, 37 insertions(+), 37 deletions(-) + +diff --git a/libexslt/functions.c b/libexslt/functions.c +index aeb7aaf9..079acde6 100644 +--- a/libexslt/functions.c ++++ b/libexslt/functions.c +@@ -758,7 +758,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 8634b09e..a631529c 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -2307,21 +2307,21 @@ 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) { +- if (prev == NULL) +- ctxt->localRVT = tmp; +- else +- prev->next = (xmlNodePtr) tmp; +- tmp->prev = (xmlNodePtr) prev; +- prev = tmp; ++ } 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->compression = XSLT_RVT_FUNC_RESULT; + } else { + xmlGenericError(xmlGenericErrorContext, + "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", +- tmp->psvi); ++ tmp->compression); + } + } while (cur != base); + +diff --git a/libxslt/variables.c b/libxslt/variables.c +index 5fdbee0f..0f4b72f3 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 +@@ -253,7 +253,7 @@ xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, + * 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; +@@ -300,34 +300,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; + } + } + } +@@ -380,7 +380,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; +@@ -419,7 +419,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) +@@ -578,15 +578,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); + } + } + } +@@ -981,7 +981,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 39b488c0..e7a058cc 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1918,7 +1918,7 @@ XSLTPUBFUN int XSLTCALL + xsltFlagRVTs( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj, +- void *val); ++ int val); + XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); + XSLTPUBFUN void XSLTCALL +-- +2.49.0 + + +From 957e111edb935259e777c15e809b1d4de8ee2f3f Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 13:35:23 +0200 +Subject: [PATCH 4/5] 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 43d82f6d..cd759d4e 100644 +--- a/libxslt/functions.c ++++ b/libxslt/functions.c +@@ -680,11 +680,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; +@@ -694,16 +699,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++) { +@@ -712,22 +716,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 e7a058cc..ae9b76af 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1792,6 +1792,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 80194891..bae9ad75 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.49.0 + + +From 7eff64281f0bcd4c6a452dc04f3250037d28786e Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 21:37:44 +0200 +Subject: [PATCH 5/5] 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 a631529c..8a424773 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -5841,6 +5841,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 bae9ad75..98ca83a1 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.49.0 + diff --git a/SPECS/libxslt.spec b/SPECS/libxslt.spec index 0a32a81..55140d6 100644 --- a/SPECS/libxslt.spec +++ b/SPECS/libxslt.spec @@ -8,7 +8,7 @@ Name: libxslt Summary: Library providing the Gnome XSLT engine Version: 1.1.32 -Release: 6.1%{?dist} +Release: 6.2%{?dist} License: MIT URL: http://xmlsoft.org/XSLT @@ -37,6 +37,8 @@ Patch5: libxslt-1.1.32-unexpected-rvt-flag.patch Patch6: libxslt-1.1.32-CVE-2024-55549.patch # https://issues.redhat.com/browse/RHEL-83492 Patch7: libxslt-1.1.32-CVE-2025-24855.patch +# https://issues.redhat.com/browse/RHEL-89374 +Patch8: libxslt-1.1.32-CVE-2023-40403.patch %description This C library allows to transform XML files into other XML files @@ -141,6 +143,9 @@ rm -vrf %{buildroot}%{_docdir} %endif # with python2 %changelog +* Tue Jun 03 2025 David King - 1.1.32-6.2 +- Fix CVE-2023-40403 (aka 2022-4909) (RHEL-89374) + * Fri Apr 04 2025 David King - 1.1.32-6.1 - Fix CVE-2024-55549 (RHEL-83506) - Fix CVE-2025-24855 (RHEL-83492)