CVE-2022-28049: NULL Pointer Dereference (CWE-476)
value: NGINX NJS 0.7.2 was discovered to contain a NULL pointer dereference via the component njs_vmcode_array at /src/njs_vmcode.c.
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 5.5
Published: 2022-04-15T14:15Z
Repository: https://github.com/nginx/njs
Language: C
Files changed: src/njs_vmcode.c, src/test/njs_unit_test.c
Commit date: 2022-02-21 16:53:16 +0000
Commit message: Fixed allocation of large array literals.

Previously, allocation of large array literals may result in
null-pointer dereference. The reason is that njs_array_alloc() may
return a slow array when size is large enough, but the instruction
code assumes that array is always flat.

The fix is to check fast_array flag before accessing array->start.

This closes #473 issue on Github.

Diff: diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c
index ef0beb5e0..ec478659c 100644
--- a/src/njs_vmcode.c
+++ b/src/njs_vmcode.c
@@ -1053,18 +1053,20 @@ njs_vmcode_array(njs_vm_t *vm, u_char *pc)
 
     if (njs_fast_path(array != NULL)) {
 
         if (code->ctor) {
             /* Array of the form [,,,], [1,,]. */
-            value = array->start;
-            length = array->length;
-
-            do {
-                njs_set_invalid(value);
-                value++;
-                length--;
-            } while (length != 0);
+            if (array->object.fast_array) {
+                value = array->start;
+                length = array->length;
+
+                do {
+                    njs_set_invalid(value);
+                    value++;
+                    length--;
+                } while (length != 0);
+            }
 
         } else {
             /* Array of the form [], [,,1], [1,2,3]. */
             array->length = 0;
         }
diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
index dc18a13b1..ef5b3ca45 100644
--- a/src/test/njs_unit_test.c
+++ b/src/test/njs_unit_test.c
@@ -13152,10 +13152,14 @@ static njs_unit_test_t  njs_test[] =
       njs_str("string") },
 
     { njs_str("(new Function('return 5' + '** 1'.repeat(2**13)))()"),
       njs_str("5") },
 
+    { njs_str("var a = (new Function('return [' + ','.repeat(2**16) + ']'))();"
+			  "njs.dump(a)"),
+      njs_str("[<65536 empty items>]") },
+
     { njs_str("(new Function('var a = 7; return a' + '= a'.repeat(2**13)))()"),
       njs_str("7") },
 
     { njs_str("var a = (new Function('return [' + '1,'.repeat(2**13) + ']'))();"
               "a.push(5); [a[2**13 - 1], a[2**13]]"),

Vulnerable code:             value = array->start;
            length = array->length;

            do {
                njs_set_invalid(value);
                value++;
                length--;
            } while (length != 0);
Fixed code:             if (array->object.fast_array) {
                value = array->start;
                length = array->length;

                do {
                    njs_set_invalid(value);
                    value++;
                    length--;
                } while (length != 0);
            }
    { njs_str("var a = (new Function('return [' + ','.repeat(2**16) + ']'))();"
			  "njs.dump(a)"),
      njs_str("[<65536 empty items>]") },