[njs] Handling zero byte characters inside RegExp pattern strings.
Dmitry Volyntsev
xeioex at nginx.com
Tue Jun 4 09:45:46 UTC 2019
details: https://hg.nginx.org/njs/rev/f57cf6b5233a
branches:
changeset: 998:f57cf6b5233a
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Jun 04 12:45:06 2019 +0300
description:
Handling zero byte characters inside RegExp pattern strings.
Fixed heap-buffer-overflow in RegExp.prototype.source.
This closes #168 issue on Github.
diffstat:
njs/njs_regexp.c | 31 +++++++++++++++++++++++++++----
njs/test/njs_unit_test.c | 24 ++++++++++++++++++++++++
2 files changed, 51 insertions(+), 4 deletions(-)
diffs (118 lines):
diff -r 2054b8410a28 -r f57cf6b5233a njs/njs_regexp.c
--- a/njs/njs_regexp.c Thu May 30 20:05:14 2019 +0300
+++ b/njs/njs_regexp.c Tue Jun 04 12:45:06 2019 +0300
@@ -207,17 +207,19 @@ njs_regexp_create(njs_vm_t *vm, njs_valu
/*
- * PCRE with PCRE_JAVASCRIPT_COMPAT flag rejects regexps with
+ * 1) PCRE with PCRE_JAVASCRIPT_COMPAT flag rejects regexps with
* lone closing square brackets as invalid. Whereas according
* to ES6: 11.8.5 it is a valid regexp expression.
*
+ * 2) escaping zero byte characters as "\u0000".
+ *
* Escaping it here as a workaround.
*/
nxt_inline njs_ret_t
njs_regexp_escape(njs_vm_t *vm, nxt_str_t *text)
{
- size_t brackets;
+ size_t brackets, zeros;
u_char *p, *dst, *start, *end;
nxt_bool_t in;
@@ -225,6 +227,7 @@ njs_regexp_escape(njs_vm_t *vm, nxt_str_
end = text->start + text->length;
in = 0;
+ zeros = 0;
brackets = 0;
for (p = start; p < end; p++) {
@@ -244,14 +247,24 @@ njs_regexp_escape(njs_vm_t *vm, nxt_str_
case '\\':
p++;
+
+ if (p == end || *p != '\0') {
+ break;
+ }
+
+ /* Fall through. */
+
+ case '\0':
+ zeros++;
+ break;
}
}
- if (!brackets) {
+ if (!brackets && !zeros) {
return NXT_OK;
}
- text->length = text->length + brackets;
+ text->length = text->length + brackets + zeros * nxt_length("\\u0000");
text->start = nxt_mp_alloc(vm->mem_pool, text->length);
if (nxt_slow_path(text->start == NULL)) {
@@ -283,6 +296,16 @@ njs_regexp_escape(njs_vm_t *vm, nxt_str_
if (p == end) {
goto done;
}
+
+ if (*p != '\0') {
+ break;
+ }
+
+ /* Fall through. */
+
+ case '\0':
+ dst = nxt_cpymem(dst, "\\u0000", 6);
+ continue;
}
*dst++ = *p;
diff -r 2054b8410a28 -r f57cf6b5233a njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Thu May 30 20:05:14 2019 +0300
+++ b/njs/test/njs_unit_test.c Tue Jun 04 12:45:06 2019 +0300
@@ -5564,6 +5564,9 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("/]cd/"),
nxt_string("/\\]cd/") },
+ { nxt_string("RegExp('\\\\0').source[1]"),
+ nxt_string("0") },
+
{ nxt_string("']'.match(/]/)"),
nxt_string("]") },
@@ -12812,6 +12815,27 @@ static njs_unit_test_t njs_regexp_test[
{ nxt_string("/[\\uFDE0-\\uFFFD]/g; export default 1"),
nxt_string("SyntaxError: Illegal export statement in 1") },
+
+ { nxt_string("RegExp(RegExp('\x00]]')).test('\x00]]')"),
+ nxt_string("true") },
+
+ { nxt_string("RegExp('\0').test('\0')"),
+ nxt_string("true") },
+
+ { nxt_string("RegExp('\x00').test('\0')"),
+ nxt_string("true") },
+
+ { nxt_string("RegExp('\x00\\\\x00').source"),
+ nxt_string("\\u0000\\x00") },
+
+ { nxt_string("/\\\0/"),
+ nxt_string("/\\\\u0000/") },
+
+ { nxt_string("RegExp('\\\\\\0').source"),
+ nxt_string("\\\\u0000") },
+
+ { nxt_string("RegExp('[\0]').test('\0')"),
+ nxt_string("true") },
};
More information about the nginx-devel
mailing list