Friday, August 29, 2025

libxslt patches

There's been a bit of noise about this recently so I looked and noticed
we have not yet pulled in the available patches. It doesn't sound like a
big deal since it appears untrusted style sheets are involved. Still,
it seems like something we want to patch.

https://vuxml.freebsd.org/freebsd/b0a3466f-5efc-11f0-ae84-99047d0a6bcc.html

lists four issues, three of which are public and have patches from apple
and google.

Two of them are for libxslt and apply cleanly. Those are included below:

https://gitlab.gnome.org/GNOME/libxslt/-/issues/139
https://gitlab.gnome.org/GNOME/libxslt/-/issues/144

Regress still passes.

The third one is quite confusing since part of it seems to be about
libxml2 and some of the fixes implicate binary compatibility. The apple
patch doesn't apply cleanly to our port:

https://gitlab.gnome.org/GNOME/libxslt/-/issues/140

I leave that one to the maintainer to sort out.

Index: Makefile
===================================================================
RCS file: /cvs/ports/textproc/libxslt/Makefile,v
diff -u -p -r1.110 Makefile
--- Makefile 15 Mar 2025 09:34:42 -0000 1.110
+++ Makefile 29 Aug 2025 13:17:48 -0000
@@ -2,7 +2,7 @@ COMMENT= XSLT C Library for GNOME

GNOME_VERSION= 1.1.43
GNOME_PROJECT= libxslt
-REVISION= 0
+REVISION= 1

SHARED_LIBS += xslt 4.2 # 2.43
SHARED_LIBS += exslt 9.8 # 8.24
Index: patches/patch-libxslt_functions_c
===================================================================
RCS file: patches/patch-libxslt_functions_c
diff -N patches/patch-libxslt_functions_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-libxslt_functions_c 29 Aug 2025 13:17:48 -0000
@@ -0,0 +1,55 @@
+https://gitlab.gnome.org/GNOME/libxslt/-/issues/139
+
+From 345d6826d0eae6f0a962456b8ed6f6a1bad0877d Mon Sep 17 00:00:00 2001
+From: David Kilzer <ddkilzer@apple.com>
+Date: Sat, 24 May 2025 15:06:42 -0700
+Subject: [PATCH] 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.
+
+Index: libxslt/functions.c
+--- libxslt/functions.c.orig
++++ libxslt/functions.c
+@@ -34,6 +34,7 @@
+ #include "numbersInternals.h"
+ #include "keys.h"
+ #include "documents.h"
++#include "transformInternals.h"
+
+ #ifdef WITH_XSLT_DEBUG
+ #define WITH_XSLT_DEBUG_FUNCTION
+@@ -125,7 +126,20 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContext
+ /*
+ * 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 {
+ goto out_fragment;
+ }
Index: patches/patch-libxslt_transformInternals_h
===================================================================
RCS file: patches/patch-libxslt_transformInternals_h
diff -N patches/patch-libxslt_transformInternals_h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-libxslt_transformInternals_h 29 Aug 2025 13:17:48 -0000
@@ -0,0 +1,35 @@
+https://gitlab.gnome.org/GNOME/libxslt/-/issues/139
+
+From 345d6826d0eae6f0a962456b8ed6f6a1bad0877d Mon Sep 17 00:00:00 2001
+From: David Kilzer <ddkilzer@apple.com>
+Date: Sat, 24 May 2025 15:06:42 -0700
+Subject: [PATCH] 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.
+
+Index: libxslt/transformInternals.h
+--- libxslt/transformInternals.h.orig
++++ 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 <ddkilzer@apple.com>
++ */
++
++void xsltCleanupSourceDoc(xmlDocPtr doc);
Index: patches/patch-libxslt_transform_c
===================================================================
RCS file: patches/patch-libxslt_transform_c
diff -N patches/patch-libxslt_transform_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-libxslt_transform_c 29 Aug 2025 13:17:48 -0000
@@ -0,0 +1,258 @@
+https://gitlab.gnome.org/GNOME/libxslt/-/issues/139
+https://gitlab.gnome.org/GNOME/libxslt/-/issues/144
+
+From 345d6826d0eae6f0a962456b8ed6f6a1bad0877d Mon Sep 17 00:00:00 2001
+From: David Kilzer <ddkilzer@apple.com>
+Date: Sat, 24 May 2025 15:06:42 -0700
+Subject: [PATCH] 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.
+
+From f94e7e9796edeb6f3bedd3fdb1099e9b556aea21 Mon Sep 17 00:00:00 2001
+From: Daniel Cheng <dcheng@chromium.org>
+Date: Sat, 31 May 2025 00:15:24 -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.
+
+Index: libxslt/transform.c
+--- libxslt/transform.c.orig
++++ libxslt/transform.c
+@@ -43,6 +43,7 @@
+ #include "xsltlocale.h"
+ #include "pattern.h"
+ #include "transform.h"
++#include "transformInternals.h"
+ #include "variables.h"
+ #include "numbersInternals.h"
+ #include "namespaces.h"
+@@ -518,19 +519,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);
+ }
+ }
+ /*
+@@ -2263,38 +2265,40 @@ 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;
++ /* Reset localRVTList early because some RVTs might be registered again. */
++ ctxt->localRVTList = base;
+ if (base != NULL)
+ base->prev = NULL;
+
+ 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);
+ }
+@@ -2322,7 +2326,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr c
+ xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
+ xmlNodePtr cur, insert, copy = NULL;
+ int level = 0, oldVarsNr;
+- xmlDocPtr oldLocalFragmentTop;
++ xsltRVTListPtr oldLocalFragmentTop;
+
+ #ifdef XSLT_REFACTORED
+ xsltStylePreCompPtr info;
+@@ -2368,7 +2372,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr c
+ }
+ ctxt->depth++;
+
+- oldLocalFragmentTop = ctxt->localRVT;
++ oldLocalFragmentTop = ctxt->localRVTList;
+ oldInsert = insert = ctxt->insert;
+ oldInst = oldCurInst = ctxt->inst;
+ oldContextNode = ctxt->node;
+@@ -2602,7 +2606,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr c
+ /*
+ * Cleanup temporary tree fragments.
+ */
+- if (oldLocalFragmentTop != ctxt->localRVT)
++ if (oldLocalFragmentTop != ctxt->localRVTList)
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+ ctxt->insert = oldInsert;
+@@ -2697,7 +2701,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr c
+ /*
+ * Cleanup temporary tree fragments.
+ */
+- if (oldLocalFragmentTop != ctxt->localRVT)
++ if (oldLocalFragmentTop != ctxt->localRVTList)
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+ ctxt->insert = oldInsert;
+@@ -2763,7 +2767,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr c
+ /*
+ * Cleanup temporary tree fragments.
+ */
+- if (oldLocalFragmentTop != ctxt->localRVT)
++ if (oldLocalFragmentTop != ctxt->localRVTList)
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+ ctxt->insert = oldInsert;
+@@ -2893,7 +2897,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr c
+ /*
+ * Cleanup temporary tree fragments.
+ */
+- if (oldLocalFragmentTop != ctxt->localRVT)
++ if (oldLocalFragmentTop != ctxt->localRVTList)
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+ ctxt->insert = oldInsert;
+@@ -3072,7 +3076,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
+ int oldVarsBase = 0;
+ xmlNodePtr cur;
+ xsltStackElemPtr tmpParam = NULL;
+- xmlDocPtr oldUserFragmentTop;
++ xsltRVTListPtr oldUserFragmentTop;
+ #ifdef WITH_PROFILER
+ long start = 0;
+

No comments:

Post a Comment