From 45d1d8597ed1b330ff059dcde81a8d09c477a049 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 12 Feb 2019 01:52:31 +0100
Subject: [PATCH 27/33] Backup context node in exsltFuncFunctionFunction

exsltFuncFunctionFunction handles XPath extension functions and is called
from the XPath engine. Since evaluation of function templates can change
the XPath context node, it must be backed up to avoid corruption.

Without proper backup, evaluating certain content in function templates
could also result in use-after-free errors.

It seems that libxml2 commit 029d0e96 helped to expose the error.

Fixes #11.
---
 libexslt/functions.c      |  6 +++++-
 tests/docs/bug-216.xml    |  1 +
 tests/general/bug-216.out |  2 ++
 tests/general/bug-216.xsl | 11 +++++++++++
 4 files changed, 19 insertions(+), 1 deletion(-)
 create mode 100644 tests/docs/bug-216.xml
 create mode 100644 tests/general/bug-216.out
 create mode 100644 tests/general/bug-216.xsl

diff --git a/libexslt/functions.c b/libexslt/functions.c
index 075e236..41d3749 100644
--- a/libexslt/functions.c
+++ b/libexslt/functions.c
@@ -291,7 +291,7 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathObjectPtr oldResult, ret;
     exsltFuncData *data;
     exsltFuncFunctionData *func;
-    xmlNodePtr paramNode, oldInsert, fake;
+    xmlNodePtr paramNode, oldInsert, oldXPNode, fake;
     int oldBase;
     void *oldCtxtVar;
     xsltStackElemPtr params = NULL, param;
@@ -360,6 +360,9 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     }
     tctxt->depth++;
 
+    /* Evaluating templates can change the XPath context node. */
+    oldXPNode = tctxt->xpathCtxt->node;
+
     /*
      * We have a problem with the evaluation of function parameters.
      * The original library code did not evaluate XPath expressions until
@@ -446,5 +449,6 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     if (params != NULL)
 	xsltFreeStackElemList(params);
+    tctxt->xpathCtxt->node = oldXPNode;
 
     if (data->error != 0)
         goto error;
diff --git a/tests/docs/bug-216.xml b/tests/docs/bug-216.xml
new file mode 100644
index 0000000..d128aec
--- /dev/null
+++ b/tests/docs/bug-216.xml
@@ -0,0 +1 @@
+<top xmlns:ns1="abc"/>
diff --git a/tests/general/bug-216.out b/tests/general/bug-216.out
new file mode 100644
index 0000000..40f6b10
--- /dev/null
+++ b/tests/general/bug-216.out
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+10
diff --git a/tests/general/bug-216.xsl b/tests/general/bug-216.xsl
new file mode 100644
index 0000000..50cc4b1
--- /dev/null
+++ b/tests/general/bug-216.xsl
@@ -0,0 +1,11 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:func="http://exslt.org/functions" version="1.0" extension-element-prefixes="func">
+  <func:function name="func:f">
+    <xsl:for-each select="namespace::*">
+      <xsl:sort/>
+    </xsl:for-each>
+    <func:result>10</func:result>
+  </func:function>
+  <xsl:template match="*">
+    <xsl:value-of select="func:f()+count(abc)"/>
+  </xsl:template>
+</xsl:stylesheet>
-- 
1.8.3.1

