CVE-2022-25044 (published 2022-03-05T02:15Z)

Espruino 2v11.251 was discovered to contain a stack buffer overflow via src/jsvar.c in jsvNewFromString.

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/espruino/Espruino
commit_details: repo_url: https://github.com/espruino/Espruino
author: Gordon Williams
author_date: 2022-02-08 14:59:00+00:00
msg: Fix potential corruption issue caused by `delete [].__proto__` (fix #2142)
repository: repo_url: https://github.com/espruino/Espruino
repo_name: espruino/Espruino
description: The Espruino JavaScript interpreter - Official Repo
repo_language: C
owner: espruino
file_changes: filename: ChangeLog
change_type: ModificationType.MODIFY
diff: @@ -9,6 +9,7 @@
             Much-improved whitespace lexing code using single jumptable - 3% speed increase
             Allow `process.memory(false)` to get memory info but skip GC
             Graphics: fix height calculation bug in fillRect/clearRect when given an object with w/h as an argument
+            Fix potential corruption issue caused by `delete [].__proto__` (fix #2142)
 
      2v12 : nRF52840: Flow control XOFF is now sent at only 3/8th full - delays in BLE mean we can sometimes fill our 1k input buffer otherwise
             __FILE__ is now set correctly for apps (fixes 2v11 regression)

programming_language: Markdown
filename: jsparse.c
change_type: ModificationType.MODIFY
diff: @@ -952,7 +952,12 @@ static NO_INLINE JsVar *jspGetNamedFieldInParents(JsVar *object, const char* nam
     } else if (strcmp(name, JSPARSE_INHERITS_VAR)==0) {
       const char *objName = jswGetBasicObjectName(object);
       if (objName) {
-        child = jspNewPrototype(objName);
+        JsVar *p = jsvSkipNameAndUnLock(jspNewPrototype(objName));
+        // jspNewPrototype returns a 'prototype' name that's already a child of eg. an array
+        // Create a new 'name' called __proto__ that links to it
+        JsVar *i = jsvNewFromString(JSPARSE_INHERITS_VAR);
+        if (p) child = jsvCreateNewChild(object, i, p);
+        jsvUnLock(i);
       }
     }
   }
@@ -1372,8 +1377,13 @@ NO_INLINE JsVar *jspeFactorDelete() {
       if (!parent && jsvIsChild(execInfo.root, a))
         parent = jsvLockAgain(execInfo.root);
 
-      if (jsvHasChildren(parent)) {
+#ifdef DEBUG
+      if (jsvHasChildren(parent)) assert(jsvIsChild(parent, a));
+#endif
+      if (jsvHasChildren(parent) && jsvIsChild(parent, a)) {
         // else remove properly.
+        /* we use jsvIsChild here just in case. delete probably isn't called
+        that often so it pays to be safe */
         if (jsvIsArray(parent)) {
           // For arrays, we must make sure we don't change the length
           JsVarInt l = jsvGetArrayLength(parent);
@@ -2848,7 +2858,7 @@ JsVar *jspNewBuiltin(const char *instanceOf) {
   return objFunc;
 }
 
-/// Create a new Class of the given instance and return its prototype
+/// Create a new Class of the given instance and return its prototype (as a name 'prototype')
 NO_INLINE JsVar *jspNewPrototype(const char *instanceOf) {
   JsVar *objFuncName = jsvFindChildFromString(execInfo.root, instanceOf, true);
   if (!objFuncName) // out of memory

programming_language: C++
filename: jsparse.h
change_type: ModificationType.MODIFY
diff: @@ -37,7 +37,7 @@ bool jspCheckStackPosition();
 /// Create a new built-in object that jswrapper can use to check for built-in functions
 JsVar *jspNewBuiltin(const char *name);
 
-/// Create a new Class of the given instance and return its prototype
+/// Create a new Class of the given instance and return its prototype (as a name 'prototype')
 NO_INLINE JsVar *jspNewPrototype(const char *instanceOf);
 
 /** Create a new object of the given instance and add it to root with name 'name'.

programming_language: C++
filename: jsvar.c
change_type: ModificationType.MODIFY
diff: @@ -2555,6 +2555,7 @@ void jsvAddName(JsVar *parent, JsVar *namedChild) {
     }
 
     if (insertAfter) {
+      assert(jsvIsName(insertAfter));
       if (jsvGetNextSibling(insertAfter)) {
         // great, we're in the middle...
         JsVar *insertBefore = jsvLock(jsvGetNextSibling(insertAfter));
@@ -2761,6 +2762,9 @@ JsVar *jsvFindChildFromVar(JsVar *parent, JsVar *childName, bool addIfNotFound)
 void jsvRemoveChild(JsVar *parent, JsVar *child) {
   assert(jsvHasChildren(parent));
   assert(jsvIsName(child));
+#ifdef DEBUG
+  assert(jsvIsChild(parent, child));
+#endif
   JsVarRef childref = jsvGetRef(child);
   bool wasChild = false;
   // unlink from parent

programming_language: C++