Commit message: Fix saxon:line-number with namespace nodes

exsltSaxonLineNumberFunction must make sure not to pass namespace
"nodes" to xmlGetLineNo. Otherwise, an OOB heap read results which
typically leads to a segfault.

Found with afl-fuzz and ASan.
CVE: CVE-2016-4609
CWE: CWE-119
Vulnerability description: libxslt in Apple iOS before 9.3.3, OS X before 10.11.6, iTunes before 12.4.2 on Windows, iCloud before 5.2.1 on Windows, tvOS before 9.2.2, and watchOS before 2.2.2 allows remote attackers to cause a denial of service (memory corruption) or possibly have unspecified other impact via unknown vectors, a different vulnerability than CVE-2016-4607, CVE-2016-4608, CVE-2016-4610, and CVE-2016-4612.

Project: libxslt
File: saxon.c

exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathCompExprPtr expr;
     xmlXPathObjectPtr ret;

     if (nargs != 1) {
	  xmlXPathSetArityError(ctxt);
	  return;
     }

     if (!xmlXPathStackIsExternal(ctxt)) {
	  xmlXPathSetTypeError(ctxt);
	  return;
     }

     expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt);

     ret = xmlXPathCompiledEval(expr, ctxt->context);
     if (ret == NULL) {
	  xmlXPathSetError(ctxt, XPATH_EXPR_ERROR);
	  return;
     }

     valuePush(ctxt, ret);
}

Project: libxslt
File: saxon.c

exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs)
{
    if (ctxt == NULL)
        return;
    if (nargs != 0) {
        xmlXPathSetArityError(ctxt);
        return;
    }

    if ((ctxt->context) && (ctxt->context->doc) &&
        (ctxt->context->doc->URL))
	valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL));
    else
	valuePush(ctxt, xmlXPathNewString(BAD_CAST ""));
}

Project: libxslt
File: saxon.c

exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     if (nargs != 1) {
	  xmlXPathSetArityError(ctxt);
	  return;
     }

     exsltSaxonExpressionFunction(ctxt, 1);
     exsltSaxonEvalFunction(ctxt, 1);
}

Project: libxslt
File: saxon.c

exsltSaxonRegister (void) {
     xsltRegisterExtModule (SAXON_NAMESPACE,
			    (xsltExtInitFunction) exsltSaxonInit,
			    (xsltExtShutdownFunction) exsltSaxonShutdown);
     xsltRegisterExtModuleFunction((const xmlChar *) "expression",
				   SAXON_NAMESPACE,
				   exsltSaxonExpressionFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "eval",
				   SAXON_NAMESPACE,
				   exsltSaxonEvalFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "evaluate",
				   SAXON_NAMESPACE,
				   exsltSaxonEvaluateFunction);
    xsltRegisterExtModuleFunction ((const xmlChar *) "line-number",
				   SAXON_NAMESPACE,
				   exsltSaxonLineNumberFunction);
    xsltRegisterExtModuleFunction ((const xmlChar *) "systemId",
				   SAXON_NAMESPACE,
				   exsltSaxonSystemIdFunction);
}

Project: libxslt
File: saxon.c

exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    xmlChar *arg;
    xmlXPathCompExprPtr ret;
    xmlHashTablePtr hash;
    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);

    if (nargs != 1) {
	xmlXPathSetArityError(ctxt);
	return;
    }

    arg = xmlXPathPopString(ctxt);
    if (xmlXPathCheckError(ctxt) || (arg == NULL)) {
	xmlXPathSetTypeError(ctxt);
	return;
    }

    hash = (xmlHashTablePtr) xsltGetExtData(tctxt,
					    ctxt->context->functionURI);

    ret = xmlHashLookup(hash, arg);

    if (ret == NULL) {
	 ret = xmlXPathCompile(arg);
	 if (ret == NULL) {
	      xmlFree(arg);
              xmlXPathSetError(ctxt, XPATH_EXPR_ERROR);
	      return;
	 }
	 xmlHashAddEntry(hash, arg, (void *) ret);
    }

    xmlFree(arg);

    xmlXPathReturnExternal(ctxt, ret);
}

Project: libxslt
File: saxon.c

exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
    xmlNodePtr cur = NULL;
    xmlXPathObjectPtr obj = NULL;
    long lineNo = -1;

    if (nargs == 0) {
	cur = ctxt->context->node;
    } else if (nargs == 1) {
	xmlNodeSetPtr nodelist;
	int i;

	if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
	    xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
		"saxon:line-number() : invalid arg expecting a node-set\n");
	    ctxt->error = XPATH_INVALID_TYPE;
	    return;
	}

	obj = valuePop(ctxt);
	nodelist = obj->nodesetval;
	if ((nodelist != NULL) && (nodelist->nodeNr > 0)) {
            cur = nodelist->nodeTab[0];
            for (i = 1;i < nodelist->nodeNr;i++) {
                int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
                if (ret == -1)
                    cur = nodelist->nodeTab[i];
            }
        }
    } else {
	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
		"saxon:line-number() : invalid number of args %d\n",
		nargs);
	ctxt->error = XPATH_INVALID_ARITY;
	return;
    }

    if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) {
        /*
        * The XPath module sets the owner element of a ns-node on
        * the ns->next field.
        */
        cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
        if (cur == NULL || cur->type != XML_ELEMENT_NODE) {
            xsltGenericError(xsltGenericErrorContext,
                "Internal error in exsltSaxonLineNumberFunction: "
                "Cannot retrieve the doc of a namespace node.\n");
            cur = NULL;
        }
    }

    if (cur != NULL)
        lineNo = xmlGetLineNo(cur);

    valuePush(ctxt, xmlXPathNewFloat(lineNo));

    xmlXPathFreeObject(obj);
}

Project: libxslt
File: saxon.c

exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
		const xmlChar *URI ATTRIBUTE_UNUSED) {
    return xmlHashCreate(1);
}

Project: libxslt
File: saxon.c

exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
		    const xmlChar *URI ATTRIBUTE_UNUSED,
		    xmlHashTablePtr data) {
    xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr);
}