Skip to content

Instantly share code, notes, and snippets.

@lexborisov
Created April 19, 2019 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lexborisov/6946f9fb8ca76a79f17d9b3a558b8a08 to your computer and use it in GitHub Desktop.
Save lexborisov/6946f9fb8ca76a79f17d9b3a558b8a08 to your computer and use it in GitHub Desktop.
# HG changeset patch
# User Alexander Borisov <alexander.borisov@nginx.com>
# Date 1555684207 -10800
# Fri Apr 19 17:30:07 2019 +0300
# Node ID 07b46eb0f25a9ece2f6ad79b834377b72c8f7baf
# Parent a6c82ddff460a0d19dd24f6189ce8252954ec41b
Added check unsigned int overflow for njs_array_alloc function.
diff -r a6c82ddff460 -r 07b46eb0f25a njs/njs_array.c
--- a/njs/njs_array.c Fri Apr 19 20:03:49 2019 +0800
+++ b/njs/njs_array.c Fri Apr 19 17:30:07 2019 +0300
@@ -125,22 +125,29 @@ static njs_ret_t njs_array_prototype_sor
nxt_noinline njs_array_t *
-njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare)
+njs_array_alloc(njs_vm_t *vm, uint64_t length, uint64_t spare)
{
uint64_t size;
njs_array_t *array;
+ if (nxt_slow_path(spare > (UINT64_MAX - length))) {
+ goto overflow;
+ }
+
+ size = length + spare;
+
+ if (nxt_slow_path(size > (UINT64_MAX / sizeof(njs_value_t)))) {
+ goto overflow;
+
+ } else if (nxt_slow_path((size * sizeof(njs_value_t)) >= UINT32_MAX)) {
+ goto overflow;
+ }
+
array = nxt_mp_alloc(vm->mem_pool, sizeof(njs_array_t));
if (nxt_slow_path(array == NULL)) {
goto memory_error;
}
- size = (uint64_t) length + spare;
-
- if (nxt_slow_path((size * sizeof(njs_value_t)) >= UINT32_MAX)) {
- goto memory_error;
- }
-
array->data = nxt_mp_align(vm->mem_pool, sizeof(njs_value_t),
size * sizeof(njs_value_t));
if (nxt_slow_path(array->data == NULL)) {
@@ -164,6 +171,12 @@ memory_error:
njs_memory_error(vm);
return NULL;
+
+overflow:
+
+ njs_range_error(vm, "Invalid array length");
+
+ return NULL;
}
@@ -266,7 +279,7 @@ njs_array_constructor(njs_vm_t *vm, njs_
if (size == 1 && njs_is_number(&args[0])) {
num = args[0].data.u.number;
- size = (uint32_t) num;
+ size = (uint32_t) (int64_t) num;
if ((double) size != num) {
njs_range_error(vm, "Invalid array length");
diff -r a6c82ddff460 -r 07b46eb0f25a njs/njs_array.h
--- a/njs/njs_array.h Fri Apr 19 20:03:49 2019 +0800
+++ b/njs/njs_array.h Fri Apr 19 17:30:07 2019 +0300
@@ -15,7 +15,7 @@
#define NJS_ARRAY_SPARE 8
-njs_array_t *njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare);
+njs_array_t *njs_array_alloc(njs_vm_t *vm, uint64_t length, uint64_t spare);
njs_ret_t njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value);
njs_ret_t njs_array_string_add(njs_vm_t *vm, njs_array_t *array,
const u_char *start, size_t size, size_t length);
diff -r a6c82ddff460 -r 07b46eb0f25a njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Fri Apr 19 20:03:49 2019 +0800
+++ b/njs/test/njs_unit_test.c Fri Apr 19 17:30:07 2019 +0300
@@ -7948,7 +7948,13 @@ static njs_unit_test_t njs_test[] =
nxt_string("RangeError: Invalid array length") },
{ nxt_string("var a = Array(1111111111)"),
- nxt_string("MemoryError") },
+ nxt_string("RangeError: Invalid array length") },
+
+ { nxt_string("var x = Array(2**64)"),
+ nxt_string("RangeError: Invalid array length") },
+
+ { nxt_string("var x = Array(2**1000)"),
+ nxt_string("RangeError: Invalid array length") },
{ nxt_string("var a = new Array(3); a"),
nxt_string(",,") },
# HG changeset patch
# User Alexander Borisov <alexander.borisov@nginx.com>
# Date 1555683869 -10800
# Fri Apr 19 17:24:29 2019 +0300
# Node ID c1a68ad25fdd4e92f316619465b824bd1f751654
# Parent 07b46eb0f25a9ece2f6ad79b834377b72c8f7baf
Fixed overflow in Array.prototype.concat().
This closes #131 issue on GitHub.
diff -r 07b46eb0f25a -r c1a68ad25fdd njs/njs_array.c
--- a/njs/njs_array.c Fri Apr 19 17:30:07 2019 +0300
+++ b/njs/njs_array.c Fri Apr 19 17:24:29 2019 +0300
@@ -1128,7 +1128,8 @@ static njs_ret_t
njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
- size_t length;
+ uint64_t length;
+ uint32_t arr_len;
nxt_uint_t i;
njs_value_t *value;
njs_array_t *array;
@@ -1137,9 +1138,19 @@ njs_array_prototype_concat(njs_vm_t *vm,
for (i = 0; i < nargs; i++) {
if (njs_is_array(&args[i])) {
- length += args[i].data.u.array->length;
+ arr_len = args[i].data.u.array->length;
+
+ if (nxt_slow_path(arr_len > (UINT64_MAX - length))) {
+ goto overflow;
+ }
+
+ length += arr_len;
} else {
+ if (nxt_slow_path(1 > (UINT64_MAX - length))) {
+ goto overflow;
+ }
+
length++;
}
}
@@ -1160,6 +1171,12 @@ njs_array_prototype_concat(njs_vm_t *vm,
}
return NXT_OK;
+
+overflow:
+
+ njs_range_error(vm, "Invalid array length");
+
+ return NXT_ERROR;
}
diff -r 07b46eb0f25a -r c1a68ad25fdd njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Fri Apr 19 17:30:07 2019 +0300
+++ b/njs/test/njs_unit_test.c Fri Apr 19 17:24:29 2019 +0300
@@ -7956,6 +7956,20 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var x = Array(2**1000)"),
nxt_string("RangeError: Invalid array length") },
+ /*
+ * The exception in the test may differ depending on the amount of memory
+ * in the operating system.
+ * Out of memory: InternalError
+ * Enough memory: RangeError
+ */
+ { nxt_string("var r; try {"
+ " var x = Array(2**27), y = Array(2**5).fill(x);"
+ " Array.prototype.concat.apply(y[0], y.slice(1));"
+ "} catch (e) {"
+ " r = e.name == 'InternalError' || e.name == 'RangeError'"
+ "} r"),
+ nxt_string("true") },
+
{ nxt_string("var a = new Array(3); a"),
nxt_string(",,") },
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment