Merge branch 'PHP-8.3'

This commit is contained in:
Ben Ramsey 2024-04-09 23:55:11 -05:00
commit 7ca4300db8
No known key found for this signature in database
GPG Key ID: F9C39DC0B9698544
11 changed files with 330 additions and 46 deletions

2
NEWS
View File

@ -195,7 +195,7 @@ PHP NEWS
. Added multicast group support for ipv4 on FreeBSD. (jonathan@tangential.ca)
. Added the TCP_SYNCNT constant for Linux to set number of attempts to send
SYN packets from the client. (David Carlier)
. Added the SO_EXCLBIND constant for exclusive socket binding on illumos/solaris.
. Added the SO_EXCLBIND constant for exclusive socket binding on illumos/solaris.
(David Carlier)
- SNMP:

View File

@ -6119,6 +6119,9 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
unsigned char *in = (unsigned char*)ZSTR_VAL(input);
size_t in_len = ZSTR_LEN(input);
ZEND_ASSERT(outcode->mime_name != NULL);
ZEND_ASSERT(outcode->mime_name[0] != '\0');
if (!in_len) {
return zend_empty_string;
}
@ -6141,7 +6144,8 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
unsigned int state = 0;
/* wchar_buf should be big enough that when it is full, we definitely have enough
* wchars to fill an entire line of output */
uint32_t wchar_buf[80];
const size_t wchar_buf_len = 90;
uint32_t wchar_buf[wchar_buf_len];
uint32_t *p, *e;
/* What part of wchar_buf is filled with still-unprocessed data which should not
* be overwritten? */
@ -6152,7 +6156,7 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
* spaces), just pass it through unchanged */
bool checking_leading_spaces = true;
while (in_len) {
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, 80, &state);
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, wchar_buf_len, &state);
p = wchar_buf;
e = wchar_buf + out_len;
@ -6186,9 +6190,9 @@ no_passthrough: ;
* do so all the way to the end of the string */
while (in_len) {
/* Decode part of the input string, refill wchar_buf */
ZEND_ASSERT(offset < 80);
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state);
ZEND_ASSERT(out_len <= 80 - offset);
ZEND_ASSERT(offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len);
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, wchar_buf_len - offset, &state);
ZEND_ASSERT(out_len <= wchar_buf_len - offset);
p = wchar_buf;
e = wchar_buf + offset + out_len;
/* ASCII output is broken into space-delimited 'words'
@ -6209,6 +6213,7 @@ no_passthrough: ;
* If we are already too far along on a line to include Base64/QPrint encoded data
* on the same line (without overrunning max line length), then add a line feed
* right now */
feed_and_mime_encode:
if (mb_convert_buf_len(&buf) - line_start + indent + strlen(outcode->mime_name) > 55) {
MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + linefeed_len + 1);
buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len);
@ -6246,7 +6251,13 @@ no_passthrough: ;
if (in_len) {
/* Copy chars which are part of an incomplete 'word' to the beginning
* of wchar_buf and reprocess them on the next iteration */
* of wchar_buf and reprocess them on the next iteration.
* But first make sure that the incomplete 'word' isn't so big that
* there will be no space to add any more decoded wchars in the buffer
* (which could lead to an infinite loop) */
if ((word_start - wchar_buf) < MBSTRING_MIN_WCHAR_BUFSIZE) {
goto feed_and_mime_encode;
}
offset = e - word_start;
if (offset) {
memmove(wchar_buf, word_start, offset * sizeof(uint32_t));
@ -6288,17 +6299,17 @@ mime_encoding_needed: ;
/* Do we need to refill wchar_buf to make sure we don't run out of wchars
* in the middle of a line? */
if (p == wchar_buf) {
offset = e - p;
if (wchar_buf_len - offset < MBSTRING_MIN_WCHAR_BUFSIZE) {
goto start_new_line;
}
offset = e - p;
memmove(wchar_buf, p, offset * sizeof(uint32_t));
while(true) {
refill_wchar_buf: ;
ZEND_ASSERT(offset < 80);
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state);
ZEND_ASSERT(out_len <= 80 - offset);
ZEND_ASSERT(offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len);
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, wchar_buf_len - offset, &state);
ZEND_ASSERT(out_len <= wchar_buf_len - offset);
p = wchar_buf;
e = wchar_buf + offset + out_len;
@ -6373,22 +6384,18 @@ start_new_line: ;
indent = 0; /* Indent argument must only affect the first line */
if (in_len) {
/* We still have more of input string remaining to decode */
if (in_len || p < e) {
/* We still have more input to process */
buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len);
buf.out = mb_convert_buf_add(buf.out, ' ');
line_start = mb_convert_buf_len(&buf);
/* Copy remaining wchars to beginning of buffer so they will be
* processed on the next iteration of outer 'do' loop */
offset = e - p;
memmove(wchar_buf, p, offset * sizeof(uint32_t));
goto refill_wchar_buf;
} else if (p < e) {
/* Input string is finished, but we still have trailing wchars
* remaining to be processed in wchar_buf */
buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len);
buf.out = mb_convert_buf_add(buf.out, ' ');
line_start = mb_convert_buf_len(&buf);
if (in_len && (wchar_buf_len - offset >= MBSTRING_MIN_WCHAR_BUFSIZE)) {
/* Copy any remaining wchars to beginning of buffer and refill
* the rest of the buffer */
memmove(wchar_buf, p, offset * sizeof(uint32_t));
goto refill_wchar_buf;
}
goto start_new_line;
} else {
/* We are done! */
@ -6426,7 +6433,7 @@ PHP_FUNCTION(mb_encode_mimeheader)
charset = php_mb_get_encoding(charset_name, 2);
if (!charset) {
RETURN_THROWS();
} else if (charset->mime_name == NULL || charset->mime_name[0] == '\0') {
} else if (charset->mime_name == NULL || charset->mime_name[0] == '\0' || charset == &mbfl_encoding_qprint) {
zend_argument_value_error(2, "\"%s\" cannot be used for MIME header encoding", ZSTR_VAL(charset_name));
RETURN_THROWS();
}

View File

@ -2,6 +2,8 @@
Test mb_encode_mimeheader() function : test cases found by fuzzer
--EXTENSIONS--
mbstring
--INI--
error_reporting=E_ALL^E_DEPRECATED
--FILE--
<?php
@ -115,7 +117,25 @@ var_dump(mb_encode_mimeheader("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
// In the general case, matching the old implementation's decision to transfer-encode or not
// perfectly would require allocating potentially unbounded scratch memory (up to the size of
// the input string), but we aim to only use a constant amount of temporarily allocated memory
var_dump(mb_encode_mimeheader("2\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3", "GB18030", "Q", ""));
var_dump(mb_encode_mimeheader("2\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3", "GB18030", "Q", ""));
// Regression test for infinite loop which was unintentionally caused when refactoring
var_dump(mb_encode_mimeheader(",9868949,9868978,9869015,9689100,9869121,9869615,9870690,9867116,98558119861183. ", "utf-8", "B"));
var_dump(mb_encode_mimeheader('xx ' . str_repeat("A", 81) . " ", "utf-8", "B"));
// Regression test for problem where MIME encoding loop would not leave enough space in wchar
// buffer for the next iteration, causing an assertion failure
mb_internal_encoding('MacJapanese');
var_dump(mb_encode_mimeheader("ne\xf6\xff\xff\xffs\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff1\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff1", 'CP50220', 'B', "A", 44));
// Regression test for failing assertion caused by the fact that QPrint deliberately generates no
// wchars for CR (0x0D) bytes
try {
mb_internal_encoding('Quoted-Printable');
var_dump(mb_encode_mimeheader("=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=00=00=00=00=00=00=00=01=00=00=00=00=00=00=00850r=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=00=00=00=0050r=08=0DCP850r850r0r", "Quoted-Printable", "B", "", 184));
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
echo "Done";
?>
@ -156,5 +176,11 @@ string(75) " 111111111111111111111111111111111111111111111111111111111111111111
string(33) "=?HZ-GB-2312?Q?=7E=7Bs=5B=7E=7D?="
string(77) "2 !3"
string(282) "=?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20!=33=20?="
string(296) "2 =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20!=33?="
string(344) "2 =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20!=33?="
string(135) "=?UTF-8?B?LDk4Njg5NDksOTg2ODk3OCw5ODY5MDE1LDk2ODkxMDAsOTg2OTEyMSw5ODY5?=
=?UTF-8?B?NjE1LDk4NzA2OTAsOTg2NzExNiw5ODU1ODExOTg2MTE4My4g?="
string(142) "xx =?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?=
=?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBIA==?="
string(690) "=?ISO-2022-JP?B?bmU/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/cxskQiFEGyhCPw==?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/MRskQiFEGyhCPxskQiFEGyhCPw==?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/MQ==?="
mb_encode_mimeheader(): Argument #2 ($charset) "Quoted-Printable" cannot be used for MIME header encoding
Done

View File

@ -181,6 +181,11 @@ static zend_string* php_password_bcrypt_hash(const zend_string *password, zend_a
zval *zcost;
zend_long cost = PHP_PASSWORD_BCRYPT_COST;
if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) {
zend_value_error("Bcrypt password must not contain null character");
return NULL;
}
if (options && (zcost = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) {
cost = zval_get_long(zcost);
}

View File

@ -536,11 +536,32 @@ static void append_backslashes(smart_str *str, size_t num_bs)
}
}
/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */
static void append_win_escaped_arg(smart_str *str, zend_string *arg)
const char *special_chars = "()!^\"<>&|%";
static bool is_special_character_present(const zend_string *arg)
{
for (size_t i = 0; i < ZSTR_LEN(arg); ++i) {
if (strchr(special_chars, ZSTR_VAL(arg)[i]) != NULL) {
return true;
}
}
return false;
}
/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments and
* https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way */
static void append_win_escaped_arg(smart_str *str, zend_string *arg, bool is_cmd_argument)
{
size_t num_bs = 0;
bool has_special_character = false;
if (is_cmd_argument) {
has_special_character = is_special_character_present(arg);
if (has_special_character) {
/* Escape double quote with ^ if executed by cmd.exe. */
smart_str_appendc(str, '^');
}
}
smart_str_appendc(str, '"');
for (size_t i = 0; i < ZSTR_LEN(arg); ++i) {
char c = ZSTR_VAL(arg)[i];
@ -554,18 +575,71 @@ static void append_win_escaped_arg(smart_str *str, zend_string *arg)
num_bs = num_bs * 2 + 1;
}
append_backslashes(str, num_bs);
if (has_special_character && strchr(special_chars, c) != NULL) {
/* Escape special chars with ^ if executed by cmd.exe. */
smart_str_appendc(str, '^');
}
smart_str_appendc(str, c);
num_bs = 0;
}
append_backslashes(str, num_bs * 2);
if (has_special_character) {
/* Escape double quote with ^ if executed by cmd.exe. */
smart_str_appendc(str, '^');
}
smart_str_appendc(str, '"');
}
static inline int stricmp_end(const char* suffix, const char* str) {
size_t suffix_len = strlen(suffix);
size_t str_len = strlen(str);
if (suffix_len > str_len) {
return -1; /* Suffix is longer than string, cannot match. */
}
/* Compare the end of the string with the suffix, ignoring case. */
return _stricmp(str + (str_len - suffix_len), suffix);
}
static bool is_executed_by_cmd(const char *prog_name)
{
/* If program name is cmd.exe, then return true. */
if (_stricmp("cmd.exe", prog_name) == 0 || _stricmp("cmd", prog_name) == 0
|| stricmp_end("\\cmd.exe", prog_name) == 0 || stricmp_end("\\cmd", prog_name) == 0) {
return true;
}
/* Find the last occurrence of the directory separator (backslash or forward slash). */
char *last_separator = strrchr(prog_name, '\\');
char *last_separator_fwd = strrchr(prog_name, '/');
if (last_separator_fwd && (!last_separator || last_separator < last_separator_fwd)) {
last_separator = last_separator_fwd;
}
/* Find the last dot in the filename after the last directory separator. */
char *extension = NULL;
if (last_separator != NULL) {
extension = strrchr(last_separator, '.');
} else {
extension = strrchr(prog_name, '.');
}
if (extension == NULL || extension == prog_name) {
/* No file extension found, it is not batch file. */
return false;
}
/* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */
return _stricmp(extension, ".bat") == 0 || _stricmp(extension, ".cmd") == 0;
}
static zend_string *create_win_command_from_args(HashTable *args)
{
smart_str str = {0};
zval *arg_zv;
bool is_prog_name = 1;
bool is_prog_name = true;
bool is_cmd_execution = false;
int elem_num = 0;
ZEND_HASH_FOREACH_VAL(args, arg_zv) {
@ -575,11 +649,13 @@ static zend_string *create_win_command_from_args(HashTable *args)
return NULL;
}
if (!is_prog_name) {
if (is_prog_name) {
is_cmd_execution = is_executed_by_cmd(ZSTR_VAL(arg_str));
} else {
smart_str_appendc(&str, ' ');
}
append_win_escaped_arg(&str, arg_str);
append_win_escaped_arg(&str, arg_str, !is_prog_name && is_cmd_execution);
is_prog_name = 0;
zend_string_release(arg_str);

View File

@ -0,0 +1,29 @@
--TEST--
GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for bat files
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != "WIN" )
die('skip Run only on Windows');
?>
--FILE--
<?php
$batch_file_content = <<<EOT
@echo off
powershell -Command "Write-Output '%1%'"
EOT;
$batch_file_path = __DIR__ . '/ghsa-54hq-v5wp-fqgv.bat';
file_put_contents($batch_file_path, $batch_file_content);
$descriptorspec = [STDIN, STDOUT, STDOUT];
$proc = proc_open([$batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
?>
--EXPECT--
"&notepad.exe
--CLEAN--
<?php
@unlink(__DIR__ . '/ghsa-54hq-v5wp-fqgv.bat');
?>

View File

@ -0,0 +1,29 @@
--TEST--
GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd files
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != "WIN" )
die('skip Run only on Windows');
?>
--FILE--
<?php
$batch_file_content = <<<EOT
@echo off
powershell -Command "Write-Output '%1%'"
EOT;
$batch_file_path = __DIR__ . '/ghsa-54hq-v5wp-fqgv.cmd';
file_put_contents($batch_file_path, $batch_file_content);
$descriptorspec = [STDIN, STDOUT, STDOUT];
$proc = proc_open([$batch_file_path, "\"&notepad<>^()!.exe"], $descriptorspec, $pipes);
proc_close($proc);
?>
--EXPECT--
"&notepad<>^()!.exe
--CLEAN--
<?php
@unlink(__DIR__ . '/ghsa-54hq-v5wp-fqgv.cmd');
?>

View File

@ -0,0 +1,29 @@
--TEST--
GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd executing batch files
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != "WIN" )
die('skip Run only on Windows');
?>
--FILE--
<?php
$batch_file_content = <<<EOT
@echo off
powershell -Command "Write-Output '%1%'"
EOT;
$batch_file_path = __DIR__ . '/ghsa-54hq-v5wp-fqgv.bat';
file_put_contents($batch_file_path, $batch_file_content);
$descriptorspec = [STDIN, STDOUT, STDOUT];
$proc = proc_open(["cmd.exe", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
?>
--EXPECT--
"&notepad.exe
--CLEAN--
<?php
@unlink(__DIR__ . '/ghsa-54hq-v5wp-fqgv.bat');
?>

View File

@ -0,0 +1,63 @@
--TEST--
ghsa-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix)
--COOKIE--
..Host-test=ignore_1;
._Host-test=ignore_2;
.[Host-test=ignore_3;
_.Host-test=ignore_4;
__Host-test=ignore_5;
_[Host-test=ignore_6;
[.Host-test=ignore_7;
[_Host-test=ignore_8;
[[Host-test=ignore_9;
..Host-test[]=ignore_10;
._Host-test[]=ignore_11;
.[Host-test[]=ignore_12;
_.Host-test[]=ignore_13;
__Host-test[]=legitimate_14;
_[Host-test[]=legitimate_15;
[.Host-test[]=ignore_16;
[_Host-test[]=ignore_17;
[[Host-test[]=ignore_18;
..Secure-test=ignore_1;
._Secure-test=ignore_2;
.[Secure-test=ignore_3;
_.Secure-test=ignore_4;
__Secure-test=ignore_5;
_[Secure-test=ignore_6;
[.Secure-test=ignore_7;
[_Secure-test=ignore_8;
[[Secure-test=ignore_9;
..Secure-test[]=ignore_10;
._Secure-test[]=ignore_11;
.[Secure-test[]=ignore_12;
_.Secure-test[]=ignore_13;
__Secure-test[]=legitimate_14;
_[Secure-test[]=legitimate_15;
[.Secure-test[]=ignore_16;
[_Secure-test[]=ignore_17;
[[Secure-test[]=ignore_18;
--FILE--
<?php
var_dump($_COOKIE);
?>
--EXPECT--
array(3) {
["__Host-test"]=>
array(1) {
[0]=>
string(13) "legitimate_14"
}
["_"]=>
array(2) {
["Host-test["]=>
string(13) "legitimate_15"
["Secure-test["]=>
string(13) "legitimate_15"
}
["__Secure-test"]=>
array(1) {
[0]=>
string(13) "legitimate_14"
}
}

View File

@ -14,7 +14,14 @@ try {
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}
try {
var_dump(password_hash("null\0password", PASSWORD_BCRYPT));
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
Invalid bcrypt cost parameter specified: 3
Invalid bcrypt cost parameter specified: 32
Bcrypt password must not contain null character

View File

@ -90,6 +90,21 @@ PHPAPI void php_register_known_variable(const char *var_name, size_t var_name_le
php_register_variable_quick(var_name, var_name_len, value, symbol_table);
}
/* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host-
* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */
static bool php_is_forbidden_variable_name(const char *mangled_name, size_t mangled_name_len, const char *pre_mangled_name)
{
if (mangled_name_len >= sizeof("__Host-")-1 && strncmp(mangled_name, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(pre_mangled_name, "__Host-", sizeof("__Host-")-1) != 0) {
return true;
}
if (mangled_name_len >= sizeof("__Secure-")-1 && strncmp(mangled_name, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(pre_mangled_name, "__Secure-", sizeof("__Secure-")-1) != 0) {
return true;
}
return false;
}
PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *track_vars_array)
{
char *p = NULL;
@ -140,20 +155,6 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac
}
var_len = p - var;
/* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- */
if (strncmp(var, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(var_name, "__Host-", sizeof("__Host-")-1) != 0) {
zval_ptr_dtor_nogc(val);
free_alloca(var_orig, use_heap);
return;
}
/* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */
if (strncmp(var, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(var_name, "__Secure-", sizeof("__Secure-")-1) != 0) {
zval_ptr_dtor_nogc(val);
free_alloca(var_orig, use_heap);
return;
}
if (var_len==0) { /* empty variable name, or variable name with a space in it */
zval_ptr_dtor_nogc(val);
free_alloca(var_orig, use_heap);
@ -257,6 +258,12 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac
return;
}
} else {
if (php_is_forbidden_variable_name(index, index_len, var_name)) {
zval_ptr_dtor_nogc(val);
free_alloca(var_orig, use_heap);
return;
}
gpc_element_p = zend_symtable_str_find(symtable1, index, index_len);
if (!gpc_element_p) {
zval tmp;
@ -294,6 +301,12 @@ plain_var:
zval_ptr_dtor_nogc(val);
}
} else {
if (php_is_forbidden_variable_name(index, index_len, var_name)) {
zval_ptr_dtor_nogc(val);
free_alloca(var_orig, use_heap);
return;
}
zend_ulong idx;
/*