CVE-2019-11935 (published 2019-12-04T17:16Z)

Insufficient boundary checks when processing a string in mb_ereg_replace allows access to out-of-bounds memory. This issue affects HHVM versions prior to 3.30.12, all versions between 4.0.0 and 4.8.5, all versions between 4.9.0 and 4.23.1, as well as 4.24.0, 4.25.0, 4.26.0, 4.27.0, 4.28.0, and 4.28.1.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-120
cwe_name: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
extended_description: A buffer overflow condition exists when a product attempts to put more data in a buffer than it can hold, or when it attempts to put data in a memory area outside of the boundaries of a buffer. The simplest type of error, and the most common cause of buffer overflows, is the "classic" case in which the product copies the buffer without restricting how much is copied. Other variants exist, but the existence of a classic overflow strongly suggests that the programmer is not considering even the most basic of security protections.
         

Fix information:
repo_url: https://github.com/facebook/hhvm
commit_details: repo_url: https://github.com/facebook/hhvm
author: Shaunak Kishore
author_date: 2019-10-28 20:20:37-07:00
msg: Fix buffer overflow in mb_ereg_replace

Summary:
This diff has already been landed to release and to open-source branches. We're now landing it on master.

CVE-2019-11935

Reviewed By: jjergus

Differential Revision: D18177934

fbshipit-source-id: d108a59e38c67f5f5e835febd7255307605ba62c
repository: repo_url: https://github.com/facebook/hhvm
repo_name: facebook/hhvm
description: A virtual machine for executing programs written in Hack.
repo_language: Hack
owner: facebook
file_changes: filename: ext_mbstring.cpp
change_type: ModificationType.MODIFY
diff: @@ -3609,8 +3609,9 @@ static Variant _php_mb_regex_ereg_replace_exec(const Variant& pattern,
       while (i < replacement.size()) {
         int fwd = (int)php_mb_mbchar_bytes_ex(p, enc);
         n = -1;
-        if ((replacement.size() - i) >= 2 && fwd == 1 &&
-          p[0] == '\\' && p[1] >= '0' && p[1] <= '9') {
+        auto const remaining = replacement.size() - i;
+        if (remaining >= 2 && fwd == 1 &&
+            p[0] == '\\' && p[1] >= '0' && p[1] <= '9') {
           n = p[1] - '0';
         }
         if (n >= 0 && n < regs->num_regs) {
@@ -3621,10 +3622,14 @@ static Variant _php_mb_regex_ereg_replace_exec(const Variant& pattern,
           }
           p += 2;
           i += 2;
-        } else {
+        } else if (remaining >= fwd) {
           out_buf.append(p, fwd);
           p += fwd;
           i += fwd;
+        } else {
+          raise_warning("Replacement ends with unterminated %s: 0x%hhx",
+                        enc->name, *p);
+          break;
         }
       }
       n = regs->end[0];

programming_language: C++
filename: mb_ereg_replace_invalid_replacement.php
change_type: ModificationType.ADD
diff: @@ -0,0 +1,7 @@
+<?hh
+
+<<__EntryPoint>>
+function main(): void {
+  var_dump(mb_ereg_replace("", "\xf1", "", ""));
+  throw new Error("done");
+}

programming_language: JavaScript
filename: mb_ereg_replace_invalid_replacement.php.expectf
change_type: ModificationType.ADD
diff: @@ -0,0 +1,7 @@
+Warning: Replacement ends with unterminated UTF-8: 0xf1 in %s/mb_ereg_replace_invalid_replacement.php on line 5
+string(0) ""
+
+Fatal error: Uncaught Error: done in %s/mb_ereg_replace_invalid_replacement.php:6
+Stack trace:
+#0 (): main()
+#1 {main}

programming_language: Markdown