mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
Fix: Only delete Multipart tmp files after rules have run
This commit is contained in:
committed by
Felipe Zimmerle
parent
1b7aa42c77
commit
d72be1c470
@@ -38,6 +38,61 @@ namespace RequestBodyProcessor {
|
||||
static const char* mime_charset_special = "!#$%&+-^_`{}~";
|
||||
static const char* attr_char_special = "!#$&+-.^_`~";
|
||||
|
||||
MultipartPartTmpFile::~MultipartPartTmpFile() {
|
||||
if (!m_tmp_file_name.empty() && m_delete) {
|
||||
/* make sure it is closed first */
|
||||
if (m_tmp_file_fd > 0) {
|
||||
Close();
|
||||
}
|
||||
|
||||
const int unlink_rc = unlink(m_tmp_file_name.c_str());
|
||||
if (unlink_rc < 0) {
|
||||
ms_dbg_a(m_transaction, 1, "Multipart: Failed to delete file (part) \"" \
|
||||
+ m_tmp_file_name + "\" because " \
|
||||
+ std::to_string(errno) + "(" \
|
||||
+ strerror(errno) + ")");
|
||||
} else {
|
||||
ms_dbg_a(m_transaction, 4, "Multipart: file deleted successfully (part) \"" \
|
||||
+ m_tmp_file_name + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void MultipartPartTmpFile::Open() {
|
||||
struct tm timeinfo;
|
||||
char tstr[300];
|
||||
time_t tt = time(NULL);
|
||||
|
||||
localtime_r(&tt, &timeinfo);
|
||||
|
||||
memset(tstr, '\0', 300);
|
||||
strftime(tstr, 299, "/%Y%m%d-%H%M%S", &timeinfo);
|
||||
|
||||
std::string path = m_transaction->m_rules->m_uploadDirectory.m_value;
|
||||
path = path + tstr + "-" + *m_transaction->m_id.get();
|
||||
path += "-file-XXXXXX";
|
||||
|
||||
char* tmp = strdup(path.c_str());
|
||||
m_tmp_file_fd = mkstemp(tmp);
|
||||
m_tmp_file_name.assign(tmp);
|
||||
free(tmp);
|
||||
ms_dbg_a(m_transaction, 4, "MultipartPartTmpFile: Create filename= " + m_tmp_file_name);
|
||||
|
||||
int mode = m_transaction->m_rules->m_uploadFileMode.m_value;
|
||||
if ((m_tmp_file_fd != -1) && (mode != 0)) {
|
||||
if (fchmod(m_tmp_file_fd, mode) == -1) {
|
||||
m_tmp_file_fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultipartPartTmpFile::Close() {
|
||||
close(m_tmp_file_fd);
|
||||
m_tmp_file_fd = -1;
|
||||
}
|
||||
|
||||
|
||||
Multipart::Multipart(const std::string &header, Transaction *transaction)
|
||||
: m_reqbody_no_files_length(0),
|
||||
m_nfiles(0),
|
||||
@@ -80,30 +135,14 @@ Multipart::~Multipart() {
|
||||
if (m_transaction->m_rules->m_uploadKeepFiles
|
||||
!= RulesSetProperties::TrueConfigBoolean) {
|
||||
for (MultipartPart *m : m_parts) {
|
||||
if (m->m_type == MULTIPART_FILE) {
|
||||
if (!m->m_tmp_file_name.empty()) {
|
||||
/* make sure it is closed first */
|
||||
if (m->m_tmp_file_fd > 0) {
|
||||
close(m->m_tmp_file_fd);
|
||||
m->m_tmp_file_fd = -1;
|
||||
}
|
||||
const int unlink_rc =
|
||||
unlink(m->m_tmp_file_name.c_str());
|
||||
|
||||
if (unlink_rc < 0) {
|
||||
ms_dbg_a(m_transaction, 1,
|
||||
"Multipart: Failed to delete file (part) \"" \
|
||||
+ m->m_tmp_file_name + "\" because " \
|
||||
+ std::to_string(errno) + "(" \
|
||||
+ strerror(errno) + ")");
|
||||
} else {
|
||||
ms_dbg_a(m_transaction, 4,
|
||||
"Multipart: file deleted successfully (part) \"" \
|
||||
+ m->m_tmp_file_name + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
if ((m->m_type == MULTIPART_FILE) && (m->m_tmp_file)) {
|
||||
// only mark for deletion for now; the file should stay on disk until
|
||||
// the transaction is complete
|
||||
ms_dbg_a(m_transaction, 9, "Multipart: Marking temporary file for deletion: " \
|
||||
+ m->m_tmp_file->getFilename());
|
||||
m->m_tmp_file->setDelete();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +471,7 @@ int Multipart::parse_content_disposition(const char *c_d_value, int offset) {
|
||||
+ std::to_string(strlen(p)) + " bytes");
|
||||
m_flag_invalid_quoting = 1;
|
||||
}
|
||||
p++;
|
||||
/* p++; */
|
||||
return -12;
|
||||
}
|
||||
p++; /* move over the semi-colon */
|
||||
@@ -453,40 +492,6 @@ int Multipart::parse_content_disposition(const char *c_d_value, int offset) {
|
||||
}
|
||||
|
||||
|
||||
int Multipart::tmp_file_name(std::string *filename) const {
|
||||
std::string path;
|
||||
struct tm timeinfo;
|
||||
char tstr[300];
|
||||
char *tmp;
|
||||
int fd;
|
||||
int mode;
|
||||
time_t tt = time(NULL);
|
||||
|
||||
localtime_r(&tt, &timeinfo);
|
||||
|
||||
path = m_transaction->m_rules->m_uploadDirectory.m_value;
|
||||
mode = m_transaction->m_rules->m_uploadFileMode.m_value;
|
||||
|
||||
memset(tstr, '\0', 300);
|
||||
strftime(tstr, 299, "/%Y%m%d-%H%M%S", &timeinfo);
|
||||
path = path + tstr + "-" + *m_transaction->m_id.get();
|
||||
path = path + "-file-XXXXXX";
|
||||
|
||||
tmp = strdup(path.c_str());
|
||||
|
||||
fd = mkstemp(tmp);
|
||||
filename->assign(tmp);
|
||||
free(tmp);
|
||||
if ((fd != -1) && (mode != 0)) {
|
||||
if (fchmod(fd, mode) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
@@ -546,20 +551,18 @@ int Multipart::process_part_data(std::string *error, size_t offset) {
|
||||
*/
|
||||
if (extract) {
|
||||
/* first create a temporary file if we don't have it already */
|
||||
if (m_mpp->m_tmp_file_fd == 0) {
|
||||
std::string path;
|
||||
m_mpp->m_tmp_file_fd = tmp_file_name(&path);
|
||||
|
||||
/* construct temporary file name */
|
||||
m_mpp->m_tmp_file_name = path;
|
||||
if (!m_mpp->m_tmp_file || !m_mpp->m_tmp_file->isValid()) {
|
||||
m_mpp->m_tmp_file = std::make_shared<RequestBodyProcessor::MultipartPartTmpFile>(m_transaction);
|
||||
m_transaction->m_multipartPartTmpFiles.push_back(m_mpp->m_tmp_file);
|
||||
m_mpp->m_tmp_file->Open();
|
||||
|
||||
/* do we have an opened file? */
|
||||
if (m_mpp->m_tmp_file_fd < 0) {
|
||||
if (!m_mpp->m_tmp_file || m_mpp->m_tmp_file->getFd() < 0) {
|
||||
ms_dbg_a(m_transaction, 1,
|
||||
"Multipart: Failed to create file: " \
|
||||
+ m_mpp->m_tmp_file_name);
|
||||
+ m_mpp->m_tmp_file->getFilename());
|
||||
error->assign("Multipart: Failed to create file: " \
|
||||
+ m_mpp->m_tmp_file_name);
|
||||
+ m_mpp->m_tmp_file->getFilename());
|
||||
return -1;
|
||||
}
|
||||
/* keep track of the files count */
|
||||
@@ -569,18 +572,18 @@ int Multipart::process_part_data(std::string *error, size_t offset) {
|
||||
ms_dbg_a(m_transaction, 4,
|
||||
"Multipart: Created temporary file " \
|
||||
+ std::to_string(m_nfiles) + " (mode o" + std::to_string(m_transaction->m_rules->m_uploadFileMode.m_value) + "): " \
|
||||
+ m_mpp->m_tmp_file_name);
|
||||
+ m_mpp->m_tmp_file->getFilename());
|
||||
}
|
||||
|
||||
/* write the reserve first */
|
||||
if (m_reserve[0] != 0) {
|
||||
if (write(m_mpp->m_tmp_file_fd, &m_reserve[1], m_reserve[0])
|
||||
if (write(m_mpp->m_tmp_file->getFd(), &m_reserve[1], m_reserve[0])
|
||||
!= m_reserve[0]) {
|
||||
ms_dbg_a(m_transaction, 1,
|
||||
"Multipart: writing to \"" \
|
||||
+ m_mpp->m_tmp_file_name + "\" failed");
|
||||
+ m_mpp->m_tmp_file->getFilename() + "\" failed");
|
||||
error->assign("Multipart: writing to \"" \
|
||||
+ m_mpp->m_tmp_file_name + "\" failed");
|
||||
+ m_mpp->m_tmp_file->getFilename() + "\" failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -594,14 +597,14 @@ int Multipart::process_part_data(std::string *error, size_t offset) {
|
||||
|
||||
/* write data to the file */
|
||||
|
||||
if (write(m_mpp->m_tmp_file_fd, m_buf,
|
||||
if (write(m_mpp->m_tmp_file->getFd(), m_buf,
|
||||
MULTIPART_BUF_SIZE - m_bufleft)
|
||||
!= (MULTIPART_BUF_SIZE - m_bufleft)) {
|
||||
ms_dbg_a(m_transaction, 1,
|
||||
"Multipart: writing to \"" \
|
||||
+ m_mpp->m_tmp_file_name + "\" failed");
|
||||
+ m_mpp->m_tmp_file->getFilename() + "\" failed");
|
||||
error->assign("Multipart: writing to \"" \
|
||||
+ m_mpp->m_tmp_file_name + "\" failed");
|
||||
+ m_mpp->m_tmp_file->getFilename() + "\" failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -911,11 +914,9 @@ int Multipart::process_boundary(int last_part) {
|
||||
/* if there was a part being built finish it */
|
||||
if (m_mpp != NULL) {
|
||||
/* close the temp file */
|
||||
if ((m_mpp->m_type == MULTIPART_FILE)
|
||||
&& (!m_mpp->m_tmp_file_name.empty())
|
||||
&& (m_mpp->m_tmp_file_fd != 0)) {
|
||||
close(m_mpp->m_tmp_file_fd);
|
||||
m_mpp->m_tmp_file_fd = -1;
|
||||
if ((m_mpp->m_type == MULTIPART_FILE) && (m_mpp->m_tmp_file)
|
||||
&& (m_mpp->m_tmp_file->isValid())) {
|
||||
m_mpp->m_tmp_file->Close();
|
||||
}
|
||||
|
||||
if (m_mpp->m_type != MULTIPART_FILE) {
|
||||
@@ -1128,8 +1129,10 @@ int Multipart::multipart_complete(std::string *error) {
|
||||
if (m->m_type == MULTIPART_FILE) {
|
||||
std::string tmp_name;
|
||||
std::string name;
|
||||
if (!m->m_tmp_file_name.empty()) {
|
||||
tmp_name.assign(m->m_tmp_file_name);
|
||||
if (m->m_tmp_file && !m->m_tmp_file->getFilename().empty()) {
|
||||
tmp_name.assign(m->m_tmp_file->getFilename());
|
||||
m_transaction->m_variableFilesTmpNames.set(m->m_tmp_file->getFilename(),
|
||||
m->m_tmp_file->getFilename(), m->m_filenameOffset);
|
||||
}
|
||||
if (!m->m_filename.empty()) {
|
||||
name.assign(m->m_filename);
|
||||
@@ -1149,9 +1152,6 @@ int Multipart::multipart_complete(std::string *error) {
|
||||
m_transaction->m_variableFilesTmpContent.set(m->m_filename,
|
||||
m->m_value, m->m_valueOffset);
|
||||
|
||||
m_transaction->m_variableFilesTmpNames.set(m->m_tmp_file_name,
|
||||
m->m_tmp_file_name, m->m_filenameOffset);
|
||||
|
||||
file_combined_size = file_combined_size + m->m_tmp_file_size.first;
|
||||
|
||||
m_transaction->m_variableFilesCombinedSize.set(
|
||||
|
@@ -54,6 +54,38 @@ struct MyEqual {
|
||||
};
|
||||
|
||||
|
||||
class MultipartPartTmpFile {
|
||||
public:
|
||||
explicit MultipartPartTmpFile(Transaction *transaction)
|
||||
: m_transaction(transaction),
|
||||
m_tmp_file_fd(0),
|
||||
m_delete(false)
|
||||
{ }
|
||||
|
||||
~MultipartPartTmpFile();
|
||||
|
||||
// forbid copying
|
||||
MultipartPartTmpFile(const MultipartPartTmpFile&) = delete;
|
||||
MultipartPartTmpFile& operator=(const MultipartPartTmpFile&) = delete;
|
||||
|
||||
int getFd() const {return m_tmp_file_fd;}
|
||||
void setFd(int fd) {m_tmp_file_fd = fd;}
|
||||
const std::string& getFilename() const {return m_tmp_file_name;}
|
||||
void setDelete() {m_delete = true;}
|
||||
|
||||
bool isValid() const {return ((m_tmp_file_fd != 0) && (!m_tmp_file_name.empty()));}
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
|
||||
private:
|
||||
Transaction *m_transaction;
|
||||
int m_tmp_file_fd;
|
||||
std::string m_tmp_file_name;
|
||||
bool m_delete; // whether to delete when transaction is done
|
||||
};
|
||||
|
||||
|
||||
class MultipartPart {
|
||||
public:
|
||||
MultipartPart()
|
||||
@@ -63,8 +95,6 @@ class MultipartPart {
|
||||
m_value(""),
|
||||
m_valueOffset(0),
|
||||
m_value_parts(),
|
||||
m_tmp_file_name(""),
|
||||
m_tmp_file_fd(0),
|
||||
m_tmp_file_size(),
|
||||
m_filename(""),
|
||||
m_filenameOffset(0),
|
||||
@@ -98,8 +128,7 @@ class MultipartPart {
|
||||
/* std::string m_content_type; */
|
||||
|
||||
/* files only, the name of the temporary file holding data */
|
||||
std::string m_tmp_file_name;
|
||||
int m_tmp_file_fd;
|
||||
std::shared_ptr<RequestBodyProcessor::MultipartPartTmpFile> m_tmp_file;
|
||||
std::pair<size_t, size_t> m_tmp_file_size;
|
||||
|
||||
/* files only, filename as supplied by the browser */
|
||||
@@ -133,8 +162,6 @@ class Multipart {
|
||||
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;
|
||||
|
||||
void validate_quotes(const char *data);
|
||||
|
||||
size_t m_reqbody_no_files_length;
|
||||
|
Reference in New Issue
Block a user