Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions src/request_body_processor/xml.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "src/request_body_processor/xml.h"

#include <cctype>
#include <list>
#include <iostream>
#include <string>
Expand Down Expand Up @@ -151,6 +152,25 @@
}
}


/* Build the error text from libxml2's last error on this context, so the
* actual parse failure ("Extra content at the end of the document", a tag
* mismatch, ...) reaches REQBODY_ERROR_MSG and the debug log instead of a
* fixed string. Falls back to "XML: <what>." when libxml2 has no message.
* xmlCtxtGetLastError() keeps working under XML_PARSE_NOERROR. */
static std::string parseError(xmlParserCtxtPtr ctx, const std::string &what) {
const xmlError *e = (ctx != NULL) ? xmlCtxtGetLastError(ctx) : NULL;

Check failure on line 162 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "nullptr" literal.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCQ&open=AaE1XvywGsfaXwq_urCQ&pullRequest=3679

Check failure on line 162 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "nullptr" literal.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCP&open=AaE1XvywGsfaXwq_urCP&pullRequest=3679
if (e == NULL || e->message == NULL || *e->message == '\0') {

Check failure on line 163 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "nullptr" literal.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCR&open=AaE1XvywGsfaXwq_urCR&pullRequest=3679

Check failure on line 163 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "nullptr" literal.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCS&open=AaE1XvywGsfaXwq_urCS&pullRequest=3679
return "XML: " + what + ".";
}
std::string detail(e->message);
while (!detail.empty() && isspace(static_cast<unsigned char>(detail.back()))) {
detail.pop_back();
}
return "XML: " + what + ": " + detail + " (line " + std::to_string(e->line)
+ ", column " + std::to_string(e->int2) + ")";
}

XML::XML(Transaction *transaction)
: m_transaction(transaction) {
m_data.doc = NULL;
Expand Down Expand Up @@ -287,8 +307,9 @@
xmlParseChunk(m_data.parsing_ctx, buf, size, 0);
m_data.xml_parser_state->parsing_ctx_arg = m_data.parsing_ctx_arg;
if (m_data.parsing_ctx->wellFormed != 1) {
error->assign("XML: Failed to parse document.");
ms_dbg_a(m_transaction, 4, "XML: Failed to parse document.");
error->assign(parseError(m_data.parsing_ctx,
"Failed to parse document"));
ms_dbg_a(m_transaction, 4, *error);

Check warning on line 312 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCT&open=AaE1XvywGsfaXwq_urCT&pullRequest=3679
return false;
}
}
Expand All @@ -303,8 +324,9 @@
) {
xmlParseChunk(m_data.parsing_ctx_arg, buf, size, 0);
if (m_data.parsing_ctx_arg->wellFormed != 1) {
error->assign("XML: Failed to parse document for ARGS.");
ms_dbg_a(m_transaction, 4, "XML: Failed to parse document for ARGS.");
error->assign(parseError(m_data.parsing_ctx_arg,
"Failed to parse document for ARGS"));
ms_dbg_a(m_transaction, 4, *error);

Check warning on line 329 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCU&open=AaE1XvywGsfaXwq_urCU&pullRequest=3679
return false;
}
}
Expand All @@ -325,6 +347,11 @@
/* Preserve the results for our reference. */
m_data.well_formed = m_data.parsing_ctx->wellFormed;
m_data.doc = m_data.parsing_ctx->myDoc;
std::string parse_error;
if (m_data.well_formed != 1) {
parse_error = parseError(m_data.parsing_ctx,
"Failed to parse document");
}

/* Clean up everything else. */
xmlFreeParserCtxt(m_data.parsing_ctx);
Expand All @@ -333,8 +360,8 @@
+ std::to_string(m_data.well_formed) + ").");

if (m_data.well_formed != 1) {
error->assign("XML: Failed to parse document.");
ms_dbg_a(m_transaction, 4, "XML: Failed to parse document.");
error->assign(parse_error);
ms_dbg_a(m_transaction, 4, *error);

Check warning on line 364 in src/request_body_processor/xml.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AaE1XvywGsfaXwq_urCV&open=AaE1XvywGsfaXwq_urCV&pullRequest=3679
return false;
}
}
Expand All @@ -352,7 +379,8 @@
error->assign(m_data.xml_error);
}
else {
error->assign("XML: Failed to parse document for ARGS.");
error->assign(parseError(m_data.parsing_ctx_arg,
"Failed to parse document for ARGS"));
}
xmlFreeParserCtxt(m_data.parsing_ctx_arg);
m_data.parsing_ctx_arg = NULL;
Expand Down
79 changes: 79 additions & 0 deletions test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,84 @@
"SecRule REQBODY_PROCESSOR_ERROR \"@contains test\" \"phase:2,id:1,pass,t:trim\"",
"SecRule REQBODY_PROCESSOR_ERROR_MSG \"@contains test\" \"phase:2,id:2,pass,t:trim\""
]
},
{
"enabled": 1,
"version_min": 300000,
"title": "Testing Variables :: REQBODY_ERROR_MSG carries the libxml2 parse error",
"resource": "libxml2",
"client": {
"ip": "200.249.12.31",
"port": 123
},
"server": {
"ip": "200.249.12.31",
"port": 80
},
"request": {
"headers": {
"Host": "localhost",
"User-Agent": "curl/7.38.0",
"Accept": "*/*",
"Content-Type": "text/xml",
"Content-Length": "736"
},
"uri": "/?key=value&key=other_value",
"method": "POST",
"http_version": 1.1,
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<bookstore>",
"<book category=\"COOKING\">",
"<title lang=\"en\">Everyday Italian</title>",
"<author>Giada De Laurentiis</author>",
"<year>2005</year>",
"<price>30.00</price>",
"</book>",
"<book category=\"CHILDREN\">",
"<title lang=\"en\">Harry Potter</title>",
"<author>J K. Rowling</author>",
"<year>2005</year>",
"<price>29.99</price>",
"</book>",
"<book category=\"WEB\">",
"<title lang=\"en\">XQuery Kick Start</title>",
"<author>James McGovern</author>",
"<author>Per Bothner</author>",
"<author>Kurt Cagle</author>",
"<author>James Linn</author>",
"<author>Vaidyanathan Nagarajan</author>",
"<year>2003</year>",
"<price>49.99</price>",
"</book>",
"<book category=\"WEB\">",
"<title lang=\"en\">Learning XML</title>",
"<author>Erik T. Ray</author>",
"<year>2003</year>",
"<price>39.95</price>",
"</bookasdf>",
"</bookstore>"
]
},
"response": {
"headers": {
"Date": "Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type": "text/html",
"Content-Length": "8"
},
"body": [
"no need."
]
},
"expected": {
"debug_log": "XML: Failed to parse document: Opening and ending tag mismatch: book line 1 and bookasdf \\(line 1, column [0-9]+\\)",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500005,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule REQBODY_ERROR_MSG \"@contains Opening and ending tag mismatch: book line 1 and bookasdf\" \"phase:2,id:3,deny,status:403\""
]
}
]
Loading