Adds offset regression tests and assorted fixes on var's offsets

This commit is contained in:
Felipe Zimmerle
2017-02-14 15:46:52 -03:00
committed by Felipe Zimmerle
parent 795994bb0e
commit 4ad3574cf2
25 changed files with 2228 additions and 117 deletions

View File

@@ -13,6 +13,9 @@
*
*/
#ifndef SRC_REQUEST_BODY_PROCESSOR_JSON_H_
#define SRC_REQUEST_BODY_PROCESSOR_JSON_H_
#ifdef WITH_YAJL
@@ -24,8 +27,6 @@
#include "modsecurity/transaction.h"
#include "modsecurity/rules.h"
#ifndef SRC_REQUEST_BODY_PROCESSOR_JSON_H_
#define SRC_REQUEST_BODY_PROCESSOR_JSON_H_
namespace modsecurity {
@@ -82,7 +83,6 @@ class JSON {
} // namespace RequestBodyProcessor
} // namespace modsecurity
#endif // WITH_YAJL
#endif // SRC_REQUEST_BODY_PROCESSOR_JSON_H_
#endif // WITH_YAJL

View File

@@ -25,6 +25,7 @@
#include <list>
#include <iostream>
#include <string>
#include <utility>
#include "modsecurity/collection/collections.h"
#include "modsecurity/rules.h"
@@ -212,7 +213,7 @@ void Multipart::validate_quotes(const char *data) {
}
int Multipart::parse_content_disposition(const char *c_d_value) {
int Multipart::parse_content_disposition(const char *c_d_value, int offset) {
const char *p = NULL;
/* accept only what we understand */
@@ -342,7 +343,8 @@ int Multipart::parse_content_disposition(const char *c_d_value) {
if (name == "name") {
validate_quotes(value.c_str());
m_transaction->m_variableMultiPartName.set(value, value, 0);
m_transaction->m_variableMultiPartName.set(value, value,
offset + ((p - c_d_value) - value.size()));
if (!m_mpp->m_name.empty()) {
debug(4, "Multipart: Warning: Duplicate Content-Disposition " \
@@ -350,10 +352,12 @@ int Multipart::parse_content_disposition(const char *c_d_value) {
return -14;
}
m_mpp->m_name.assign(value);
m_mpp->m_nameOffset = offset + ((p - c_d_value) - value.size());
debug(9, "Multipart: Content-Disposition name: " + value + ".");
} else if (name == "filename") {
validate_quotes(value.c_str());
m_transaction->m_variableMultiPartFileName.set(value, value, 0);
m_transaction->m_variableMultiPartFileName.set(value, value, \
offset + ((p - c_d_value) - value.size()));
if (!m_mpp->m_filename.empty()) {
debug(4, "Multipart: Warning: Duplicate Content-Disposition " \
@@ -361,6 +365,7 @@ int Multipart::parse_content_disposition(const char *c_d_value) {
return -15;
}
m_mpp->m_filename.assign(value);
m_mpp->m_filenameOffset = offset + ((p - c_d_value) - value.size());
debug(9, "Multipart: Content-Disposition filename: " \
+ value + ".");
@@ -432,7 +437,7 @@ int Multipart::tmp_file_name(std::string *filename) const {
}
int Multipart::process_part_data(std::string *error) {
int Multipart::process_part_data(std::string *error, size_t offset) {
char *p = m_buf + (MULTIPART_BUF_SIZE - m_bufleft);
char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */
int bytes_reserved = 0;
@@ -525,7 +530,11 @@ int Multipart::process_part_data(std::string *error) {
return -1;
}
m_mpp->m_tmp_file_size += m_reserve[0];
m_mpp->m_tmp_file_size.first += m_reserve[0];
if (m_mpp->m_tmp_file_size.second == 0) {
m_mpp->m_tmp_file_size.second = offset \
- m_mpp->m_tmp_file_size.first;
}
m_mpp->m_length += m_reserve[0];
}
@@ -541,12 +550,26 @@ int Multipart::process_part_data(std::string *error) {
return -1;
}
m_mpp->m_tmp_file_size += (MULTIPART_BUF_SIZE - m_bufleft);
m_mpp->m_value.append(std::string(m_buf,
MULTIPART_BUF_SIZE - m_bufleft));
m_mpp->m_valueOffset = offset - (MULTIPART_BUF_SIZE - m_bufleft);
m_mpp->m_tmp_file_size.first += (MULTIPART_BUF_SIZE - m_bufleft);
if (m_mpp->m_tmp_file_size.second == 0) {
m_mpp->m_tmp_file_size.second = offset \
- m_mpp->m_tmp_file_size.first;
}
m_mpp->m_length += (MULTIPART_BUF_SIZE - m_bufleft);
} else {
/* just keep track of the file size */
m_mpp->m_tmp_file_size += (MULTIPART_BUF_SIZE - m_bufleft) \
m_mpp->m_tmp_file_size.first += (MULTIPART_BUF_SIZE - m_bufleft) \
+ m_reserve[0];
if (m_mpp->m_tmp_file_size.second == 0) {
m_mpp->m_tmp_file_size.second = offset \
- m_mpp->m_tmp_file_size.first;
}
m_mpp->m_length += (MULTIPART_BUF_SIZE - m_bufleft) + m_reserve[0];
}
} else if (m_mpp->m_type == MULTIPART_FORMDATA) {
@@ -573,7 +596,7 @@ int Multipart::process_part_data(std::string *error) {
m_mpp->m_length += d.size();
}
m_mpp->m_value_parts.push_back(d);
m_mpp->m_value_parts.push_back(std::make_pair(d, m_buf_offset));
debug(9, "Multipart: Added data to variable: " + d);
} else {
@@ -601,7 +624,7 @@ int Multipart::process_part_data(std::string *error) {
}
int Multipart::process_part_header(std::string *error) {
int Multipart::process_part_header(std::string *error, int offset) {
int i, len;
/* Check for nul bytes. */
@@ -614,6 +637,7 @@ int Multipart::process_part_header(std::string *error) {
}
}
i = 0;
/* The buffer is data so increase the data length counter. */
m_reqbody_no_files_length += (MULTIPART_BUF_SIZE - m_bufleft);
@@ -639,9 +663,10 @@ int Multipart::process_part_header(std::string *error) {
"Content-Disposition header.");
return false;
}
header_value = m_mpp->m_headers.at("Content-Disposition");
header_value = m_mpp->m_headers.at("Content-Disposition").second;
rc = parse_content_disposition(header_value.c_str());
rc = parse_content_disposition(header_value.c_str(),
m_mpp->m_headers.at("Content-Disposition").first);
if (rc < 0) {
debug(1, "Multipart: Invalid Content-Disposition header ("
+ std::to_string(rc) + "): " + header_value);
@@ -714,15 +739,17 @@ int Multipart::process_part_header(std::string *error) {
m_flag_invalid_header_folding = 1;
}
data++;
i++;
}
new_value = std::string(data);
utils::string::chomp(&new_value);
/* update the header value in the table */
header_value = m_mpp->m_headers.at(m_mpp->m_last_header_name);
header_value = m_mpp->m_headers.at(
m_mpp->m_last_header_name).second;
new_value = header_value + " " + new_value;
m_mpp->m_headers.at(m_mpp->m_last_header_name) = new_value;
m_mpp->m_headers.at(m_mpp->m_last_header_name).second = new_value;
debug(9, "Multipart: Continued folder header \"" \
+ m_mpp->m_last_header_name + "\" with \"" \
@@ -742,6 +769,7 @@ int Multipart::process_part_header(std::string *error) {
data = m_buf;
while ((*data != ':') && (*data != '\0')) {
data++;
i++;
}
if (*data == '\0') {
debug(1, "Multipart: Invalid part header (colon missing): " \
@@ -763,8 +791,10 @@ int Multipart::process_part_header(std::string *error) {
/* extract the value value */
data++;
i++;
while ((*data == '\t') || (*data == ' ')) {
data++;
i++;
}
header_value = std::string(data);
utils::string::chomp(&header_value);
@@ -780,7 +810,8 @@ int Multipart::process_part_header(std::string *error) {
m_mpp->m_headers.emplace(
std::string(header_name), std::string(header_value));
std::string(header_name), std::make_pair(offset - len + i,
std::string(header_value)));
debug(9, "Multipart: Added part header \"" + header_name \
@@ -805,8 +836,11 @@ int Multipart::process_boundary(int last_part) {
if (m_mpp->m_type != MULTIPART_FILE) {
/* now construct a single string out of the parts */
for (std::string &i : m_mpp->m_value_parts) {
m_mpp->m_value.append(i);
for (const auto &i : m_mpp->m_value_parts) {
if (m_mpp->m_valueOffset == 0) {
m_mpp->m_valueOffset = i.second;
}
m_mpp->m_value.append(i.first);
}
}
@@ -986,6 +1020,7 @@ int Multipart::multipart_complete(std::string *error) {
if (m->m_name.empty()) {
continue;
}
size_t offset = m_transaction->m_variableOffset + 1;
if (m->m_type == MULTIPART_FILE) {
std::string tmp_name;
@@ -996,25 +1031,36 @@ int Multipart::multipart_complete(std::string *error) {
if (!m->m_filename.empty()) {
name.assign(m->m_filename);
}
m_transaction->m_variableFiles.set(m->m_filename,
m->m_filename, 0);
m_transaction->m_variableFilesNames.set(m->m_name,
m->m_name, 0);
m->m_filename, m->m_filenameOffset);
m_transaction->m_variableFilesNames.set(m->m_filename,
m->m_filename, m->m_filenameOffset);
m_transaction->m_variableFilesSizes.set(m->m_name,
std::to_string(m->m_tmp_file_size), 0);
m_transaction->m_variableFilesTmpContent.set(m->m_name,
m->m_value, 0);
m_transaction->m_variableFilesTmpContent.set(m->m_name,
m->m_value, 0);
m_transaction->m_variableFilesTmpNames.set(m->m_name,
m->m_value, 0);
file_combined_size = file_combined_size + m->m_tmp_file_size;
std::to_string(m->m_tmp_file_size.first),
m->m_tmp_file_size.second,
m->m_tmp_file_size.first);
m_transaction->m_variableFilesTmpContent.set(m->m_filename,
m->m_value, m->m_valueOffset);
m_transaction->m_variableFilesTmpNames.set(m->m_filename,
m->m_filename, m->m_filenameOffset);
file_combined_size = file_combined_size + m->m_tmp_file_size.first;
m_transaction->m_variableFilesCombinedSize.set(
std::to_string(file_combined_size),
m->m_tmp_file_size.second, m->m_tmp_file_size.first);
} else {
debug(4, "Adding request argument (BODY): name \"" +
m->m_name + "\", value \"" + m->m_value + "\"");
m_transaction->m_variableArgs.set(m->m_name, m->m_value,
m_transaction->m_variableOffset);
m_transaction->m_variableArgsPost.set(m->m_name, m->m_value, 0);
offset + m->m_valueOffset);
m_transaction->m_variableArgsPost.set(m->m_name, m->m_value,
offset + m->m_valueOffset);
}
#if 0
if (m_transaction->m_namesArgs->empty()) {
@@ -1036,9 +1082,7 @@ int Multipart::multipart_complete(std::string *error) {
std::to_string(m_transaction->->m_ARGScombinedSize));
#endif
}
m_transaction->m_variableFilesCombinedSize.set(
std::to_string(file_combined_size),
m_transaction->m_variableOffset);
return true;
}
@@ -1256,12 +1300,13 @@ bool Multipart::init(std::string *error) {
* Assuming that all data is on data. We are not processing chunks.
*
*/
bool Multipart::process(const std::string& data, std::string *error) {
bool Multipart::process(const std::string& data, std::string *error,
int offset) {
const char *inptr = data.c_str();
unsigned int inleft = data.size();
size_t z = 0;
if (data.size() == 0) return true;
m_seen_data = true;
if (m_is_complete) {
@@ -1285,6 +1330,8 @@ bool Multipart::process(const std::string& data, std::string *error) {
char c = *inptr;
int process_buffer = 0;
z++;
if ((c == '\r') && (m_bufleft == 1)) {
/* we don't want to take \r as the last byte in the buffer */
process_buffer = 1;
@@ -1443,13 +1490,13 @@ bool Multipart::process(const std::string& data, std::string *error) {
return false;
}
if (process_part_header(error) < 0) {
if (process_part_header(error, offset + z) < 0) {
m_flag_error = 1;
return false;
}
} else {
if (process_part_data(error) < 0) {
if (process_part_data(error, offset + z) < 0) {
m_flag_error = 1;
return false;
}

View File

@@ -17,6 +17,7 @@
#include <iostream>
#include <list>
#include <unordered_map>
#include <utility>
#ifndef SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
#define SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
@@ -58,9 +59,14 @@ class MultipartPart {
MultipartPart()
: m_type(MULTIPART_FORMDATA),
m_tmp_file_fd(0),
m_tmp_file_size(0),
m_offset(0),
m_length(0) { }
m_filenameOffset(0),
m_nameOffset(0),
m_valueOffset(0),
m_length(0) {
m_tmp_file_size.first = 0;
m_tmp_file_size.second = 0;
}
~MultipartPart() {
m_headers.clear();
@@ -72,10 +78,13 @@ class MultipartPart {
/* the name */
std::string m_name;
size_t m_nameOffset;
/* variables only, variable value */
std::string m_value;
std::list<std::string> m_value_parts;
size_t m_valueOffset;
std::list<std::pair<std::string, int>> m_value_parts;
/* files only, the content type (where available) */
/* std::string m_content_type; */
@@ -83,13 +92,15 @@ class MultipartPart {
/* files only, the name of the temporary file holding data */
std::string m_tmp_file_name;
int m_tmp_file_fd;
unsigned int m_tmp_file_size;
std::pair<size_t, size_t> m_tmp_file_size;
/* files only, filename as supplied by the browser */
std::string m_filename;
size_t m_filenameOffset;
std::string m_last_header_name;
std::unordered_map<std::string, std::string, MyHash, MyEqual> m_headers;
std::unordered_map<std::string, std::pair<size_t, std::string>,
MyHash, MyEqual> m_headers;
unsigned int m_offset;
unsigned int m_length;
@@ -108,11 +119,11 @@ class Multipart {
int is_token_char(unsigned char c);
int multipart_complete(std::string *err);
int parse_content_disposition(const char *c_d_value);
bool process(const std::string& data, std::string *err);
int parse_content_disposition(const char *c_d_value, int offset);
bool process(const std::string& data, std::string *err, int offset);
int process_boundary(int last_part);
int process_part_header(std::string *error);
int process_part_data(std::string *error);
int process_part_header(std::string *error, int offset);
int process_part_data(std::string *error, size_t offset);
int tmp_file_name(std::string *filename) const;