Skip to content

Commit 7ca4300

Browse files
committed
Merge branch 'PHP-8.3'
2 parents fc14f17 + 049082e commit 7ca4300

11 files changed

+330
-46
lines changed

NEWS

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ PHP NEWS
195195
. Added multicast group support for ipv4 on FreeBSD. (jonathan@tangential.ca)
196196
. Added the TCP_SYNCNT constant for Linux to set number of attempts to send
197197
SYN packets from the client. (David Carlier)
198-
. Added the SO_EXCLBIND constant for exclusive socket binding on illumos/solaris.
198+
. Added the SO_EXCLBIND constant for exclusive socket binding on illumos/solaris.
199199
(David Carlier)
200200

201201
- SNMP:

ext/mbstring/mbstring.c

+31-24
Original file line numberDiff line numberDiff line change
@@ -6119,6 +6119,9 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
61196119
unsigned char *in = (unsigned char*)ZSTR_VAL(input);
61206120
size_t in_len = ZSTR_LEN(input);
61216121

6122+
ZEND_ASSERT(outcode->mime_name != NULL);
6123+
ZEND_ASSERT(outcode->mime_name[0] != '\0');
6124+
61226125
if (!in_len) {
61236126
return zend_empty_string;
61246127
}
@@ -6141,7 +6144,8 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
61416144
unsigned int state = 0;
61426145
/* wchar_buf should be big enough that when it is full, we definitely have enough
61436146
* wchars to fill an entire line of output */
6144-
uint32_t wchar_buf[80];
6147+
const size_t wchar_buf_len = 90;
6148+
uint32_t wchar_buf[wchar_buf_len];
61456149
uint32_t *p, *e;
61466150
/* What part of wchar_buf is filled with still-unprocessed data which should not
61476151
* be overwritten? */
@@ -6152,7 +6156,7 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
61526156
* spaces), just pass it through unchanged */
61536157
bool checking_leading_spaces = true;
61546158
while (in_len) {
6155-
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, 80, &state);
6159+
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, wchar_buf_len, &state);
61566160
p = wchar_buf;
61576161
e = wchar_buf + out_len;
61586162

@@ -6186,9 +6190,9 @@ no_passthrough: ;
61866190
* do so all the way to the end of the string */
61876191
while (in_len) {
61886192
/* Decode part of the input string, refill wchar_buf */
6189-
ZEND_ASSERT(offset < 80);
6190-
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state);
6191-
ZEND_ASSERT(out_len <= 80 - offset);
6193+
ZEND_ASSERT(offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len);
6194+
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, wchar_buf_len - offset, &state);
6195+
ZEND_ASSERT(out_len <= wchar_buf_len - offset);
61926196
p = wchar_buf;
61936197
e = wchar_buf + offset + out_len;
61946198
/* ASCII output is broken into space-delimited 'words'
@@ -6209,6 +6213,7 @@ no_passthrough: ;
62096213
* If we are already too far along on a line to include Base64/QPrint encoded data
62106214
* on the same line (without overrunning max line length), then add a line feed
62116215
* right now */
6216+
feed_and_mime_encode:
62126217
if (mb_convert_buf_len(&buf) - line_start + indent + strlen(outcode->mime_name) > 55) {
62136218
MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + linefeed_len + 1);
62146219
buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len);
@@ -6246,7 +6251,13 @@ no_passthrough: ;
62466251

