diff --git a/backport-CVE-2023-40403-Make-generate-id-deterministic.patch b/backport-CVE-2023-40403-Make-generate-id-deterministic.patch new file mode 100644 index 0000000000000000000000000000000000000000..494ece585917ebbe609144648d379ca664febd8b --- /dev/null +++ b/backport-CVE-2023-40403-Make-generate-id-deterministic.patch @@ -0,0 +1,347 @@ +From 82f6cbf8ca61b1f9e00dc04aa3b15d563e7bbc6d Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 13:35:23 +0200 +Subject: [PATCH] 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 ed2b0023..98146d8d 100644 +--- a/libxslt/functions.c ++++ b/libxslt/functions.c +@@ -672,11 +672,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; +@@ -686,16 +691,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++) { +@@ -704,22 +708,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; ++ } + +- val = (long)((char *)cur - (char *)&base_address); +- if (val >= 0) { +- snprintf((char *)str, sizeof(str), "idp%ld", val); ++ 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); ++ } ++ ++ 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 74a2b640..2fd1f681 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1787,6 +1787,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 598b1eaf..d858b04e 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -247,6 +247,7 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + #ifdef IN_LIBXSLT + #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 +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.33.0 + diff --git a/backport-CVE-2025-10911.patch b/backport-CVE-2025-10911.patch index 42867413dae9c77312f5f95dc3be889a9411d9c4..c40eb927eb931573f69f96a40aa034b770c12823 100644 --- a/backport-CVE-2025-10911.patch +++ b/backport-CVE-2025-10911.patch @@ -76,33 +76,33 @@ index 54ef821..bdff66d 100644 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) { + cur = cur->next; -+ if (tmp->RVT->psvi == XSLT_RVT_LOCAL) { ++ if (tmp->RVT->compression == XSLT_RVT_LOCAL) { + xsltReleaseRVTList(ctxt, tmp); -+ } else if (tmp->RVT->psvi == XSLT_RVT_GLOBAL) { ++ } else if (tmp->RVT->compression == XSLT_RVT_GLOBAL) { + xsltRegisterPersistRVT(ctxt, tmp->RVT); + xmlFree(tmp); -+ } else if (tmp->RVT->psvi == XSLT_RVT_FUNC_RESULT) { ++ } 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->psvi = XSLT_RVT_FUNC_RESULT; +- tmp->compression = XSLT_RVT_FUNC_RESULT; + xsltRegisterLocalRVT(ctxt, tmp->RVT); -+ tmp->RVT->psvi = XSLT_RVT_FUNC_RESULT; ++ tmp->RVT->compression = XSLT_RVT_FUNC_RESULT; + xmlFree(tmp); } else { xmlGenericError(xmlGenericErrorContext, - "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", - tmp->psvi); + "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", -+ tmp->RVT->psvi); ++ tmp->RVT->compression); } } while (cur != base); } @@ -287,7 +287,7 @@ index eb98aab..cbe7198 100644 + list = xsltRVTListCreate(); + if (list == NULL) return(-1); + - RVT->psvi = XSLT_RVT_LOCAL; + RVT->compression = XSLT_RVT_LOCAL; + list->RVT = RVT; /* @@ -325,7 +325,7 @@ index eb98aab..cbe7198 100644 + list = xsltRVTListCreate(); + if (list == NULL) return(-1); + - RVT->psvi = XSLT_RVT_LOCAL; + RVT->compression = XSLT_RVT_LOCAL; + list->RVT = RVT; /* @@ -444,8 +444,8 @@ index eb98aab..cbe7198 100644 /* * Reset the ownership information. */ -- RVT->psvi = NULL; -+ list->RVT->psvi = NULL; +- RVT->compression = 0; ++ list->RVT->compression = 0; - RVT->next = (xmlNodePtr) ctxt->cache->RVT; - ctxt->cache->RVT = RVT; @@ -482,7 +482,7 @@ index eb98aab..cbe7198 100644 + list = xsltRVTListCreate(); + if (list == 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) @@ -584,22 +584,22 @@ index eb98aab..cbe7198 100644 - elem->fragment = (xmlDocPtr) cur->next; + elem->fragment = 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; -+ if (cur->RVT->psvi == XSLT_RVT_LOCAL) { +- cur->compression = XSLT_RVT_FUNC_RESULT; ++ if (cur->RVT->compression == XSLT_RVT_LOCAL) { + xsltReleaseRVTList(elem->context, cur); -+ } else if (cur->RVT->psvi == XSLT_RVT_FUNC_RESULT) { ++ } else if (cur->RVT->compression == XSLT_RVT_FUNC_RESULT) { + xsltRegisterLocalRVT(elem->context, cur->RVT); -+ cur->RVT->psvi = XSLT_RVT_FUNC_RESULT; ++ cur->RVT->compression = XSLT_RVT_FUNC_RESULT; + xmlFree(cur); } else { xmlGenericError(xmlGenericErrorContext, - "xsltFreeStackElem: Unexpected RVT flag %p\n", -- cur->psvi); -+ cur->RVT->psvi); + "xsltFreeStackElem: Unexpected RVT flag %d\n", +- cur->compression); ++ cur->RVT->compression); } } } @@ -621,7 +621,7 @@ index eb98aab..cbe7198 100644 + goto error; + rvtList->RVT = container; + variable->fragment = rvtList; - container->psvi = XSLT_RVT_LOCAL; + container->compression = XSLT_RVT_LOCAL; oldOutput = ctxt->output; @@ -2361,5 +2432,3 @@ local_variable_found: diff --git a/backport-Store-RVT-ownership-in-compression-member.patch b/backport-Store-RVT-ownership-in-compression-member.patch new file mode 100644 index 0000000000000000000000000000000000000000..5736daf9c828cd1ecbc8acf6cf44dbdac93898d2 --- /dev/null +++ b/backport-Store-RVT-ownership-in-compression-member.patch @@ -0,0 +1,229 @@ +From ccec6fa31d11ab0a5299f15ea184c7a457e92940 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:35:37 +0200 +Subject: [PATCH] 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 643ee202..6babf0d9 100644 +--- a/libexslt/functions.c ++++ b/libexslt/functions.c +@@ -772,7 +772,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 512eb024..7489504f 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -2275,17 +2275,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 60341d55..d7315eea 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; + } + } + } +@@ -377,7 +377,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; +@@ -416,7 +416,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) +@@ -575,15 +575,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); + } + } + } +@@ -986,7 +986,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 b0125c21..74a2b640 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1916,7 +1916,7 @@ XSLTPUBFUN int XSLTCALL + xsltFlagRVTs( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj, +- void *val); ++ int val); + XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); + XSLTPUBFUN void XSLTCALL +-- +2.33.0 + diff --git a/backport-Store-key-status-of-source-nodes-as-bit-flag.patch b/backport-Store-key-status-of-source-nodes-as-bit-flag.patch new file mode 100644 index 0000000000000000000000000000000000000000..961fc1b1d0a5ce37c5c11af6d7c6705f91728cfd --- /dev/null +++ b/backport-Store-key-status-of-source-nodes-as-bit-flag.patch @@ -0,0 +1,145 @@ +From 1d9820635c271b35f88431f33ea78dc8be349e5b Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 31 Aug 2022 15:34:47 +0200 +Subject: [PATCH] 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 ca0779c5..fb18cd5d 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 da3444f2..0a6fd92d 100644 +--- a/libxslt/pattern.c ++++ b/libxslt/pattern.c +@@ -2283,7 +2283,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); +@@ -2361,37 +2360,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: +@@ -2461,7 +2448,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))) { +@@ -2489,27 +2476,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 65ef78e0..598b1eaf 100644 +--- a/libxslt/xsltutils.h ++++ b/libxslt/xsltutils.h +@@ -246,6 +246,7 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + + #ifdef IN_LIBXSLT + #define XSLT_SOURCE_NODE_MASK 15u ++#define XSLT_SOURCE_NODE_HAS_KEY 1u + int + xsltGetSourceNodeFlags(xmlNodePtr node); + int +-- +2.33.0 + diff --git a/libxslt.spec b/libxslt.spec index 2e15027b6ff9d1ed15d300e541f20f3a6512f27c..2adc46937116d16a78c1778ec880eeb42a6151ea 100644 --- a/libxslt.spec +++ b/libxslt.spec @@ -1,6 +1,6 @@ Name: libxslt Version: 1.1.34 -Release: 12 +Release: 13 Summary: XSLT Transformation Library License: MIT URL: http://xmlsoft.org/libxslt/ @@ -21,8 +21,11 @@ Patch11: backport-Clean-up-attributes-in-source-doc.patch Patch12: backport-transform-Avoid-null-deref-on-documents-without-root.patch Patch13: backport-CVE-2025-7424.patch Patch14: backport-CVE-2025-9714-Test-recursion-in-EXSLT-dynamic-functions.patch -Patch15: backport-CVE-2025-10911.patch -Patch16: backport-CVE-2025-11731-End-function-node-ancestor-search-at-document.patch +Patch15: backport-Store-key-status-of-source-nodes-as-bit-flag.patch +Patch16: backport-Store-RVT-ownership-in-compression-member.patch +Patch17: backport-CVE-2023-40403-Make-generate-id-deterministic.patch +Patch18: backport-CVE-2025-10911.patch +Patch19: backport-CVE-2025-11731-End-function-node-ancestor-search-at-document.patch BuildRequires: gcc make libtool autoconf automake libgcrypt-devel pkgconfig(libxml-2.0) >= 2.6.27 @@ -112,6 +115,9 @@ pushd $RPM_BUILD_ROOT/%{_includedir}/%{name}; touch -m --reference=xslt.h ../../ %doc python/tests/*.xsl %changelog +* Tue Nov 4 2025 luckky - 1.1.34-13 +- fix CVE-2023-40403 + * Tue Oct 14 2025 fuanan - 1.1.34-12 - fix CVE-2025-11731