CVE-2018-11598 (published 2018-05-31T16:29Z)

Espruino before 1.99 allows attackers to cause a denial of service (application crash) and a potential Information Disclosure with user crafted input files via a Buffer Overflow or Out-of-bounds Read during syntax parsing of certain for loops in jsparse.c.

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

Weakness information:
cwe_id: CWE-125
cwe_name: Out-of-bounds Read
description: The product reads 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: 2018-05-23 17:27:51+01:00
msg: Fix bug if using an undefined member of an object for for..in (fix #1437)
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: @@ -3,6 +3,7 @@
             Fix parsing of try..catch when not executing (fix #1439)
             Add extra ReferenceError checks, even if variable is not used
             Allow Ctrl-C out of while...continue loop (fix #1441)
+            Fix bug if using an undefined member of an object for for..in (fix #1437)
 
      1v99 : Increase jslMatch error buffer size to handle "UNFINISHED TEMPLATE LITERAL" string (#1426)
             nRF5x: Make FlashWrite cope with flash writes > 4k

programming_language: Markdown
filename: jsparse.c
change_type: ModificationType.MODIFY
diff: @@ -122,6 +122,16 @@ void jspReplaceWith(JsVar *dst, JsVar *src) {
   }
 }
 
+void jspReplaceWithOrAddToRoot(JsVar *dst, JsVar *src) {
+  /* If we're assigning to this and we don't have a parent,
+   * add it to the symbol table root */
+  if (!jsvGetRefs(dst) && jsvIsName(dst)) {
+    if (!jsvIsArrayBufferName(dst) && !jsvIsNewChild(dst))
+      jsvAddName(execInfo.root, dst);
+  }
+  jspReplaceWith(dst, src);
+}
+
 bool jspeiAddScope(JsVar *scope) {
   if (execInfo.scopeCount >= JSPARSE_MAX_SCOPES) {
     jsExceptionHere(JSET_ERROR, "Maximum number of scopes exceeded");
@@ -1971,13 +1981,7 @@ NO_INLINE JsVar *__jspeAssignmentExpression(JsVar *lhs) {
 
     if (JSP_SHOULD_EXECUTE && lhs) {
       if (op=='=') {
-        /* If we're assigning to this and we don't have a parent,
-         * add it to the symbol table root */
-        if (!jsvGetRefs(lhs) && jsvIsName(lhs)) {
-          if (!jsvIsArrayBufferName(lhs) && !jsvIsNewChild(lhs))
-            jsvAddName(execInfo.root, lhs);
-        }
-        jspReplaceWith(lhs, rhs);
+        jspReplaceWithOrAddToRoot(lhs, rhs);
       } else {
         if (op==LEX_PLUSEQUAL) op='+';
         else if (op==LEX_MINUSEQUAL) op='-';
@@ -2330,12 +2334,6 @@ NO_INLINE JsVar *jspeStatementFor() {
       jsExceptionHere(JSET_ERROR, "FOR a IN b - 'a' must be a variable name, not %t", forStatement);
       return 0;
     }
-    bool addedIteratorToScope = false;
-    if (JSP_SHOULD_EXECUTE && !jsvGetRefs(forStatement)) {
-      // if the variable did not exist, add it to the scope
-      addedIteratorToScope = true;
-      jsvAddName(execInfo.root, forStatement);
-    }
     JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_R_IN, jsvUnLock(forStatement), 0);
     JsVar *array = jsvSkipNameAndUnLock(jspeExpression());
     JSP_MATCH_WITH_CLEANUP_AND_RETURN(')', jsvUnLock2(forStatement, array), 0);
@@ -2371,7 +2369,7 @@ NO_INLINE JsVar *jspeStatementFor() {
                 loopIndexVar;
             if (indexValue) { // could be out of memory
               assert(!jsvIsName(indexValue) && jsvGetRefs(indexValue)==0);
-              jsvSetValueOfName(forStatement, indexValue);
+              jspReplaceWithOrAddToRoot(forStatement, indexValue);
               if (indexValue!=loopIndexVar) jsvUnLock(indexValue);
 
               jsvIteratorNext(&it);
@@ -2410,9 +2408,6 @@ NO_INLINE JsVar *jspeStatementFor() {
     jslCharPosFree(&forBodyStart);
     jslCharPosFree(&forBodyEnd);
 
-    if (addedIteratorToScope) {
-      jsvRemoveChild(execInfo.root, forStatement);
-    }
     jsvUnLock2(forStatement, array);
   } else { // ----------------------------------------------- NORMAL FOR LOOP
 #ifdef JSPARSE_MAX_LOOP_ITERATIONS

programming_language: C++