CVE-2016-6870 (published 2017-02-17T17:59Z)

Out-of-bounds write in the (1) mb_detect_encoding, (2) mb_send_mail, and (3) mb_detect_order functions in Facebook HHVM before 3.15.0 allows attackers to have unspecified impact via unknown vectors.

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.0/AV:N/AC:L/PR:N/UI:N/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/facebook/hhvm
commit_details: repo_url: https://github.com/facebook/hhvm
author: Bill Nell
author_date: 2016-07-01 09:55:16-07:00
msg: Use req::strndup in php_mb_parse_encoding_list to prevent oob memory write.

Summary:
Fix out of bounds write access in mb_detect_encoding.  Using strndup in
php_mb_parse_encoding_list will cause strings with embedded nulls to be
unexpectedly shortened.  The expected length of the string is tracked in
value_length but since strndup may copy fewer characters when there are
mbedded null this can lead to oob writes into tmpstr.

I've found a couple other places in this file that use strndup and replaced
them with req::strndup as well.  The use of strndup in mb_send_mail also seemed
to be a leak.

This replaces uses of strndup with req::strndup which can handle embedded
nulls properly.

It looks like I also accidentally fixed t11337047 at the same time.  Adding it to the list of tasks.

Reviewed By: paulbiss

Differential Revision: D3360065

fbshipit-source-id: 99776cf9105e3789883380bf30240009eec52cec
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: @@ -554,11 +554,11 @@ static int php_mb_parse_encoding_list(const char *value, int value_length,
 
     /* copy the value string for work */
     if (value[0]=='"' && value[value_length-1]=='"' && value_length>2) {
-      tmpstr = (char *)strndup(value+1, value_length-2);
+      tmpstr = req::strndup(value + 1, value_length - 2);
       value_length -= 2;
+    } else {
+      tmpstr = req::strndup(value, value_length);
     }
-    else
-      tmpstr = (char *)strndup(value, value_length);
     if (tmpstr == nullptr) {
       return 0;
     }
@@ -640,7 +640,7 @@ static int php_mb_parse_encoding_list(const char *value, int value_length,
       }
       ret = 0;
     }
-    free(tmpstr);
+    req::free(tmpstr);
   }
 
   return ret;
@@ -2254,11 +2254,11 @@ bool HHVM_FUNCTION(mb_parse_str,
   info.num_from_encodings     = MBSTRG(http_input_list_size);
   info.from_language          = MBSTRG(current_language);
 
-  char *encstr = strndup(encoded_string.data(), encoded_string.size());
+  char *encstr = req::strndup(encoded_string.data(), encoded_string.size());
   Array resultArr = Array::Create();
   mbfl_encoding *detected =
     _php_mb_encoding_handler_ex(&info, resultArr, encstr);
-  free(encstr);
+  req::free(encstr);
   result.assignIfRef(resultArr);
 
   MBSTRG(http_input_identify) = detected;
@@ -4251,7 +4251,7 @@ bool HHVM_FUNCTION(mb_send_mail,
   if (!to.empty()) {
     int to_len = to.size();
     if (to_len > 0) {
-      to_r = strndup(to.data(), to_len);
+      to_r = req::strndup(to.data(), to_len);
       for (; to_len; to_len--) {
         if (!isspace((unsigned char)to_r[to_len - 1])) {
           break;
@@ -4398,6 +4398,9 @@ bool HHVM_FUNCTION(mb_send_mail,
                                encoded_message.data(),
                                all_headers, cmd.data()));
   mbfl_memory_device_clear(&device);
+  if (to_r != to.data()) {
+    req::free(to_r);
+  }
   return ret;
 }
 

programming_language: C
filename: mbstring-oob.php
change_type: ModificationType.ADD
diff: @@ -0,0 +1,6 @@
+<?hh // strict
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+$var0 = null;
+$var3 = "\x00";
+$var3 = mb_detect_encoding($var0,$var3);

programming_language: PHP