Skip to content

Commit

Permalink
update php to 8.1.29 (#654)
Browse files Browse the repository at this point in the history
* update php to 8.1.29

* Update PHP-VERSION.conf

* Revert main.c
  • Loading branch information
aldok10 authored and matyhtf committed Aug 23, 2024
1 parent 5df2354 commit 645e322
Show file tree
Hide file tree
Showing 16 changed files with 999 additions and 39 deletions.
2 changes: 1 addition & 1 deletion Zend/zend.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#ifndef ZEND_H
#define ZEND_H

#define ZEND_VERSION "4.1.27"
#define ZEND_VERSION "4.1.29"

#define ZEND_ENGINE_3

Expand Down
35 changes: 20 additions & 15 deletions ext/filter/logical_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
#define FORMAT_IPV4 4
#define FORMAT_IPV6 6

static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]);
static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]);

static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */
zend_long ctx_value;
Expand Down Expand Up @@ -580,6 +580,14 @@ static int is_userinfo_valid(zend_string *str)
return 1;
}

static bool php_filter_is_valid_ipv6_hostname(const char *s, size_t l)
{
const char *e = s + l;
const char *t = e - 1;

return *s == '[' && *t == ']' && _php_filter_validate_ipv6(s + 1, l - 2, NULL);
}

void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
php_url *url;
Expand All @@ -600,7 +608,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */

if (url->scheme != NULL &&
(zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) {
char *e, *s, *t;
const char *s;
size_t l;

if (url->host == NULL) {
Expand All @@ -609,17 +617,14 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */

s = ZSTR_VAL(url->host);
l = ZSTR_LEN(url->host);
e = s + l;
t = e - 1;

/* An IPv6 enclosed by square brackets is a valid hostname */
if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2, NULL)) {
php_url_free(url);
return;
}

// Validate domain
if (!_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)) {
if (
/* An IPv6 enclosed by square brackets is a valid hostname.*/
!php_filter_is_valid_ipv6_hostname(s, l) &&
/* Validate domain.
* This includes a loose check for an IPv4 address. */
!_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)
) {
php_url_free(url);
RETURN_VALIDATION_FAILED
}
Expand Down Expand Up @@ -753,15 +758,15 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{
}
/* }}} */

static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]) /* {{{ */
static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) /* {{{ */
{
int compressed_pos = -1;
int blocks = 0;
int num, n, i;
char *ipv4;
char *end;
const char *end;
int ip4elm[4];
char *s = str;
const char *s = str;

if (!memchr(str, ':', str_len)) {
return 0;
Expand Down
41 changes: 41 additions & 0 deletions ext/filter/tests/ghsa-w8qr-v226-r27w.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
GHSA-w8qr-v226-r27w
--EXTENSIONS--
filter
--FILE--
<?php

function test(string $input) {
var_dump(filter_var($input, FILTER_VALIDATE_URL));
}

echo "--- These ones should fail ---\n";
test("http://t[est@127.0.0.1");
test("http://t[est@[::1]");
test("http://t[est@[::1");
test("http://t[est@::1]");
test("http://php.net\\@aliyun.com/aaa.do");
test("http://test[@2001:db8:3333:4444:5555:6666:1.2.3.4]");
test("http://te[st@2001:db8:3333:4444:5555:6666:1.2.3.4]");
test("http://te[st@2001:db8:3333:4444:5555:6666:1.2.3.4");

echo "--- These ones should work ---\n";
test("http://test@127.0.0.1");
test("http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]");
test("http://test@[::1]");

?>
--EXPECT--
--- These ones should fail ---
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
--- These ones should work ---
string(21) "http://test@127.0.0.1"
string(50) "http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]"
string(17) "http://test@[::1]"
5 changes: 5 additions & 0 deletions ext/standard/password.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,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);
}
Expand Down
77 changes: 72 additions & 5 deletions ext/standard/proc_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,11 +492,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];
Expand All @@ -510,18 +531,62 @@ 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 bool is_executed_by_cmd(const char *prog_name, size_t prog_name_length)
{
size_t out_len;
WCHAR long_name[MAX_PATH];
WCHAR full_name[MAX_PATH];
LPWSTR file_part = NULL;

wchar_t *prog_name_wide = php_win32_cp_conv_any_to_w(prog_name, prog_name_length, &out_len);

if (GetLongPathNameW(prog_name_wide, long_name, MAX_PATH) == 0) {
/* This can fail for example with ERROR_FILE_NOT_FOUND (short path resolution only works for existing files)
* in which case we'll pass the path verbatim to the FullPath transformation. */
lstrcpynW(long_name, prog_name_wide, MAX_PATH);
}

free(prog_name_wide);
prog_name_wide = NULL;

if (GetFullPathNameW(long_name, MAX_PATH, full_name, &file_part) == 0 || file_part == NULL) {
return false;
}

bool uses_cmd = false;
if (_wcsicmp(file_part, L"cmd.exe") == 0 || _wcsicmp(file_part, L"cmd") == 0) {
uses_cmd = true;
} else {
const WCHAR *extension_dot = wcsrchr(file_part, L'.');
if (extension_dot && (_wcsicmp(extension_dot, L".bat") == 0 || _wcsicmp(extension_dot, L".cmd") == 0)) {
uses_cmd = true;
}
}

return uses_cmd;
}

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) {
Expand All @@ -531,11 +596,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), ZSTR_LEN(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);
Expand Down
56 changes: 56 additions & 0 deletions ext/standard/tests/general_functions/ghsa-9fcc-425m-g385_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
--TEST--
GHSA-9fcc-425m-g385 - bypass CVE-2024-1874 - batch file variation
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != "WIN" )
die('skip Run only on Windows');
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
?>
--FILE--
<?php

