libxslt: fix CVE-2023-40403

Upstream-Status: Backport from  adebe45f6e && 1d9820635c && ccec6fa31d && 82f6cbf8ca && 452fb4ca9b

(From OE-Core rev: b77845d6fed5385de5789f8864fc399f82209ea1)

Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
Hitendra Prajapati
2025-08-11 12:33:33 +05:30
committed by Steve Sakoman
parent 8f356f507e
commit 423e0ff3fb
6 changed files with 1044 additions and 0 deletions

View File

@@ -0,0 +1,257 @@
From 4f26166f9e253aa62f8c121a6a25c76df5aa8142 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 31 Aug 2022 15:29:57 +0200
Subject: [PATCH] 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.
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxslt/-/commit/adebe45f6ef9f9d036acacd8aec7411d4ea84e25]
CVE: CVE-2023-40403
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
libxslt/transform.c | 34 ++++++++++
libxslt/xsltInternals.h | 1 +
libxslt/xsltutils.c | 135 ++++++++++++++++++++++++++++++++++++++++
libxslt/xsltutils.h | 13 ++++
4 files changed, 183 insertions(+)
diff --git a/libxslt/transform.c b/libxslt/transform.c
index 57f05bf..40ab810 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -5747,6 +5747,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
@@ -6145,6 +6176,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 14343d2..b0125c2 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -1786,6 +1786,7 @@ struct _xsltTransformContext {
int maxTemplateVars;
unsigned long opLimit;
unsigned long opCount;
+ int sourceDocDirty;
};
/**
diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c
index 9faa6b2..a879aa8 100644
--- a/libxslt/xsltutils.c
+++ b/libxslt/xsltutils.c
@@ -1835,6 +1835,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 ea6c374..202694f 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.
*/

View File

@@ -0,0 +1,147 @@
From b392a3d0265f190d86cc122d86769a23ddb1fe66 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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.
CVE: CVE-2023-40403
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxslt/-/commit/1d9820635c271b35f88431f33ea78dc8be349e5b]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
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 ecef538..3a134ab 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 1944661..9372bc3 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) ||
@@ -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 202694f..dcfd139 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

View File

@@ -0,0 +1,231 @@
From 8986995b07126852762e8a59eaee83be0b8de9a3 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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.
CVE: CVE-2023-40403
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxslt/-/commit/ccec6fa31d11ab0a5299f15ea184c7a457e92940]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
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 958bf60..859a992 100644
--- a/libexslt/functions.c
+++ b/libexslt/functions.c
@@ -775,7 +775,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 40ab810..19d7326 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -2276,17 +2276,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 4c972a4..dab0bab 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 039288f..e2adee0 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 b0125c2..74a2b64 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

View File