62476252
if (in_len) {
62486253
/* Copy chars which are part of an incomplete 'word' to the beginning
6249-
* of wchar_buf and reprocess them on the next iteration */
6254+
* of wchar_buf and reprocess them on the next iteration.
6255+
* But first make sure that the incomplete 'word' isn't so big that
6256+
* there will be no space to add any more decoded wchars in the buffer
6257+
* (which could lead to an infinite loop) */
6258+
if ((word_start - wchar_buf) < MBSTRING_MIN_WCHAR_BUFSIZE) {
6259+
goto feed_and_mime_encode;
6260+
}
62506261
offset = e - word_start;
62516262
if (offset) {
62526263
memmove(wchar_buf, word_start, offset * sizeof(uint32_t));
@@ -6288,17 +6299,17 @@ mime_encoding_needed: ;
62886299

62896300
/* Do we need to refill wchar_buf to make sure we don't run out of wchars
62906301
* in the middle of a line? */
6291-
if (p == wchar_buf) {
6302+
offset = e - p;
6303+
if (wchar_buf_len - offset < MBSTRING_MIN_WCHAR_BUFSIZE) {
62926304
goto start_new_line;
62936305
}
6294-
offset = e - p;
62956306
memmove(wchar_buf, p, offset * sizeof(uint32_t));
62966307

62976308
while(true) {
62986309
refill_wchar_buf: ;
6299-
ZEND_ASSERT(offset < 80);
6300-
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state);
6301-
ZEND_ASSERT(out_len <= 80 - offset);
6310+
ZEND_ASSERT(offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len);
6311+
size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, wchar_buf_len - offset, &state);
6312+
ZEND_ASSERT(out_len <= wchar_buf_len - offset);
63026313
p = wchar_buf;
63036314
e = wchar_buf + offset + out_len;
63046315

@@ -6373,22 +6384,18 @@ start_new_line: ;
63736384

63746385
indent = 0; /* Indent argument must only affect the first line */
63756386

6376-
if (in_len) {
6377-
/* We still have more of input string remaining to decode */
6387+
if (in_len || p < e) {
6388+
/* We still have more input to process */
63786389
buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len);
63796390
buf.out = mb_convert_buf_add(buf.out, ' ');
63806391
line_start = mb_convert_buf_len(&buf);
6381-
/* Copy remaining wchars to beginning of buffer so they will be
6382-
* processed on the next iteration of outer 'do' loop */
63836392
offset = e - p;
6384-
memmove(wchar_buf, p, offset * sizeof(uint32_t));
6385-
goto refill_wchar_buf;
6386-
} else if (p < e) {
6387-
/* Input string is finished, but we still have trailing wchars
6388-
* remaining to be processed in wchar_buf */
6389-
buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len);
6390-
buf.out = mb_convert_buf_add(buf.out, ' ');
6391-
line_start = mb_convert_buf_len(&buf);
6393+
if (in_len && (wchar_buf_len - offset >= MBSTRING_MIN_WCHAR_BUFSIZE)) {
6394+
/* Copy any remaining wchars to beginning of buffer and refill
6395+
* the rest of the buffer */
6396+
memmove(wchar_buf, p, offset * sizeof(uint32_t));
6397+
goto refill_wchar_buf;
6398+
}
63926399
goto start_new_line;
63936400
} else {
63946401
/* We are done! */
@@ -6426,7 +6433,7 @@ PHP_FUNCTION(mb_encode_mimeheader)
64266433
charset = php_mb_get_encoding(charset_name, 2);
64276434
if (!charset) {
64286435
RETURN_THROWS();
6429-
} else if (charset->mime_name == NULL || charset->mime_name[0] == '\0') {
6436+
} else if (charset->mime_name == NULL || charset->mime_name[0] == '\0' || charset == &mbfl_encoding_qprint) {
64306437
zend_argument_value_error(2, "\"%s\" cannot be used for MIME header encoding", ZSTR_VAL(charset_name));
64316438
RETURN_THROWS();
64326439
}

ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt

+28-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
Test mb_encode_mimeheader() function : test cases found by fuzzer
33
--EXTENSIONS--
44
mbstring
5+
--INI--
6+
error_reporting=E_ALL^E_DEPRECATED
57
--FILE--
68
<?php
79

@@ -115,7 +117,25 @@ var_dump(mb_encode_mimeheader("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
115117
// In the general case, matching the old implementation's decision to transfer-encode or not
116118
// perfectly would require allocating potentially unbounded scratch memory (up to the size of
117119
// the input string), but we aim to only use a constant amount of temporarily allocated memory
118-
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", ""));
120+
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", ""));
121+
122+
// Regression test for infinite loop which was unintentionally caused when refactoring
123+
var_dump(mb_encode_mimeheader(",9868949,9868978,9869015,9689100,9869121,9869615,9870690,9867116,98558119861183. ", "utf-8", "B"));
124+
var_dump(mb_encode_mimeheader('xx ' . str_repeat("A", 81) . " ", "utf-8", "B"));
125+
126+
// Regression test for problem where MIME encoding loop would not leave enough space in wchar
127+
// buffer for the next iteration, causing an assertion failure
128+
mb_internal_encoding('MacJapanese');
129+
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));
130+
131+
// Regression test for failing assertion caused by the fact that QPrint deliberately generates no
132+
// wchars for CR (0x0D) bytes
133+
try {
134+
mb_internal_encoding('Quoted-Printable');
135+
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));
136+
} catch (\ValueError $e) {
137+
echo $e->getMessage() . \PHP_EOL;
138+
}
119139