$batch_file_content = <<<EOT
@echo off
powershell -Command "Write-Output '%0%'"
powershell -Command "Write-Output '%1%'"
EOT;
$batch_file_path = __DIR__ . '/ghsa-9fcc-425m-g385_001.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);
$proc = proc_open([$batch_file_path . " ", "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open([$batch_file_path . ". ", "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open([$batch_file_path . ". ... ", "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open([$batch_file_path . ". ... . ", "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open([$batch_file_path . ". ... . .", "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
proc_open([$batch_file_path . ". .\\.. . .", "\"&notepad.exe"], $descriptorspec, $pipes);

?>
--EXPECTF--
'"%sghsa-9fcc-425m-g385_001.bat."' is not recognized as an internal or external command,
operable program or batch file.
%sghsa-9fcc-425m-g385_001.bat
"&notepad.exe
%sghsa-9fcc-425m-g385_001.bat.
"&notepad.exe
%sghsa-9fcc-425m-g385_001.bat. ...
"&notepad.exe
%sghsa-9fcc-425m-g385_001.bat. ... .
"&notepad.exe
'"%sghsa-9fcc-425m-g385_001.bat. ... . ."' is not recognized as an internal or external command,
operable program or batch file.

Warning: proc_open(): CreateProcess failed, error code: 2 in %s on line %d
--CLEAN--
<?php
@unlink(__DIR__ . '/ghsa-9fcc-425m-g385_001.bat');
?>
66 changes: 66 additions & 0 deletions ext/standard/tests/general_functions/ghsa-9fcc-425m-g385_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
--TEST--
GHSA-9fcc-425m-g385 - bypass CVE-2024-1874 - cmd.exe variation
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != "WIN" )
die('skip Run only on Windows');
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
?>
--FILE--
<?php

$batch_file_content = <<<EOT
@echo off
powershell -Command "Write-Output '%0%'"
powershell -Command "Write-Output '%1%'"
EOT;
$batch_file_path = __DIR__ . '/ghsa-9fcc-425m-g385_002.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);
$proc = proc_open(["cmd.exe ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open(["cmd.exe. ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open(["cmd.exe. ... ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open(["\\cmd.exe. ... ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);

$proc = proc_open(["cmd", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open(["cmd ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
proc_close($proc);
$proc = proc_open(["cmd. ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
$proc = proc_open(["cmd. ... ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);
$proc = proc_open(["\\cmd. ... ", "/c", $batch_file_path, "\"&notepad.exe"], $descriptorspec, $pipes);

?>
--EXPECTF--
%sghsa-9fcc-425m-g385_002.bat
"&notepad.exe
%sghsa-9fcc-425m-g385_002.bat
"&notepad.exe
%sghsa-9fcc-425m-g385_002.bat
"&notepad.exe
%sghsa-9fcc-425m-g385_002.bat
"&notepad.exe

Warning: proc_open(): CreateProcess failed, error code: 2 in %s on line %d
%sghsa-9fcc-425m-g385_002.bat
"&notepad.exe
%sghsa-9fcc-425m-g385_002.bat
"&notepad.exe

Warning: proc_open(): CreateProcess failed, error code: 2 in %s on line %d

Warning: proc_open(): CreateProcess failed, error code: 2 in %s on line %d

Warning: proc_open(): CreateProcess failed, error code: 2 in %s on line %d
--CLEAN--
<?php
@unlink(__DIR__ . '/ghsa-9fcc-425m-g385_002.bat');
?>
Loading

0 comments on commit 645e322

Please sign in to comment.