mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-10-26 00:37:43 +03:00
Optional XPath operation limit
Optionally limit the maximum numbers of XPath operations when evaluating an expression. Useful to avoid timeouts when fuzzing. The following operations count towards the limit: - XPath operations - Location step iterations - Union operations Enabled by setting opLimit to a non-zero value. Note that it's the user's responsibility to reset opCount. This allows to enforce the operation limit across multiple reuses of an XPath context.
This commit is contained in:
@@ -70,7 +70,8 @@ typedef enum {
|
|||||||
XPATH_INVALID_CHAR_ERROR,
|
XPATH_INVALID_CHAR_ERROR,
|
||||||
XPATH_INVALID_CTXT,
|
XPATH_INVALID_CTXT,
|
||||||
XPATH_STACK_ERROR,
|
XPATH_STACK_ERROR,
|
||||||
XPATH_FORBID_VARIABLE_ERROR
|
XPATH_FORBID_VARIABLE_ERROR,
|
||||||
|
XPATH_OP_LIMIT_EXCEEDED
|
||||||
} xmlXPathError;
|
} xmlXPathError;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -352,6 +353,10 @@ struct _xmlXPathContext {
|
|||||||
|
|
||||||
/* Cache for reusal of XPath objects */
|
/* Cache for reusal of XPath objects */
|
||||||
void *cache;
|
void *cache;
|
||||||
|
|
||||||
|
/* Resource limits */
|
||||||
|
unsigned long opLimit;
|
||||||
|
unsigned long opCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
81
xpath.c
81
xpath.c
@@ -610,6 +610,7 @@ static const char *xmlXPathErrorMessages[] = {
|
|||||||
"Invalid or incomplete context\n",
|
"Invalid or incomplete context\n",
|
||||||
"Stack usage error\n",
|
"Stack usage error\n",
|
||||||
"Forbidden variable\n",
|
"Forbidden variable\n",
|
||||||
|
"Operation limit exceeded\n",
|
||||||
"?? Unknown error ??\n" /* Must be last in the list! */
|
"?? Unknown error ??\n" /* Must be last in the list! */
|
||||||
};
|
};
|
||||||
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
|
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
|
||||||
@@ -747,6 +748,32 @@ xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
|
|||||||
xmlXPathErr(ctxt, no);
|
xmlXPathErr(ctxt, no);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmlXPathCheckOpLimit:
|
||||||
|
* @ctxt: the XPath Parser context
|
||||||
|
* @opCount: the number of operations to be added
|
||||||
|
*
|
||||||
|
* Adds opCount to the running total of operations and returns -1 if the
|
||||||
|
* operation limit is exceeded. Returns 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
|
||||||
|
xmlXPathContextPtr xpctxt = ctxt->context;
|
||||||
|
|
||||||
|
if ((opCount > xpctxt->opLimit) ||
|
||||||
|
(xpctxt->opCount > xpctxt->opLimit - opCount)) {
|
||||||
|
xpctxt->opCount = xpctxt->opLimit;
|
||||||
|
xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
xpctxt->opCount += opCount;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OP_LIMIT_EXCEEDED(ctxt, n) \
|
||||||
|
((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* *
|
* *
|
||||||
* Utilities *
|
* Utilities *
|
||||||
@@ -12289,6 +12316,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
|||||||
cur = NULL;
|
cur = NULL;
|
||||||
hasNsNodes = 0;
|
hasNsNodes = 0;
|
||||||
do {
|
do {
|
||||||
|
if (OP_LIMIT_EXCEEDED(ctxt, 1))
|
||||||
|
goto error;
|
||||||
|
|
||||||
cur = next(ctxt, cur);
|
cur = next(ctxt, cur);
|
||||||
if (cur == NULL)
|
if (cur == NULL)
|
||||||
break;
|
break;
|
||||||
@@ -12692,6 +12722,8 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
|
|||||||
xmlXPathObjectPtr arg1, arg2;
|
xmlXPathObjectPtr arg1, arg2;
|
||||||
|
|
||||||
CHECK_ERROR0;
|
CHECK_ERROR0;
|
||||||
|
if (OP_LIMIT_EXCEEDED(ctxt, 1))
|
||||||
|
return(0);
|
||||||
comp = ctxt->comp;
|
comp = ctxt->comp;
|
||||||
switch (op->op) {
|
switch (op->op) {
|
||||||
case XPATH_OP_END:
|
case XPATH_OP_END:
|
||||||
@@ -12732,6 +12764,17 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
|
|||||||
xmlXPathReleaseObject(ctxt->context, arg2);
|
xmlXPathReleaseObject(ctxt->context, arg2);
|
||||||
XP_ERROR0(XPATH_INVALID_TYPE);
|
XP_ERROR0(XPATH_INVALID_TYPE);
|
||||||
}
|
}
|
||||||
|
if ((ctxt->context->opLimit != 0) &&
|
||||||
|
(((arg1->nodesetval != NULL) &&
|
||||||
|
(xmlXPathCheckOpLimit(ctxt,
|
||||||
|
arg1->nodesetval->nodeNr) < 0)) ||
|
||||||
|
((arg2->nodesetval != NULL) &&
|
||||||
|
(xmlXPathCheckOpLimit(ctxt,
|
||||||
|
arg2->nodesetval->nodeNr) < 0)))) {
|
||||||
|
xmlXPathReleaseObject(ctxt->context, arg1);
|
||||||
|
xmlXPathReleaseObject(ctxt->context, arg2);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
|
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
|
||||||
arg2->nodesetval);
|
arg2->nodesetval);
|
||||||
@@ -12811,6 +12854,8 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
|
|||||||
xmlXPathObjectPtr arg1, arg2;
|
xmlXPathObjectPtr arg1, arg2;
|
||||||
|
|
||||||
CHECK_ERROR0;
|
CHECK_ERROR0;
|
||||||
|
if (OP_LIMIT_EXCEEDED(ctxt, 1))
|
||||||
|
return(0);
|
||||||
comp = ctxt->comp;
|
comp = ctxt->comp;
|
||||||
switch (op->op) {
|
switch (op->op) {
|
||||||
case XPATH_OP_END:
|
case XPATH_OP_END:
|
||||||
@@ -12850,6 +12895,17 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
|
|||||||
xmlXPathReleaseObject(ctxt->context, arg2);
|
xmlXPathReleaseObject(ctxt->context, arg2);
|
||||||
XP_ERROR0(XPATH_INVALID_TYPE);
|
XP_ERROR0(XPATH_INVALID_TYPE);
|
||||||
}
|
}
|
||||||
|
if ((ctxt->context->opLimit != 0) &&
|
||||||
|
(((arg1->nodesetval != NULL) &&
|
||||||
|
(xmlXPathCheckOpLimit(ctxt,
|
||||||
|
arg1->nodesetval->nodeNr) < 0)) ||
|
||||||
|
((arg2->nodesetval != NULL) &&
|
||||||
|
(xmlXPathCheckOpLimit(ctxt,
|
||||||
|
arg2->nodesetval->nodeNr) < 0)))) {
|
||||||
|
xmlXPathReleaseObject(ctxt->context, arg1);
|
||||||
|
xmlXPathReleaseObject(ctxt->context, arg2);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
|
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
|
||||||
arg2->nodesetval);
|
arg2->nodesetval);
|
||||||
@@ -13191,6 +13247,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
|||||||
xmlXPathObjectPtr arg1, arg2;
|
xmlXPathObjectPtr arg1, arg2;
|
||||||
|
|
||||||
CHECK_ERROR0;
|
CHECK_ERROR0;
|
||||||
|
if (OP_LIMIT_EXCEEDED(ctxt, 1))
|
||||||
|
return(0);
|
||||||
comp = ctxt->comp;
|
comp = ctxt->comp;
|
||||||
switch (op->op) {
|
switch (op->op) {
|
||||||
case XPATH_OP_END:
|
case XPATH_OP_END:
|
||||||
@@ -13292,6 +13350,17 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
|||||||
xmlXPathReleaseObject(ctxt->context, arg2);
|
xmlXPathReleaseObject(ctxt->context, arg2);
|
||||||
XP_ERROR0(XPATH_INVALID_TYPE);
|
XP_ERROR0(XPATH_INVALID_TYPE);
|
||||||
}
|
}
|
||||||
|
if ((ctxt->context->opLimit != 0) &&
|
||||||
|
(((arg1->nodesetval != NULL) &&
|
||||||
|
(xmlXPathCheckOpLimit(ctxt,
|
||||||
|
arg1->nodesetval->nodeNr) < 0)) ||
|
||||||
|
((arg2->nodesetval != NULL) &&
|
||||||
|
(xmlXPathCheckOpLimit(ctxt,
|
||||||
|
arg2->nodesetval->nodeNr) < 0)))) {
|
||||||
|
xmlXPathReleaseObject(ctxt->context, arg1);
|
||||||
|
xmlXPathReleaseObject(ctxt->context, arg2);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
if ((arg1->nodesetval == NULL) ||
|
if ((arg1->nodesetval == NULL) ||
|
||||||
((arg2->nodesetval != NULL) &&
|
((arg2->nodesetval != NULL) &&
|
||||||
@@ -13967,6 +14036,8 @@ xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
|
|||||||
xmlXPathObjectPtr resObj = NULL;
|
xmlXPathObjectPtr resObj = NULL;
|
||||||
|
|
||||||
start:
|
start:
|
||||||
|
if (OP_LIMIT_EXCEEDED(ctxt, 1))
|
||||||
|
return(0);
|
||||||
/* comp = ctxt->comp; */
|
/* comp = ctxt->comp; */
|
||||||
switch (op->op) {
|
switch (op->op) {
|
||||||
case XPATH_OP_END:
|
case XPATH_OP_END:
|
||||||
@@ -14166,6 +14237,16 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
|
|||||||
goto scan_children;
|
goto scan_children;
|
||||||
next_node:
|
next_node:
|
||||||
do {
|
do {
|
||||||
|
if (ctxt->opLimit != 0) {
|
||||||
|
if (ctxt->opCount >= ctxt->opLimit) {
|
||||||
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
|
"XPath operation limit exceeded\n");
|
||||||
|
xmlFreeStreamCtxt(patstream);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
ctxt->opCount++;
|
||||||
|
}
|
||||||
|
|
||||||
nb_nodes++;
|
nb_nodes++;
|
||||||
|
|
||||||
switch (cur->type) {
|
switch (cur->type) {
|
||||||
|
|||||||
Reference in New Issue
Block a user