120140
echo "Done";
121141
?>
@@ -156,5 +176,11 @@ string(75) " 111111111111111111111111111111111111111111111111111111111111111111
156176
string(33) "=?HZ-GB-2312?Q?=7E=7Bs=5B=7E=7D?="
157177
string(77) "2 !3"
158178
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?="
159-
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?="
179+
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?="
180+
string(135) "=?UTF-8?B?LDk4Njg5NDksOTg2ODk3OCw5ODY5MDE1LDk2ODkxMDAsOTg2OTEyMSw5ODY5?=
181+
=?UTF-8?B?NjE1LDk4NzA2OTAsOTg2NzExNiw5ODU1ODExOTg2MTE4My4g?="
182+
string(142) "xx =?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?=
183+
=?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBIA==?="
184+
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==?="
185+
mb_encode_mimeheader(): Argument #2 ($charset) "Quoted-Printable" cannot be used for MIME header encoding
160186
Done

ext/standard/password.c

+5
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ static zend_string* php_password_bcrypt_hash(const zend_string *password, zend_a
181181
zval *zcost;
182182
zend_long cost = PHP_PASSWORD_BCRYPT_COST;
183183

184+
if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) {
185+
zend_value_error("Bcrypt password must not contain null character");
186+
return NULL;
187+
}
188+
184189
if (options && (zcost = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) {
185190
cost = zval_get_long(zcost);
186191
}

ext/standard/proc_open.c

+81-5
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,32 @@ static void append_backslashes(smart_str *str, size_t num_bs)
536536
}
537537
}
538538

539-
/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */
540-
static void append_win_escaped_arg(smart_str *str, zend_string *arg)
539+
const char *special_chars = "()!^\"<>&|%";
540+
541+
static bool is_special_character_present(const zend_string *arg)
542+
{
543+
for (size_t i = 0; i < ZSTR_LEN(arg); ++i) {
544+
if (strchr(special_chars, ZSTR_VAL(arg)[i]) != NULL) {
545+
return true;
546+
}
547+
}
548+
return false;
549+
}
550+
551+
/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments and
552+
* https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way */
553+
static void append_win_escaped_arg(smart_str *str, zend_string *arg, bool is_cmd_argument)
541554
{
542555
size_t num_bs = 0;
556+
bool has_special_character = false;
543557

558+
if (is_cmd_argument) {
559+
has_special_character = is_special_character_present(arg);
560+
if (has_special_character) {
561+
/* Escape double quote with ^ if executed by cmd.exe. */
562+
smart_str_appendc(str, '^');
563+
}
564+
}
544565
smart_str_appendc(str, '"');
545566
for (size_t i = 0; i < ZSTR_LEN(arg); ++i) {
546567
char c = ZSTR_VAL(arg)[i];
@@ -554,18 +575,71 @@ static void append_win_escaped_arg(smart_str *str, zend_string *arg)
554575
num_bs = num_bs * 2 + 1;
555576
}
556577
append_backslashes(str, num_bs);
578+
if (has_special_character && strchr(special_chars, c) != NULL) {
579+
/* Escape special chars with ^ if executed by cmd.exe. */
580+
smart_str_appendc(str, '^');
581+
}
557582
smart_str_appendc(str, c);
558583
num_bs = 0;
559584
}
560585
append_backslashes(str, num_bs * 2);
586+
if (has_special_character) {
587+
/* Escape double quote with ^ if executed by cmd.exe. */
588+
smart_str_appendc(str, '^');
589+
}
561590
smart_str_appendc(str, '"');
562591
}
563592

