summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2020-06-29 17:38:14 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2020-06-29 19:05:02 +0200
commita385cfa7ad7fe3621bb6095ff88bc8d74b358df0 (patch)
tree75babdefc6eb3793530945a6a4aa43c6c36666ba
parent816b4c1235d70b1b83d26c415f044fc04a48875f (diff)
downloadphp-git-a385cfa7ad7fe3621bb6095ff88bc8d74b358df0.tar.gz
Fix #63208: BSTR to PHP string conversion not binary safe
A `BSTR` is similar to a `zend_string`; it stores the length of the string just before the actual string, and thus the string may contain NUL bytes. However, `php_com_olestring_to_string()` is supposed to deal with arbitrary `OLECHAR*`s which may not be `BSTR`s, so we introduce `php_com_bstr_to_string()` and use it for the only case where we actually have to deal with `BSTR`s which may contain NUL bytes. Contrary to `php_com_olestring_to_string()` we return a `zend_string`, so we can save the re-allocation when converting to a `zval`. We also cater to `php_com_string_to_olestring()` not being binary safe, with basically the same fix we did for `php_com_olestring_to_string()`.
-rw-r--r--NEWS3
-rw-r--r--ext/com_dotnet/com_olechar.c55
-rw-r--r--ext/com_dotnet/com_variant.c17
-rw-r--r--ext/com_dotnet/php_com_dotnet_internal.h2
-rw-r--r--ext/com_dotnet/tests/bug63208.phpt17
5 files changed, 80 insertions, 14 deletions
diff --git a/NEWS b/NEWS
index 5ba6019106..2c8da20466 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@ PHP NEWS
. Fixed bug #79030 (Upgrade apache2handler's php_apache_sapi_get_request_time
to return usec). (Herbert256)
+- COM:
+ . Fixed bug #63208 (BSTR to PHP string conversion not binary safe). (cmb)
+
- Curl:
. Fixed bug #79741 (curl_setopt CURLOPT_POSTFIELDS asserts on object with
declared properties). (Nikita)
diff --git a/ext/com_dotnet/com_olechar.c b/ext/com_dotnet/com_olechar.c
index b9a332e4f5..1cd1017a02 100644
--- a/ext/com_dotnet/com_olechar.c
+++ b/ext/com_dotnet/com_olechar.c
@@ -103,3 +103,58 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring, size_t
return string;
}
+
+BSTR php_com_string_to_bstr(zend_string *string, int codepage)
+{
+ BSTR bstr = NULL;
+ DWORD flags = codepage == CP_UTF8 ? 0 : MB_PRECOMPOSED | MB_ERR_INVALID_CHARS;
+ size_t mb_len = ZSTR_LEN(string);
+ int wc_len;
+
+ if ((wc_len = MultiByteToWideChar(codepage, flags, ZSTR_VAL(string), (int)mb_len + 1, NULL, 0)) <= 0) {
+ goto fail;
+ }
+ if ((bstr = SysAllocStringLen(NULL, (UINT)(wc_len - 1))) == NULL) {
+ goto fail;
+ }
+ if ((wc_len = MultiByteToWideChar(codepage, flags, ZSTR_VAL(string), (int)mb_len + 1, bstr, wc_len)) <= 0) {
+ goto fail;
+ }
+ return bstr;
+
+fail:
+ char *msg = php_win32_error_to_msg(GetLastError());
+ php_error_docref(NULL, E_WARNING,
+ "Could not convert string to unicode: `%s'", msg);
+ LocalFree(msg);
+ SysFreeString(bstr);
+ return SysAllocString(L"");
+}
+
+zend_string *php_com_bstr_to_string(BSTR bstr, int codepage)
+{
+ zend_string *string = NULL;
+ UINT wc_len = SysStringLen(bstr);
+ int mb_len;
+
+ mb_len = WideCharToMultiByte(codepage, 0, bstr, wc_len + 1, NULL, 0, NULL, NULL);
+ if (mb_len > 0) {
+ string = zend_string_alloc(mb_len - 1, 0);
+ mb_len = WideCharToMultiByte(codepage, 0, bstr, wc_len + 1, ZSTR_VAL(string), mb_len, NULL, NULL);
+ }
+
+ if (mb_len <= 0) {
+ char *msg = php_win32_error_to_msg(GetLastError());
+
+ php_error_docref(NULL, E_WARNING,
+ "Could not convert string from unicode: `%s'", msg);
+ LocalFree(msg);
+
+ if (string != NULL) {
+ zend_string_release(string);
+ }
+ string = ZSTR_EMPTY_ALLOC();
+ }
+
+ return string;
+}
diff --git a/ext/com_dotnet/com_variant.c b/ext/com_dotnet/com_variant.c
index f4f7d5a9dd..901b0a866a 100644
--- a/ext/com_dotnet/com_variant.c
+++ b/ext/com_dotnet/com_variant.c
@@ -96,7 +96,6 @@ bogus:
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
{
- OLECHAR *olestring;
php_com_dotnet_object *obj;
zend_uchar ztype = IS_NULL;
@@ -164,13 +163,7 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
case IS_STRING:
V_VT(v) = VT_BSTR;
- olestring = php_com_string_to_olestring(Z_STRVAL_P(z), Z_STRLEN_P(z), codepage);
- if (CP_UTF8 == codepage) {
- V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(wcslen(olestring) * sizeof(OLECHAR)));
- } else {
- V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(Z_STRLEN_P(z) * sizeof(OLECHAR)));
- }
- efree(olestring);
+ V_BSTR(v) = php_com_string_to_bstr(Z_STR_P(z), codepage);
break;
case IS_RESOURCE:
@@ -236,12 +229,8 @@ PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepa
case VT_BSTR:
olestring = V_BSTR(v);
if (olestring) {
- size_t len;
- char *str = php_com_olestring_to_string(olestring,
- &len, codepage);
- ZVAL_STRINGL(z, str, len);
- // TODO: avoid reallocation???
- efree(str);
+ zend_string *str = php_com_bstr_to_string(olestring, codepage);
+ ZVAL_STR(z, str);
olestring = NULL;
}
break;
diff --git a/ext/com_dotnet/php_com_dotnet_internal.h b/ext/com_dotnet/php_com_dotnet_internal.h
index a2fe813683..663c0694fe 100644
--- a/ext/com_dotnet/php_com_dotnet_internal.h
+++ b/ext/com_dotnet/php_com_dotnet_internal.h
@@ -89,6 +89,8 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring,
size_t *string_len, int codepage);
PHP_COM_DOTNET_API OLECHAR *php_com_string_to_olestring(char *string,
size_t string_len, int codepage);
+BSTR php_com_string_to_bstr(zend_string *string, int codepage);
+zend_string *php_com_bstr_to_string(BSTR bstr, int codepage);
/* com_com.c */
diff --git a/ext/com_dotnet/tests/bug63208.phpt b/ext/com_dotnet/tests/bug63208.phpt
new file mode 100644
index 0000000000..ae62dbba98
--- /dev/null
+++ b/ext/com_dotnet/tests/bug63208.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #63208 (BSTR to PHP string conversion not binary safe)
+--SKIPIF--
+<?php
+if (!extension_loaded('com_dotnet')) die('skip com_dotnet extension not available');
+?>
+--FILE--
+<?php
+$string = "\u{0905}b\0cd";
+$variant = new VARIANT($string, VT_ARRAY | VT_UI1, CP_UTF8); // Array of bytes
+$converted = (string) $variant;
+var_dump(bin2hex($string));
+var_dump(bin2hex($converted));
+?>
+--EXPECT--
+string(14) "e0a48562006364"
+string(14) "e0a48562006364"