@@ -0,0 +1,349 @@
From 91c9c56dcca01bfe3f9dae74fb75dcf792ebe58b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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.
CVE: CVE-2023-40403
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxslt/-/commit/82f6cbf8ca61b1f9e00dc04aa3b15d563e7bbc6d]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
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 7887dda..da25c24 100644
--- a/libxslt/functions.c
+++ b/libxslt/functions.c
@@ -693,11 +693,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;
@@ -707,16 +712,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++) {
@@ -725,22 +729,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 74a2b64..2fd1f68 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 dcfd139..6c14ecf 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 0000000..237a9f2
--- /dev/null
+++ b/tests/REC/test-12.4-1.out
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<result>
+ <document>id1</document>
+ <element>id2</element>
+ <attribute>id3</attribute>
+ <namespace>id2ns</namespace>
+ <namespace>id2nsC3A4C3B6C3BC</namespace>
+ <text>id4</text>
+ <comment>id5</comment>
+ <processing-instruction>id6</processing-instruction>
+</result>
diff --git a/tests/REC/test-12.4-1.xml b/tests/REC/test-12.4-1.xml
new file mode 100644
index 0000000..84484f6
--- /dev/null
+++ b/tests/REC/test-12.4-1.xml
@@ -0,0 +1,6 @@
+<doc xmlns="s:def">
+ <elem attr="value" xmlns:äöü="uri"/>
+ <text>text</text>
+ <!-- comment -->
+ <?pi content?>
+</doc>
diff --git a/tests/REC/test-12.4-1.xsl b/tests/REC/test-12.4-1.xsl
new file mode 100644
index 0000000..5cf5dd3
--- /dev/null
+++ b/tests/REC/test-12.4-1.xsl
@@ -0,0 +1,38 @@
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:d="s:def"
+ exclude-result-prefixes="d">
+
+<xsl:output indent="yes"/>
+
+<xsl:template match="/">
+ <result>
+ <document>
+ <xsl:value-of select="generate-id(/)"/>
+ </document>
+ <element>
+ <xsl:value-of select="generate-id(/d:doc/d:elem)"/>
+ </element>
+ <attribute>
+ <xsl:value-of select="generate-id(d:doc/d:elem/@attr)"/>
+ </attribute>
+ <namespace>
+ <xsl:value-of select="generate-id(d:doc/d:elem/namespace::*[local-name()=''])"/>
+ </namespace>
+ <namespace>
+ <xsl:value-of select="generate-id(d:doc/d:elem/namespace::äöü)"/>
+ </namespace>
+ <text>
+ <xsl:value-of select="generate-id(d:doc/d:text/text())"/>
+ </text>
+ <comment>
+ <xsl:value-of select="generate-id(d:doc/comment())"/>
+ </comment>
+ <processing-instruction>
+ <xsl:value-of select="generate-id(d:doc/processing-instruction())"/>
+ </processing-instruction>
+ </result>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/tests/exslt/common/dynamic-id.out b/tests/exslt/common/dynamic-id.out
new file mode 100644
index 0000000..1b7b7ba
--- /dev/null
+++ b/tests/exslt/common/dynamic-id.out
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<result xmlns:exsl="http://exslt.org/common">
+ <id>id1</id>
+ <id>id2</id>
+ <id>id3</id>
+ <id>id4</id>
+ <id>id5</id>
+ <id>id6</id>
+ <id>id7</id>
+ <id>id8</id>
+ <id>id9</id>
+ <id>id10</id>
+</result>
diff --git a/tests/exslt/common/dynamic-id.xml b/tests/exslt/common/dynamic-id.xml
new file mode 100644
index 0000000..69d62f2
--- /dev/null
+++ b/tests/exslt/common/dynamic-id.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/exslt/common/dynamic-id.xsl b/tests/exslt/common/dynamic-id.xsl
new file mode 100644
index 0000000..8478f6a
--- /dev/null
+++ b/tests/exslt/common/dynamic-id.xsl
@@ -0,0 +1,29 @@
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common">
+
+<xsl:output indent="yes"/>
+
+<xsl:template name="dynamic-id">
+ <id>
+ <xsl:value-of select="generate-id(exsl:node-set('string'))"/>
+ </id>
+</xsl:template>
+
+<xsl:template match="/">
+ <result>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ <xsl:call-template name="dynamic-id"/>
+ </result>
+</xsl:template>
+
+</xsl:stylesheet>

View File

@@ -0,0 +1,55 @@
From 3014af50b22f1be89b5514faea284de7b63fa5dc Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 31 Aug 2022 21:37:44 +0200
Subject: [PATCH] Clean up attributes in source doc
Also make bit flag constants unsigned to avoid implicit-conversion
warnings.
CVE: CVE-2023-40403
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxslt/-/commit/452fb4ca9b9803448826008b9573987c615912a1]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
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 19d7326..7299eb5 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -5764,6 +5764,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 6c14ecf..2af4282 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

View File

@@ -16,6 +16,11 @@ DEPENDS = "libxml2"
SRC_URI = "https://download.gnome.org/sources/libxslt/1.1/libxslt-${PV}.tar.xz \
file://CVE-2024-55549.patch \
file://CVE-2025-24855.patch \
file://CVE-2023-40403-001.patch \
file://CVE-2023-40403-002.patch \
file://CVE-2023-40403-003.patch \
file://CVE-2023-40403-004.patch \
file://CVE-2023-40403-005.patch \
"
SRC_URI[sha256sum] = "8247f33e9a872c6ac859aa45018bc4c4d00b97e2feac9eebc10c93ce1f34dd79"