593+
static inline int stricmp_end(const char* suffix, const char* str) {
594+
size_t suffix_len = strlen(suffix);
595+
size_t str_len = strlen(str);
596+
597+
if (suffix_len > str_len) {
598+
return -1; /* Suffix is longer than string, cannot match. */
599+
}
600+
601+
/* Compare the end of the string with the suffix, ignoring case. */
602+
return _stricmp(str + (str_len - suffix_len), suffix);
603+
}
604+
605+
static bool is_executed_by_cmd(const char *prog_name)
606+
{
607+
/* If program name is cmd.exe, then return true. */
608+
if (_stricmp("cmd.exe", prog_name) == 0 || _stricmp("cmd", prog_name) == 0
609+
|| stricmp_end("\\cmd.exe", prog_name) == 0 || stricmp_end("\\cmd", prog_name) == 0) {
610+
return true;
611+
}
612+
613+
/* Find the last occurrence of the directory separator (backslash or forward slash). */
614+
char *last_separator = strrchr(prog_name, '\\');
615+
char *last_separator_fwd = strrchr(prog_name, '/');
616+
if (last_separator_fwd && (!last_separator || last_separator < last_separator_fwd)) {
617+
last_separator = last_separator_fwd;
618+
}
619+
620+
/* Find the last dot in the filename after the last directory separator. */
621+
char *extension = NULL;
622+
if (last_separator != NULL) {
623+
extension = strrchr(last_separator, '.');
624+
} else {
625+
extension = strrchr(prog_name, '.');
626+
}
627+
628+
if (extension == NULL || extension == prog_name) {
629+
/* No file extension found, it is not batch file. */
630+
return false;
631+
}
632+
633+
/* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */
634+
return _stricmp(extension, ".bat") == 0 || _stricmp(extension, ".cmd") == 0;
635+
}
636+
564637
static zend_string *create_win_command_from_args(HashTable *args)
565638
{
566639
smart_str str = {0};
567640
zval *arg_zv;
568-
bool is_prog_name = 1;
641+
bool is_prog_name = true;
642+
bool is_cmd_execution = false;
569643
int elem_num = 0;
570644

571645
ZEND_HASH_FOREACH_VAL(args, arg_zv) {
@@ -575,11 +649,13 @@ static zend_string *create_win_command_from_args(HashTable *args)
575649
return NULL;
576650
}
577651

578-
if (!is_prog_name) {
652+
if (is_prog_name) {
653+
is_cmd_execution = is_executed_by_cmd(ZSTR_VAL(arg_str));
654+
} else {
579655
smart_str_appendc(&str, ' ');
580656
}
581657

582-
append_win_escaped_arg(&str, arg_str);
658+
append_win_escaped_arg(&str, arg_str, !is_prog_name && is_cmd_execution);
583659

584660
is_prog_name = 0;
585661
zend_string_release(arg_str);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for bat files
3+
--SKIPIF--
4+
<?php
5+
if( substr(PHP_OS, 0, 3) != "WIN" )
6+
die('skip Run only on Windows');
7+
?>
8+
--FILE--
9+
<?php
10+
11+
$batch_file_content = <<<EOT
12+
@echo off
13+
powershell -Command "Write-Output '%1%'"
14+
EOT;
15+
$batch_file_path = __DIR__ . '/ghsa-54hq-v5wp-fqgv.bat';
16+
17+
file_put_contents($batch_file_path, $batch_file_content);
18+
19+
$descriptorspec = [STDIN, STDOUT, STDOUT];
20+
$proc = proc_open([$batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
21+
proc_close($proc);
22+
23+
?>
24+
--EXPECT--
25+
"&notepad.exe
26+
--CLEAN--
27+
<?php
28+
@unlink(__DIR__ . '/ghsa-54hq-v5wp-fqgv.bat');
29+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd files
3+
--SKIPIF--
4+
<?php
5+
if( substr(PHP_OS, 0, 3) != "WIN" )
6+
die('skip Run only on Windows');
7+
?>
8+
--FILE--
9+
<?php
10+
11+
$batch_file_content = <<<EOT
12+
@echo off
13+
powershell -Command "Write-Output '%1%'"
14+
EOT;
15+
$batch_file_path = __DIR__ . '/ghsa-54hq-v5wp-fqgv.cmd';
16+
17+
file_put_contents($batch_file_path, $batch_file_content);
18+
19+
$descriptorspec = [STDIN, STDOUT, STDOUT];
20+
$proc = proc_open([$batch_file_path, "\"&notepad<>^()!.exe"], $descriptorspec, $pipes);
21+
proc_close($proc);
22+
23+
?>
24+
--EXPECT--
25+
"&notepad<>^()!.exe
26+
--CLEAN--
27+
<?php
28+
@unlink(__DIR__ . '/ghsa-54hq-v5wp-fqgv.cmd');
29+
?>

0 commit comments

Comments
 (0)