Perform NormalisePath & NormalisePathWin transformations in-place

This commit is contained in:
Eduardo Arias
2024-08-19 10:20:12 -07:00
parent 2c3c228725
commit 021d0caa33
3 changed files with 24 additions and 58 deletions

View File

@@ -25,23 +25,7 @@ NormalisePath::NormalisePath(const std::string &action)
} }
bool NormalisePath::transform(std::string &value, const Transaction *trans) const { bool NormalisePath::transform(std::string &value, const Transaction *trans) const {
int _changed = 0; return normalize_path_inplace(value, false);
char *tmp = reinterpret_cast<char *>(
malloc(sizeof(char) * value.size() + 1));
memcpy(tmp, value.c_str(), value.size() + 1);
tmp[value.size()] = '\0';
int i = normalize_path_inplace((unsigned char *)tmp,
value.size(), 0, &_changed);
std::string ret("");
ret.assign(tmp, i);
free(tmp);
const auto changed = ret != value;
value = ret;
return changed;
} }
@@ -49,21 +33,22 @@ bool NormalisePath::transform(std::string &value, const Transaction *trans) cons
* *
* IMP1 Assumes NUL-terminated * IMP1 Assumes NUL-terminated
*/ */
int NormalisePath::normalize_path_inplace(unsigned char *input, int input_len, bool NormalisePath::normalize_path_inplace(std::string &val, const bool win) {
int win, int *changed) {
unsigned char *src; unsigned char *src;
unsigned char *dst; unsigned char *dst;
unsigned char *end; unsigned char *end;
int ldst = 0;
int hitroot = 0; int hitroot = 0;
int done = 0; int done = 0;
int relative; int relative;
int trailing; int trailing;
*changed = 0; bool changed = false;
/* Need at least one byte to normalize */ /* Need at least one byte to normalize */
if (input_len <= 0) return 0; if(val.empty()) return false;
auto input = reinterpret_cast<unsigned char*>(val.data());
const auto input_len = val.length();
/* /*
* ENH: Deal with UNC and drive letters? * ENH: Deal with UNC and drive letters?
@@ -71,7 +56,6 @@ int NormalisePath::normalize_path_inplace(unsigned char *input, int input_len,
src = dst = input; src = dst = input;
end = input + (input_len - 1); end = input + (input_len - 1);
ldst = 1;
relative = ((*input == '/') || (win && (*input == '\\'))) ? 0 : 1; relative = ((*input == '/') || (win && (*input == '\\'))) ? 0 : 1;
trailing = ((*end == '/') || (win && (*end == '\\'))) ? 1 : 0; trailing = ((*end == '/') || (win && (*end == '\\'))) ? 1 : 0;
@@ -82,11 +66,11 @@ int NormalisePath::normalize_path_inplace(unsigned char *input, int input_len,
if (win) { if (win) {
if (*src == '\\') { if (*src == '\\') {
*src = '/'; *src = '/';
*changed = 1; changed = true;
} }
if ((src < end) && (*(src + 1) == '\\')) { if ((src < end) && (*(src + 1) == '\\')) {
*(src + 1) = '/'; *(src + 1) = '/';
*changed = 1; changed = true;
} }
} }
@@ -104,7 +88,7 @@ int NormalisePath::normalize_path_inplace(unsigned char *input, int input_len,
/* Could it be an empty path segment? */ /* Could it be an empty path segment? */
if ((src != end) && *src == '/') { if ((src != end) && *src == '/') {
/* Ignore */ /* Ignore */
*changed = 1; changed = true;
goto copy; /* Copy will take care of this. */ goto copy; /* Copy will take care of this. */
} else if (*src == '.') { } else if (*src == '.') {
/* Could it be a back or self reference? */ /* Could it be a back or self reference? */
@@ -141,25 +125,25 @@ int NormalisePath::normalize_path_inplace(unsigned char *input, int input_len,
} }
} }
if (done) goto length; /* Skip the copy. */ if (done) goto skip_copy; /* Skip the copy. */
src++; src++;
*changed = 1; changed = true;
} else if (dst == input) { } else if (dst == input) {
/* Relative Self-reference? */ /* Relative Self-reference? */
*changed = 1; changed = true;
/* Ignore. */ /* Ignore. */
if (done) goto length; /* Skip the copy. */ if (done) goto skip_copy; /* Skip the copy. */
src++; src++;
} else if (*(dst - 1) == '/') { } else if (*(dst - 1) == '/') {
/* Self-reference? */ /* Self-reference? */
*changed = 1; changed = true;
/* Ignore. */ /* Ignore. */
if (done) goto length; /* Skip the copy. */ if (done) goto skip_copy; /* Skip the copy. */
dst--; dst--;
src++; src++;
} }
@@ -179,7 +163,7 @@ copy:
&& ((*(src + 1) == '/') || (win && (*(src + 1) == '\\'))) ) { && ((*(src + 1) == '/') || (win && (*(src + 1) == '\\'))) ) {
src++; src++;
} }
if (oldsrc != src) *changed = 1; if (oldsrc != src) changed = true;
/* Do not copy the forward slash to the root /* Do not copy the forward slash to the root
* if it is not a relative path. Instead * if it is not a relative path. Instead
@@ -187,27 +171,27 @@ copy:
*/ */
if (relative && (dst == input)) { if (relative && (dst == input)) {
src++; src++;
goto length; /* Skip the copy */ goto skip_copy; /* Skip the copy */
} }
} }
*(dst++) = *(src++); *(dst++) = *(src++);
length: skip_copy:
ldst = (dst - input); ; // nop for the goto label to work
} }
/* Make sure that there is not a trailing slash in the /* Make sure that there is not a trailing slash in the
* normalized form if there was not one in the original form. * normalized form if there was not one in the original form.
*/ */
if (!trailing && (dst > input) && *(dst - 1) == '/') { if (!trailing && (dst > input) && *(dst - 1) == '/') {
ldst--;
dst--; dst--;
} }
/* Always NUL terminate */ /* Always NUL terminate */
*dst = '\0'; *dst = '\0';
return ldst; val.resize(dst - input);
return changed;
} }

View File

@@ -26,8 +26,7 @@ class NormalisePath : public Transformation {
bool transform(std::string &value, const Transaction *trans) const override; bool transform(std::string &value, const Transaction *trans) const override;
static int normalize_path_inplace(unsigned char *input, int input_len, static bool normalize_path_inplace(std::string &val, const bool win);
int win, int *changed);
}; };
} // namespace modsecurity::actions::transformations } // namespace modsecurity::actions::transformations

View File

@@ -22,24 +22,7 @@ namespace modsecurity::actions::transformations {
bool NormalisePathWin::transform(std::string &value, const Transaction *trans) const { bool NormalisePathWin::transform(std::string &value, const Transaction *trans) const {
int _changed; return NormalisePath::normalize_path_inplace(value, true);
char *tmp = reinterpret_cast<char *>(
malloc(sizeof(char) * value.size() + 1));
memcpy(tmp, value.c_str(), value.size() + 1);
tmp[value.size()] = '\0';
int i = NormalisePath::normalize_path_inplace(
reinterpret_cast<unsigned char *>(tmp),
value.size(), 1, &_changed);
std::string ret("");
ret.assign(tmp, i);
free(tmp);
const auto changed = ret != value;
value = ret;
return changed;
} }