From f5048b3e71fc30ad096970b8df6e7af073bae4cb Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Thu, 18 Aug 2011 09:10:13 +0000 Subject: Hardening of XPath evaluation Add a mechanism of frame for XPath evaluation when entering a function or a scoped evaluation, also fix a potential problem in predicate evaluation. --- diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h index 1a9e30e..ddd9dd8 100644 --- a/include/libxml/xpath.h +++ b/include/libxml/xpath.h @@ -68,7 +68,8 @@ typedef enum { XPATH_UNDEF_PREFIX_ERROR, XPATH_ENCODING_ERROR, XPATH_INVALID_CHAR_ERROR, - XPATH_INVALID_CTXT + XPATH_INVALID_CTXT, + XPATH_STACK_ERROR } xmlXPathError; /* @@ -380,6 +381,8 @@ struct _xmlXPathParserContext { xmlXPathCompExprPtr comp; /* the precompiled expression */ int xptr; /* it this an XPointer expression */ xmlNodePtr ancestor; /* used for walking preceding axis */ + + int valueFrame; /* used to limit Pop on the stack */ }; /************************************************************************ diff --git a/xpath.c b/xpath.c index b59ac5a..bcee2ea 100644 --- a/xpath.c +++ b/xpath.c @@ -252,6 +252,7 @@ static const char *xmlXPathErrorMessages[] = { "Encoding error\n", "Char out of XML range\n", "Invalid or incomplete context\n", + "Stack usage errror\n", "?? Unknown error ??\n" /* Must be last in the list! */ }; #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ @@ -2398,6 +2399,42 @@ xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { ************************************************************************/ /** + * xmlXPathSetFrame: + * @ctxt: an XPath parser context + * + * Set the callee evaluation frame + * + * Returns the previous frame value to be restored once done + */ +static int +xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { + int ret; + + if (ctxt == NULL) + return(0); + ret = ctxt->valueFrame; + ctxt->valueFrame = ctxt->valueNr; + return(ret); +} + +/** + * xmlXPathPopFrame: + * @ctxt: an XPath parser context + * @frame: the previous frame value + * + * Remove the callee evaluation frame + */ +static void +xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { + if (ctxt == NULL) + return; + if (ctxt->valueNr < ctxt->valueFrame) { + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); + } + ctxt->valueFrame = frame; +} + +/** * valuePop: * @ctxt: an XPath evaluation context * @@ -2412,6 +2449,12 @@ valuePop(xmlXPathParserContextPtr ctxt) if ((ctxt == NULL) || (ctxt->valueNr <= 0)) return (NULL); + + if (ctxt->valueNr <= ctxt->valueFrame) { + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); + return (NULL); + } + ctxt->valueNr--; if (ctxt->valueNr > 0) ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; @@ -6154,6 +6197,7 @@ xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { ret->valueNr = 0; ret->valueMax = 10; ret->value = NULL; + ret->valueFrame = 0; ret->context = ctxt; ret->comp = comp; @@ -11711,6 +11755,7 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; xmlNodePtr oldContextNode, contextNode = NULL; xmlXPathContextPtr xpctxt = ctxt->context; + int frame; #ifdef LIBXML_XPTR_ENABLED /* @@ -11730,6 +11775,8 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, */ exprOp = &ctxt->comp->steps[op->ch2]; for (i = 0; i < set->nodeNr; i++) { + xmlXPathObjectPtr tmp; + if (set->nodeTab[i] == NULL) continue; @@ -11757,23 +11804,25 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, xmlXPathNodeSetAddUnique(contextObj->nodesetval, contextNode); + frame = xmlXPathSetFrame(ctxt); valuePush(ctxt, contextObj); res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); + tmp = valuePop(ctxt); + xmlXPathPopFrame(ctxt, frame); if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { - xmlXPathObjectPtr tmp; - /* pop the result if any */ - tmp = valuePop(ctxt); - if (tmp != contextObj) { + while (tmp != contextObj) { /* * Free up the result * then pop off contextObj, which will be freed later */ xmlXPathReleaseObject(xpctxt, tmp); - valuePop(ctxt); + tmp = valuePop(ctxt); } goto evaluation_error; } + /* push the result back onto the stack */ + valuePush(ctxt, tmp); if (res) pos++; @@ -13377,7 +13426,9 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) xmlXPathFunction func; const xmlChar *oldFunc, *oldFuncURI; int i; + int frame; + frame = xmlXPathSetFrame(ctxt); if (op->ch1 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); @@ -13385,15 +13436,18 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) xmlGenericError(xmlGenericErrorContext, "xmlXPathCompOpEval: parameter error\n"); ctxt->error = XPATH_INVALID_OPERAND; + xmlXPathPopFrame(ctxt, frame); return (total); } - for (i = 0; i < op->value; i++) + for (i = 0; i < op->value; i++) { if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlXPathCompOpEval: parameter error\n"); ctxt->error = XPATH_INVALID_OPERAND; + xmlXPathPopFrame(ctxt, frame); return (total); } + } if (op->cache != NULL) XML_CAST_FPTR(func) = op->cache; else { @@ -13409,6 +13463,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) xmlGenericError(xmlGenericErrorContext, "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", (char *)op->value4, (char *)op->value5); + xmlXPathPopFrame(ctxt, frame); return (total); } func = xmlXPathFunctionLookupNS(ctxt->context, @@ -13430,6 +13485,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) func(ctxt, op->value); ctxt->context->function = oldFunc; ctxt->context->functionURI = oldFuncURI; + xmlXPathPopFrame(ctxt, frame); return (total); } case XPATH_OP_ARG: @@ -14333,6 +14389,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) ctxt->valueNr = 0; ctxt->valueMax = 10; ctxt->value = NULL; + ctxt->valueFrame = 0; } #ifdef XPATH_STREAMING if (ctxt->comp->stream) { diff --git a/xpointer.c b/xpointer.c index 7a42d02..37afa3a 100644 --- a/xpointer.c +++ b/xpointer.c @@ -1269,6 +1269,7 @@ xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { ctxt->valueNr = 0; ctxt->valueMax = 10; ctxt->value = NULL; + ctxt->valueFrame = 0; } SKIP_BLANKS; if (CUR == '/') { -- cgit v0.9.0.2