import UBI php-7.4.33-3.module+el8.10.0+23902+d3c8dd8f
This commit is contained in:
parent
93f2151a5a
commit
204bf317c0
68
SOURCES/php-cve-2024-11233.patch
Normal file
68
SOURCES/php-cve-2024-11233.patch
Normal file
File diff suppressed because one or more lines are too long
95
SOURCES/php-cve-2024-11234.patch
Normal file
95
SOURCES/php-cve-2024-11234.patch
Normal file
@ -0,0 +1,95 @@
|
||||
From 494de65139592da0e5e5b6fdf198c2f9c762f4d6 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Fri, 8 Nov 2024 23:43:47 +0100
|
||||
Subject: [PATCH 3/7] Fix GHSA-c5f2-jwm7-mmq2: stream HTTP fulluri CRLF
|
||||
injection
|
||||
|
||||
(cherry picked from commit 426a6d4539ebee34879ac5de857036bb6ff0e732)
|
||||
(cherry picked from commit bc1f192102dd8cbda028e40aa31604c4885d387c)
|
||||
(cherry picked from commit 8d130e16fbfda7d154fedfa0f1ff1d5ad5e26815)
|
||||
---
|
||||
ext/standard/http_fopen_wrapper.c | 18 ++++++++----
|
||||
.../tests/http/ghsa-c5f2-jwm7-mmq2.phpt | 28 +++++++++++++++++++
|
||||
2 files changed, 40 insertions(+), 6 deletions(-)
|
||||
create mode 100644 ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt
|
||||
|
||||
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
|
||||
index 4d918b21e65..aeeb438f0f9 100644
|
||||
--- a/ext/standard/http_fopen_wrapper.c
|
||||
+++ b/ext/standard/http_fopen_wrapper.c
|
||||
@@ -186,6 +186,11 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ /* Should we send the entire path in the request line, default to no. */
|
||||
+ if (context && (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) {
|
||||
+ request_fulluri = zend_is_true(tmpzval);
|
||||
+ }
|
||||
+
|
||||
use_ssl = resource->scheme && (ZSTR_LEN(resource->scheme) > 4) && ZSTR_VAL(resource->scheme)[4] == 's';
|
||||
/* choose default ports */
|
||||
if (use_ssl && resource->port == 0)
|
||||
@@ -205,6 +210,13 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
|
||||
}
|
||||
}
|
||||
|
||||
+ if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) {
|
||||
+ php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper full URI path does not allow CR or LF characters");
|
||||
+ php_url_free(resource);
|
||||
+ efree(transport_string);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
if (context && (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "timeout")) != NULL) {
|
||||
double d = zval_get_double(tmpzval);
|
||||
#ifndef PHP_WIN32
|
||||
@@ -385,12 +397,6 @@ finish:
|
||||
smart_str_appends(&req_buf, "GET ");
|
||||
}
|
||||
|
||||
- /* Should we send the entire path in the request line, default to no. */
|
||||
- if (!request_fulluri && context &&
|
||||
- (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) {
|
||||
- request_fulluri = zend_is_true(tmpzval);
|
||||
- }
|
||||
-
|
||||
if (request_fulluri) {
|
||||
/* Ask for everything */
|
||||
smart_str_appends(&req_buf, path);
|
||||
diff --git a/ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt b/ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..5b2e04f94f2
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt
|
||||
@@ -0,0 +1,28 @@
|
||||
+--TEST--
|
||||
+GHSA-c5f2-jwm7-mmq2 (Configuring a proxy in a stream context might allow for CRLF injection in URIs)
|
||||
+--INI--
|
||||
+allow_url_fopen=1
|
||||
+--CONFLICTS--
|
||||
+server
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+echo $_SERVER['REQUEST_URI'];
|
||||
+CODE;
|
||||
+
|
||||
+include __DIR__."/../../../../sapi/cli/tests/php_cli_server.inc";
|
||||
+php_cli_server_start($serverCode, null, []);
|
||||
+
|
||||
+$host = PHP_CLI_SERVER_ADDRESS;
|
||||
+$userinput = "index.php HTTP/1.1\r\nHost: $host\r\n\r\nGET /index2.php HTTP/1.1\r\nHost: $host\r\n\r\nGET /index.php";
|
||||
+$context = stream_context_create(['http' => ['proxy' => 'tcp://' . $host, 'request_fulluri' => true]]);
|
||||
+echo file_get_contents("http://$host/$userinput", false, $context);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Warning: file_get_contents(http://localhost:%d/index.php HTTP/1.1
|
||||
+Host: localhost:%d
|
||||
+
|
||||
+GET /index2.php HTTP/1.1
|
||||
+Host: localhost:%d
|
||||
+
|
||||
+GET /index.php): failed to open stream: HTTP wrapper full URI path does not allow CR or LF characters in %s on line %d
|
||||
--
|
||||
2.47.0
|
||||
|
||||
119
SOURCES/php-cve-2024-11236.patch
Normal file
119
SOURCES/php-cve-2024-11236.patch
Normal file
@ -0,0 +1,119 @@
|
||||
From 97546df8d6900b115536c17af9213f1da837b82e Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
|
||||
Date: Thu, 24 Oct 2024 22:02:17 +0200
|
||||
Subject: [PATCH 1/7] Fix GHSA-5hqh-c84r-qjcv: Integer overflow in the dblib
|
||||
quoter causing OOB writes
|
||||
|
||||
(cherry picked from commit d9baa9fed8c3ba692a36b388c0c7762e5102e2e0)
|
||||
(cherry picked from commit 5d9e54065ed18c51e4f25d8900635f90810c7394)
|
||||
---
|
||||
ext/pdo_dblib/dblib_driver.c | 8 ++++++-
|
||||
ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt | 24 ++++++++++++++++++++
|
||||
2 files changed, 31 insertions(+), 1 deletion(-)
|
||||
create mode 100644 ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
|
||||
|
||||
diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c
|
||||
index f36451afeeb..1dc75a4d2e3 100644
|
||||
--- a/ext/pdo_dblib/dblib_driver.c
|
||||
+++ b/ext/pdo_dblib/dblib_driver.c
|
||||
@@ -154,6 +154,7 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
|
||||
|
||||
size_t i;
|
||||
char * q;
|
||||
+ size_t extralen = 0;
|
||||
*quotedlen = 0;
|
||||
|
||||
if (H->assume_national_character_set_strings) {
|
||||
@@ -168,7 +169,7 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
|
||||
|
||||
/* Detect quoted length, adding extra char for doubled single quotes */
|
||||
for (i = 0; i < unquotedlen; i++) {
|
||||
- if (unquoted[i] == '\'') ++*quotedlen;
|
||||
+ if (unquoted[i] == '\'') ++extralen;
|
||||
++*quotedlen;
|
||||
}
|
||||
|
||||
@@ -176,6 +177,11 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
|
||||
if (use_national_character_set) {
|
||||
++*quotedlen; /* N prefix */
|
||||
}
|
||||
+ if (UNEXPECTED(*quotedlen > ZSTR_MAX_LEN - extralen)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ *quotedlen += extralen;
|
||||
q = *quoted = emalloc(*quotedlen + 1); /* Add byte for terminal null */
|
||||
if (use_national_character_set) {
|
||||
*q++ = 'N';
|
||||
diff --git a/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt b/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..431c61951ee
|
||||
--- /dev/null
|
||||
+++ b/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
|
||||
@@ -0,0 +1,24 @@
|
||||
+--TEST--
|
||||
+GHSA-5hqh-c84r-qjcv (Integer overflow in the dblib quoter causing OOB writes)
|
||||
+--EXTENSIONS--
|
||||
+pdo_dblib
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (PHP_INT_SIZE != 4) die("skip for 32bit platforms only");
|
||||
+if (PHP_OS_FAMILY === "Windows") die("skip not for Windows because the virtual address space for application is only 2GiB");
|
||||
+if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
|
||||
+require __DIR__ . '/config.inc';
|
||||
+getDbConnection();
|
||||
+?>
|
||||
+--INI--
|
||||
+memory_limit=-1
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+require __DIR__ . '/config.inc';
|
||||
+$db = getDbConnection();
|
||||
+var_dump($db->quote(str_repeat("'", 2147483646)));
|
||||
+
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+bool(false)
|
||||
--
|
||||
2.47.0
|
||||
|
||||
From 0530cbfe5c3044537de52d8382eba5d69dbac726 Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
|
||||
Date: Thu, 24 Oct 2024 22:02:36 +0200
|
||||
Subject: [PATCH 2/7] Fix GHSA-5hqh-c84r-qjcv: Integer overflow in the firebird
|
||||
quoter causing OOB writes
|
||||
|
||||
(cherry picked from commit 69c5f68fdc3deed9ebce2cc44b4bf5e0c47cd28f)
|
||||
(cherry picked from commit b4f73be75dbdde970a18cc7a636898b10400fb3f)
|
||||
---
|
||||
ext/pdo_firebird/firebird_driver.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
|
||||
index 3e403afd368..5b74290abcc 100644
|
||||
--- a/ext/pdo_firebird/firebird_driver.c
|
||||
+++ b/ext/pdo_firebird/firebird_driver.c
|
||||
@@ -243,7 +243,7 @@ free_statement:
|
||||
static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, /* {{{ */
|
||||
char **quoted, size_t *quotedlen, enum pdo_param_type paramtype)
|
||||
{
|
||||
- int qcount = 0;
|
||||
+ size_t qcount = 0;
|
||||
char const *co, *l, *r;
|
||||
char *c;
|
||||
|
||||
@@ -258,6 +258,10 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t u
|
||||
/* count the number of ' characters */
|
||||
for (co = unquoted; (co = strchr(co,'\'')); qcount++, co++);
|
||||
|
||||
+ if (UNEXPECTED(unquotedlen + 2 > ZSTR_MAX_LEN - qcount)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
*quotedlen = unquotedlen + qcount + 2;
|
||||
*quoted = c = emalloc(*quotedlen+1);
|
||||
*c++ = '\'';
|
||||
--
|
||||
2.47.0
|
||||
|
||||
2714
SOURCES/php-cve-2024-8929.patch
Normal file
2714
SOURCES/php-cve-2024-8929.patch
Normal file
File diff suppressed because it is too large
Load Diff
139
SOURCES/php-cve-2024-8932.patch
Normal file
139
SOURCES/php-cve-2024-8932.patch
Normal file
@ -0,0 +1,139 @@
|
||||
From 50e9e72530a4805980384b8ea6672877af816145 Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
|
||||
Date: Thu, 26 Sep 2024 22:22:27 +0200
|
||||
Subject: [PATCH 4/7] Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape
|
||||
|
||||
(cherry picked from commit f9ecf90070a11dad09ca7671a712f81cc2a7d52f)
|
||||
(cherry picked from commit 9f367d847989b339c33369737daf573e30bab5f1)
|
||||
---
|
||||
ext/ldap/ldap.c | 21 ++++++++++++++--
|
||||
ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt | 28 ++++++++++++++++++++++
|
||||
ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt | 29 +++++++++++++++++++++++
|
||||
3 files changed, 76 insertions(+), 2 deletions(-)
|
||||
create mode 100644 ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
|
||||
create mode 100644 ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
|
||||
|
||||
diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c
|
||||
index 72a39bd93df..75adf1b5df2 100644
|
||||
--- a/ext/ldap/ldap.c
|
||||
+++ b/ext/ldap/ldap.c
|
||||
@@ -49,6 +49,7 @@
|
||||
|
||||
#include "ext/standard/php_string.h"
|
||||
#include "ext/standard/info.h"
|
||||
+#include "Zend/zend_exceptions.h"
|
||||
|
||||
#ifdef HAVE_LDAP_SASL
|
||||
#include <sasl/sasl.h>
|
||||
@@ -3836,13 +3837,23 @@ static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value,
|
||||
zend_string *ret;
|
||||
|
||||
for (i = 0; i < valuelen; i++) {
|
||||
- len += (map[(unsigned char) value[i]]) ? 3 : 1;
|
||||
+ size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
|
||||
+ if (len > ZSTR_MAX_LEN - addend) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ len += addend;
|
||||
}
|
||||
/* Per RFC 4514, a leading and trailing space must be escaped */
|
||||
if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
|
||||
+ if (len > ZSTR_MAX_LEN - 2) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
len += 2;
|
||||
}
|
||||
if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
|
||||
+ if (len > ZSTR_MAX_LEN - 2) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
len += 2;
|
||||
}
|
||||
|
||||
@@ -3909,7 +3920,13 @@ PHP_FUNCTION(ldap_escape)
|
||||
php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
|
||||
}
|
||||
|
||||
- RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
|
||||
+ zend_string *result = php_ldap_do_escape(map, value, valuelen, flags);
|
||||
+ if (UNEXPECTED(!result)) {
|
||||
+ zend_throw_exception(NULL, "Argument #1 ($value) is too long", 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ RETURN_NEW_STR(result);
|
||||
}
|
||||
|
||||
#ifdef STR_TRANSLATION
|
||||
diff --git a/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt b/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..734bbe91d42
|
||||
--- /dev/null
|
||||
+++ b/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
|
||||
@@ -0,0 +1,28 @@
|
||||
+--TEST--
|
||||
+GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
|
||||
+--EXTENSIONS--
|
||||
+ldap
|
||||
+--INI--
|
||||
+memory_limit=-1
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
|
||||
+if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+try {
|
||||
+ ldap_escape(' '.str_repeat("#", 1431655758), "", LDAP_ESCAPE_DN);
|
||||
+} catch (Exception $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+
|
||||
+try {
|
||||
+ ldap_escape(str_repeat("#", 1431655758).' ', "", LDAP_ESCAPE_DN);
|
||||
+} catch (Exception $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+ldap_escape(): Argument #1 ($value) is too long
|
||||
+ldap_escape(): Argument #1 ($value) is too long
|
||||
diff --git a/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt b/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..5c1b0fb6611
|
||||
--- /dev/null
|
||||
+++ b/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
|
||||
@@ -0,0 +1,29 @@
|
||||
+--TEST--
|
||||
+GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
|
||||
+--EXTENSIONS--
|
||||
+ldap
|
||||
+--INI--
|
||||
+memory_limit=-1
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
|
||||
+if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+try {
|
||||
+ ldap_escape(str_repeat("*", 1431655759), "", LDAP_ESCAPE_FILTER);
|
||||
+} catch (Exception $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+
|
||||
+// would allocate a string of length 2
|
||||
+try {
|
||||
+ ldap_escape(str_repeat("*", 1431655766), "", LDAP_ESCAPE_FILTER);
|
||||
+} catch (Exception $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+ldap_escape(): Argument #1 ($value) is too long
|
||||
+ldap_escape(): Argument #1 ($value) is too long
|
||||
--
|
||||
2.47.0
|
||||
|
||||
917
SOURCES/php-cve-2025-1217.patch
Normal file
917
SOURCES/php-cve-2025-1217.patch
Normal file
@ -0,0 +1,917 @@
|
||||
From bf4a8df2b3972118c87b05450e9062d3926f6be8 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Tue, 31 Dec 2024 18:57:02 +0100
|
||||
Subject: [PATCH 01/11] Fix GHSA-ghsa-v8xr-gpvj-cx9g: http header folding
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds HTTP header folding support for HTTP wrapper response
|
||||
headers.
|
||||
|
||||
Reviewed-by: Tim Düsterhus <tim@tideways-gmbh.com>
|
||||
(cherry picked from commit d20b4c97a9f883b62b65b82d939c5af9a2028ef1)
|
||||
(cherry picked from commit 4fec08542748c25573063ffc53ea89cd5de1edf0)
|
||||
---
|
||||
ext/openssl/tests/ServerClientTestCase.inc | 65 +++-
|
||||
ext/standard/http_fopen_wrapper.c | 347 ++++++++++++------
|
||||
.../tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt | 49 +++
|
||||
.../tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt | 51 +++
|
||||
.../tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt | 49 +++
|
||||
.../tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt | 48 +++
|
||||
.../tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt | 48 +++
|
||||
.../tests/http/http_response_header_05.phpt | 35 --
|
||||
8 files changed, 537 insertions(+), 155 deletions(-)
|
||||
create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
|
||||
delete mode 100644 ext/standard/tests/http/http_response_header_05.phpt
|
||||
|
||||
diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc
|
||||
index 753366df6f4..c74da444102 100644
|
||||
--- a/ext/openssl/tests/ServerClientTestCase.inc
|
||||
+++ b/ext/openssl/tests/ServerClientTestCase.inc
|
||||
@@ -4,14 +4,19 @@ const WORKER_ARGV_VALUE = 'RUN_WORKER';
|
||||
|
||||
const WORKER_DEFAULT_NAME = 'server';
|
||||
|
||||
-function phpt_notify($worker = WORKER_DEFAULT_NAME)
|
||||
+function phpt_notify(string $worker = WORKER_DEFAULT_NAME, string $message = ""): void
|
||||
{
|
||||
- ServerClientTestCase::getInstance()->notify($worker);
|
||||
+ ServerClientTestCase::getInstance()->notify($worker, $message);
|
||||
}
|
||||
|
||||
-function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null)
|
||||
+function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null): ?string
|
||||
{
|
||||
- ServerClientTestCase::getInstance()->wait($worker, $timeout);
|
||||
+ return ServerClientTestCase::getInstance()->wait($worker, $timeout);
|
||||
+}
|
||||
+
|
||||
+function phpt_notify_server_start($server): void
|
||||
+{
|
||||
+ ServerClientTestCase::getInstance()->notify_server_start($server);
|
||||
}
|
||||
|
||||
function phpt_has_sslv3() {
|
||||
@@ -119,43 +124,73 @@ class ServerClientTestCase
|
||||
eval($code);
|
||||
}
|
||||
|
||||
- public function run($masterCode, $workerCode)
|
||||
+ /**
|
||||
+ * Run client and all workers
|
||||
+ *
|
||||
+ * @param string $clientCode The client PHP code
|
||||
+ * @param string|array $workerCode
|
||||
+ * @param bool $ephemeral Select whether automatic port selection and automatic awaiting is used
|
||||
+ * @return void
|
||||
+ * @throws Exception
|
||||
+ */
|
||||
+ public function run(string $clientCode, $workerCode, bool $ephemeral = true): void
|
||||
{
|
||||
if (!is_array($workerCode)) {
|
||||
$workerCode = [WORKER_DEFAULT_NAME => $workerCode];
|
||||
}
|
||||
- foreach ($workerCode as $worker => $code) {
|
||||
+ reset($workerCode);
|
||||
+ $code = current($workerCode);
|
||||
+ $worker = key($workerCode);
|
||||
+ while ($worker != null) {
|
||||
$this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code));
|
||||
+ $code = next($workerCode);
|
||||
+ if ($ephemeral) {
|
||||
+ $addr = trim($this->wait($worker));
|
||||
+ if (empty($addr)) {
|
||||
+ throw new \Exception("Failed server start");
|
||||
+ }
|
||||
+ if ($code === false) {
|
||||
+ $clientCode = preg_replace('/{{\s*ADDR\s*}}/', $addr, $clientCode);
|
||||
+ } else {
|
||||
+ $code = preg_replace('/{{\s*ADDR\s*}}/', $addr, $code);
|
||||
+ }
|
||||
+ }
|
||||
+ $worker = key($workerCode);
|
||||
}
|
||||
- eval($this->stripPhpTagsFromCode($masterCode));
|
||||
+
|
||||
+ eval($this->stripPhpTagsFromCode($clientCode));
|
||||
foreach ($workerCode as $worker => $code) {
|
||||
$this->cleanupWorkerProcess($worker);
|
||||
}
|
||||
}
|
||||
|
||||
- public function wait($worker, $timeout = null)
|
||||
+ public function wait($worker, $timeout = null): ?string
|
||||
{
|
||||
$handle = $this->isWorker ? STDIN : $this->workerStdOut[$worker];
|
||||
if ($timeout === null) {
|
||||
- fgets($handle);
|
||||
- return true;
|
||||
+ return fgets($handle);
|
||||
}
|
||||
|
||||
stream_set_blocking($handle, false);
|
||||
$read = [$handle];
|
||||
$result = stream_select($read, $write, $except, $timeout);
|
||||
if (!$result) {
|
||||
- return false;
|
||||
+ return null;
|
||||
}
|
||||
|
||||
- fgets($handle);
|
||||
+ $result = fgets($handle);
|
||||
stream_set_blocking($handle, true);
|
||||
- return true;
|
||||
+ return $result;
|
||||
+ }
|
||||
+
|
||||
+ public function notify(string $worker, string $message = ""): void
|
||||
+ {
|
||||
+ fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "$message\n");
|
||||
}
|
||||
|
||||
- public function notify($worker)
|
||||
+ public function notify_server_start($server): void
|
||||
{
|
||||
- fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "\n");
|
||||
+ echo stream_socket_get_name($server, false) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
|
||||
index aeeb438f0f9..08386cfafcd 100644
|
||||
--- a/ext/standard/http_fopen_wrapper.c
|
||||
+++ b/ext/standard/http_fopen_wrapper.c
|
||||
@@ -116,6 +116,172 @@ static zend_bool check_has_header(const char *headers, const char *header) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+typedef struct _php_stream_http_response_header_info {
|
||||
+ php_stream_filter *transfer_encoding;
|
||||
+ size_t file_size;
|
||||
+ zend_bool follow_location;
|
||||
+ char location[HTTP_HEADER_BLOCK_SIZE];
|
||||
+} php_stream_http_response_header_info;
|
||||
+
|
||||
+static void php_stream_http_response_header_info_init(
|
||||
+ php_stream_http_response_header_info *header_info)
|
||||
+{
|
||||
+ header_info->transfer_encoding = NULL;
|
||||
+ header_info->file_size = 0;
|
||||
+ header_info->follow_location = 1;
|
||||
+ header_info->location[0] = '\0';
|
||||
+}
|
||||
+
|
||||
+/* Trim white spaces from response header line and update its length */
|
||||
+static zend_bool php_stream_http_response_header_trim(char *http_header_line,
|
||||
+ size_t *http_header_line_length)
|
||||
+{
|
||||
+ char *http_header_line_end = http_header_line + *http_header_line_length - 1;
|
||||
+ while (http_header_line_end >= http_header_line &&
|
||||
+ (*http_header_line_end == '\n' || *http_header_line_end == '\r')) {
|
||||
+ http_header_line_end--;
|
||||
+ }
|
||||
+
|
||||
+ /* The primary definition of an HTTP header in RFC 7230 states:
|
||||
+ * > Each header field consists of a case-insensitive field name followed
|
||||
+ * > by a colon (":"), optional leading whitespace, the field value, and
|
||||
+ * > optional trailing whitespace. */
|
||||
+
|
||||
+ /* Strip trailing whitespace */
|
||||
+ zend_bool space_trim = (*http_header_line_end == ' ' || *http_header_line_end == '\t');
|
||||
+ if (space_trim) {
|
||||
+ do {
|
||||
+ http_header_line_end--;
|
||||
+ } while (http_header_line_end >= http_header_line &&
|
||||
+ (*http_header_line_end == ' ' || *http_header_line_end == '\t'));
|
||||
+ }
|
||||
+ http_header_line_end++;
|
||||
+ *http_header_line_end = '\0';
|
||||
+ *http_header_line_length = http_header_line_end - http_header_line;
|
||||
+
|
||||
+ return space_trim;
|
||||
+}
|
||||
+
|
||||
+/* Process folding headers of the current line and if there are none, parse last full response
|
||||
+ * header line. It returns NULL if the last header is finished, otherwise it returns updated
|
||||
+ * last header line. */
|
||||
+static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
|
||||
+ php_stream_context *context, int options, zend_string *last_header_line_str,
|
||||
+ char *header_line, size_t *header_line_length, int response_code,
|
||||
+ zval *response_header, php_stream_http_response_header_info *header_info)
|
||||
+{
|
||||
+ char *last_header_line = ZSTR_VAL(last_header_line_str);
|
||||
+ size_t last_header_line_length = ZSTR_LEN(last_header_line_str);
|
||||
+ char *last_header_line_end = ZSTR_VAL(last_header_line_str) + ZSTR_LEN(last_header_line_str) - 1;
|
||||
+
|
||||
+ /* Process non empty header line. */
|
||||
+ if (header_line && (*header_line != '\n' && *header_line != '\r')) {
|
||||
+ /* Removing trailing white spaces. */
|
||||
+ if (php_stream_http_response_header_trim(header_line, header_line_length) &&
|
||||
+ *header_line_length == 0) {
|
||||
+ /* Only spaces so treat as an empty folding header. */
|
||||
+ return last_header_line_str;
|
||||
+ }
|
||||
+
|
||||
+ /* Process folding headers if starting with a space or a tab. */
|
||||
+ if (header_line && (*header_line == ' ' || *header_line == '\t')) {
|
||||
+ char *http_folded_header_line = header_line;
|
||||
+ size_t http_folded_header_line_length = *header_line_length;
|
||||
+ /* Remove the leading white spaces. */
|
||||
+ while (*http_folded_header_line == ' ' || *http_folded_header_line == '\t') {
|
||||
+ http_folded_header_line++;
|
||||
+ http_folded_header_line_length--;
|
||||
+ }
|
||||
+ /* It has to have some characters because it would get returned after the call
|
||||
+ * php_stream_http_response_header_trim above. */
|
||||
+ ZEND_ASSERT(http_folded_header_line_length > 0);
|
||||
+ /* Concatenate last header line, space and current header line. */
|
||||
+ zend_string *extended_header_str = zend_string_alloc(last_header_line_length + 1 + http_folded_header_line_length, 0);
|
||||
+ memcpy(ZSTR_VAL(extended_header_str), last_header_line, last_header_line_length);
|
||||
+ ZSTR_VAL(extended_header_str)[last_header_line_length] = ' ';
|
||||
+ memcpy(ZSTR_VAL(extended_header_str) + last_header_line_length + 1, http_folded_header_line, http_folded_header_line_length);
|
||||
+ ZSTR_VAL(extended_header_str)[ZSTR_LEN(extended_header_str)] = 0;
|
||||
+ zend_string_efree(last_header_line_str);
|
||||
+ last_header_line_str = extended_header_str;
|
||||
+ /* Return new header line. */
|
||||
+ return last_header_line_str;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Find header separator position. */
|
||||
+ char *last_header_value = memchr(last_header_line, ':', last_header_line_length);
|
||||
+ if (last_header_value) {
|
||||
+ last_header_value++; /* Skip ':'. */
|
||||
+
|
||||
+ /* Strip leading whitespace. */
|
||||
+ while (last_header_value < last_header_line_end
|
||||
+ && (*last_header_value == ' ' || *last_header_value == '\t')) {
|
||||
+ last_header_value++;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* There is no colon. Set the value to the end of the header line, which is effectively
|
||||
+ * an empty string. */
|
||||
+ last_header_value = last_header_line_end;
|
||||
+ }
|
||||
+
|
||||
+ zend_bool store_header = 1;
|
||||
+ zval *tmpzval = NULL;
|
||||
+
|
||||
+ if (!strncasecmp(last_header_line, "Location:", sizeof("Location:")-1)) {
|
||||
+ /* Check if the location should be followed. */
|
||||
+ if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) {
|
||||
+ header_info->follow_location = zval_is_true(tmpzval);
|
||||
+ } else if (!((response_code >= 300 && response_code < 304)
|
||||
+ || 307 == response_code || 308 == response_code)) {
|
||||
+ /* The redirection should not be automatic if follow_location is not set and
|
||||
+ * response_code not in (300, 301, 302, 303 and 307)
|
||||
+ * see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1
|
||||
+ * RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
|
||||
+ header_info->follow_location = 0;
|
||||
+ }
|
||||
+ strlcpy(header_info->location, last_header_value, sizeof(header_info->location));
|
||||
+ } else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) {
|
||||
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0);
|
||||
+ } else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) {
|
||||
+ header_info->file_size = atoi(last_header_value);
|
||||
+ php_stream_notify_file_size(context, header_info->file_size, last_header_line, 0);
|
||||
+ } else if (
|
||||
+ !strncasecmp(last_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1)
|
||||
+ && !strncasecmp(last_header_value, "Chunked", sizeof("Chunked")-1)
|
||||
+ ) {
|
||||
+ /* Create filter to decode response body. */
|
||||
+ if (!(options & STREAM_ONLY_GET_HEADERS)) {
|
||||
+ zend_long decode = 1;
|
||||
+
|
||||
+ if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) {
|
||||
+ decode = zend_is_true(tmpzval);
|
||||
+ }
|
||||
+ if (decode) {
|
||||
+ if (header_info->transfer_encoding != NULL) {
|
||||
+ /* Prevent a memory leak in case there are more transfer-encoding headers. */
|
||||
+ php_stream_filter_free(header_info->transfer_encoding);
|
||||
+ }
|
||||
+ header_info->transfer_encoding = php_stream_filter_create(
|
||||
+ "dechunk", NULL, php_stream_is_persistent(stream));
|
||||
+ if (header_info->transfer_encoding != NULL) {
|
||||
+ /* Do not store transfer-encoding header. */
|
||||
+ store_header = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (store_header) {
|
||||
+ zval http_header;
|
||||
+ ZVAL_NEW_STR(&http_header, last_header_line_str);
|
||||
+ zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header);
|
||||
+ } else {
|
||||
+ zend_string_efree(last_header_line_str);
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
|
||||
const char *path, const char *mode, int options, zend_string **opened_path,
|
||||
php_stream_context *context, int redirect_max, int flags,
|
||||
@@ -128,11 +294,12 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
|
||||
zend_string *tmp = NULL;
|
||||
char *ua_str = NULL;
|
||||
zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name;
|
||||
- char location[HTTP_HEADER_BLOCK_SIZE];
|
||||
int reqok = 0;
|
||||
char *http_header_line = NULL;
|
||||
+ zend_string *last_header_line_str = NULL;
|
||||
+ php_stream_http_response_header_info header_info;
|
||||
char tmp_line[128];
|
||||
- size_t chunk_size = 0, file_size = 0;
|
||||
+ size_t chunk_size = 0;
|
||||
int eol_detect = 0;
|
||||
char *transport_string;
|
||||
zend_string *errstr = NULL;
|
||||
@@ -143,8 +310,6 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
|
||||
char *user_headers = NULL;
|
||||
int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0);
|
||||
int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0);
|
||||
- zend_bool follow_location = 1;
|
||||
- php_stream_filter *transfer_encoding = NULL;
|
||||
int response_code;
|
||||
smart_str req_buf = {0};
|
||||
zend_bool custom_request_method;
|
||||
@@ -657,8 +822,6 @@ finish:
|
||||
/* send it */
|
||||
php_stream_write(stream, ZSTR_VAL(req_buf.s), ZSTR_LEN(req_buf.s));
|
||||
|
||||
- location[0] = '\0';
|
||||
-
|
||||
if (Z_ISUNDEF_P(response_header)) {
|
||||
array_init(response_header);
|
||||
}
|
||||
@@ -736,125 +899,101 @@ finish:
|
||||
}
|
||||
}
|
||||
|
||||
- /* read past HTTP headers */
|
||||
+ php_stream_http_response_header_info_init(&header_info);
|
||||
|
||||
+ /* read past HTTP headers */
|
||||
while (!php_stream_eof(stream)) {
|
||||
size_t http_header_line_length;
|
||||
|
||||
if (http_header_line != NULL) {
|
||||
efree(http_header_line);
|
||||
}
|
||||
- if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length)) && *http_header_line != '\n' && *http_header_line != '\r') {
|
||||
- char *e = http_header_line + http_header_line_length - 1;
|
||||
- char *http_header_value;
|
||||
-
|
||||
- while (e >= http_header_line && (*e == '\n' || *e == '\r')) {
|
||||
- e--;
|
||||
- }
|
||||
-
|
||||
- /* The primary definition of an HTTP header in RFC 7230 states:
|
||||
- * > Each header field consists of a case-insensitive field name followed
|
||||
- * > by a colon (":"), optional leading whitespace, the field value, and
|
||||
- * > optional trailing whitespace. */
|
||||
-
|
||||
- /* Strip trailing whitespace */
|
||||
- while (e >= http_header_line && (*e == ' ' || *e == '\t')) {
|
||||
- e--;
|
||||
- }
|
||||
-
|
||||
- /* Terminate header line */
|
||||
- e++;
|
||||
- *e = '\0';
|
||||
- http_header_line_length = e - http_header_line;
|
||||
-
|
||||
- http_header_value = memchr(http_header_line, ':', http_header_line_length);
|
||||
- if (http_header_value) {
|
||||
- http_header_value++; /* Skip ':' */
|
||||
-
|
||||
- /* Strip leading whitespace */
|
||||
- while (http_header_value < e
|
||||
- && (*http_header_value == ' ' || *http_header_value == '\t')) {
|
||||
- http_header_value++;
|
||||
+ if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length))) {
|
||||
+ zend_bool last_line;
|
||||
+ if (*http_header_line == '\r') {
|
||||
+ if (http_header_line[1] != '\n') {
|
||||
+ php_stream_close(stream);
|
||||
+ stream = NULL;
|
||||
+ php_stream_wrapper_log_error(wrapper, options,
|
||||
+ "HTTP invalid header name (cannot start with CR character)!");
|
||||
+ goto out;
|
||||
}
|
||||
+ last_line = 1;
|
||||
+ } else if (*http_header_line == '\n') {
|
||||
+ last_line = 1;
|
||||
} else {
|
||||
- /* There is no colon. Set the value to the end of the header line, which is
|
||||
- * effectively an empty string. */
|
||||
- http_header_value = e;
|
||||
+ last_line = 0;
|
||||
}
|
||||
-
|
||||
- if (!strncasecmp(http_header_line, "Location:", sizeof("Location:")-1)) {
|
||||
- if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) {
|
||||
- follow_location = zval_is_true(tmpzval);
|
||||
- } else if (!((response_code >= 300 && response_code < 304)
|
||||
- || 307 == response_code || 308 == response_code)) {
|
||||
- /* we shouldn't redirect automatically
|
||||
- if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307)
|
||||
- see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1
|
||||
- RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
|
||||
- follow_location = 0;
|
||||
+
|
||||
+ if (last_header_line_str != NULL) {
|
||||
+ /* Parse last header line. */
|
||||
+ last_header_line_str = php_stream_http_response_headers_parse(stream, context,
|
||||
+ options, last_header_line_str, http_header_line, &http_header_line_length,
|
||||
+ response_code, response_header, &header_info);
|
||||
+ if (last_header_line_str != NULL) {
|
||||
+ /* Folding header present so continue. */
|
||||
+ continue;
|
||||
}
|
||||
- strlcpy(location, http_header_value, sizeof(location));
|
||||
- } else if (!strncasecmp(http_header_line, "Content-Type:", sizeof("Content-Type:")-1)) {
|
||||
- php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_value, 0);
|
||||
- } else if (!strncasecmp(http_header_line, "Content-Length:", sizeof("Content-Length:")-1)) {
|
||||
- file_size = atoi(http_header_value);
|
||||
- php_stream_notify_file_size(context, file_size, http_header_line, 0);
|
||||
- } else if (
|
||||
- !strncasecmp(http_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1)
|
||||
- && !strncasecmp(http_header_value, "Chunked", sizeof("Chunked")-1)
|
||||
- ) {
|
||||
-
|
||||
- /* create filter to decode response body */
|
||||
- if (!(options & STREAM_ONLY_GET_HEADERS)) {
|
||||
- zend_long decode = 1;
|
||||
-
|
||||
- if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) {
|
||||
- decode = zend_is_true(tmpzval);
|
||||
- }
|
||||
- if (decode) {
|
||||
- transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream));
|
||||
- if (transfer_encoding) {
|
||||
- /* don't store transfer-encodeing header */
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
+ } else if (!last_line) {
|
||||
+ /* The first line cannot start with spaces. */
|
||||
+ if (*http_header_line == ' ' || *http_header_line == '\t') {
|
||||
+ php_stream_close(stream);
|
||||
+ stream = NULL;
|
||||
+ php_stream_wrapper_log_error(wrapper, options,
|
||||
+ "HTTP invalid response format (folding header at the start)!");
|
||||
+ goto out;
|
||||
}
|
||||
+ /* Trim the first line if it is not the last line. */
|
||||
+ php_stream_http_response_header_trim(http_header_line, &http_header_line_length);
|
||||
}
|
||||
-
|
||||
- {
|
||||
- zval http_header;
|
||||
- ZVAL_STRINGL(&http_header, http_header_line, http_header_line_length);
|
||||
- zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header);
|
||||
+ if (last_line) {
|
||||
+ /* For the last line the last header line must be NULL. */
|
||||
+ ZEND_ASSERT(last_header_line_str == NULL);
|
||||
+ break;
|
||||
}
|
||||
+ /* Save current line as the last line so it gets parsed in the next round. */
|
||||
+ last_header_line_str = zend_string_init(http_header_line, http_header_line_length, 0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- if (!reqok || (location[0] != '\0' && follow_location)) {
|
||||
- if (!follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
|
||||
+ /* If the stream was closed early, we still want to process the last line to keep BC. */
|
||||
+ if (last_header_line_str != NULL) {
|
||||
+ php_stream_http_response_headers_parse(stream, context, options, last_header_line_str,
|
||||
+ NULL, NULL, response_code, response_header, &header_info);
|
||||
+ }
|
||||
+
|
||||
+ if (!reqok || (header_info.location[0] != '\0' && header_info.follow_location)) {
|
||||
+ if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (location[0] != '\0')
|
||||
- php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);
|
||||
+ if (header_info.location[0] != '\0')
|
||||
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0);
|
||||
|
||||
php_stream_close(stream);
|
||||
stream = NULL;
|
||||
|
||||
- if (location[0] != '\0') {
|
||||
+ if (header_info.transfer_encoding) {
|
||||
+ php_stream_filter_free(header_info.transfer_encoding);
|
||||
+ header_info.transfer_encoding = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (header_info.location[0] != '\0') {
|
||||
|
||||
char new_path[HTTP_HEADER_BLOCK_SIZE];
|
||||
char loc_path[HTTP_HEADER_BLOCK_SIZE];
|
||||
|
||||
*new_path='\0';
|
||||
- if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) &&
|
||||
- strncasecmp(location, "https://", sizeof("https://")-1) &&
|
||||
- strncasecmp(location, "ftp://", sizeof("ftp://")-1) &&
|
||||
- strncasecmp(location, "ftps://", sizeof("ftps://")-1)))
|
||||
+ if (strlen(header_info.location) < 8 ||
|
||||
+ (strncasecmp(header_info.location, "http://", sizeof("http://")-1) &&
|
||||
+ strncasecmp(header_info.location, "https://", sizeof("https://")-1) &&
|
||||
+ strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) &&
|
||||
+ strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1)))
|
||||
{
|
||||
- if (*location != '/') {
|
||||
- if (*(location+1) != '\0' && resource->path) {
|
||||
+ if (*header_info.location != '/') {
|
||||
+ if (*(header_info.location+1) != '\0' && resource->path) {
|
||||
char *s = strrchr(ZSTR_VAL(resource->path), '/');
|
||||
if (!s) {
|
||||
s = ZSTR_VAL(resource->path);
|
||||
@@ -870,15 +1009,17 @@ finish:
|
||||
if (resource->path &&
|
||||
ZSTR_VAL(resource->path)[0] == '/' &&
|
||||
ZSTR_VAL(resource->path)[1] == '\0') {
|
||||
- snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", ZSTR_VAL(resource->path), location);
|
||||
+ snprintf(loc_path, sizeof(loc_path) - 1, "%s%s",
|
||||
+ ZSTR_VAL(resource->path), header_info.location);
|
||||
} else {
|
||||
- snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", ZSTR_VAL(resource->path), location);
|
||||
+ snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s",
|
||||
+ ZSTR_VAL(resource->path), header_info.location);
|
||||
}
|
||||
} else {
|
||||
- snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
|
||||
+ snprintf(loc_path, sizeof(loc_path) - 1, "/%s", header_info.location);
|
||||
}
|
||||
} else {
|
||||
- strlcpy(loc_path, location, sizeof(loc_path));
|
||||
+ strlcpy(loc_path, header_info.location, sizeof(loc_path));
|
||||
}
|
||||
if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
|
||||
snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path);
|
||||
@@ -886,7 +1027,7 @@ finish:
|
||||
snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path);
|
||||
}
|
||||
} else {
|
||||
- strlcpy(new_path, location, sizeof(new_path));
|
||||
+ strlcpy(new_path, header_info.location, sizeof(new_path));
|
||||
}
|
||||
|
||||
php_url_free(resource);
|
||||
@@ -939,7 +1080,7 @@ out:
|
||||
if (header_init) {
|
||||
ZVAL_COPY(&stream->wrapperdata, response_header);
|
||||
}
|
||||
- php_stream_notify_progress_init(context, 0, file_size);
|
||||
+ php_stream_notify_progress_init(context, 0, header_info.file_size);
|
||||
|
||||
/* Restore original chunk size now that we're done with headers */
|
||||
if (options & STREAM_WILL_CAST)
|
||||
@@ -955,12 +1096,8 @@ out:
|
||||
/* restore mode */
|
||||
strlcpy(stream->mode, mode, sizeof(stream->mode));
|
||||
|
||||
- if (transfer_encoding) {
|
||||
- php_stream_filter_append(&stream->readfilters, transfer_encoding);
|
||||
- }
|
||||
- } else {
|
||||
- if (transfer_encoding) {
|
||||
- php_stream_filter_free(transfer_encoding);
|
||||
+ if (header_info.transfer_encoding) {
|
||||
+ php_stream_filter_append(&stream->readfilters, header_info.transfer_encoding);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..64904bfcd1d
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
|
||||
@@ -0,0 +1,49 @@
|
||||
+--TEST--
|
||||
+GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (single)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\n charset=utf-8\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html; charset=utf-8
|
||||
+string(4) "body"
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(38) "Content-Type: text/html; charset=utf-8"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..a6d9d00fd58
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
|
||||
@@ -0,0 +1,51 @@
|
||||
+--TEST--
|
||||
+GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (multiple)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\nCustom-Header: somevalue;\r\n param1=value1; \r\n param2=value2\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html;
|
||||
+string(4) "body"
|
||||
+array(3) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(24) "Content-Type: text/html;"
|
||||
+ [2]=>
|
||||
+ string(54) "Custom-Header: somevalue; param1=value1; param2=value2"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..4eff7fc63f3
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
|
||||
@@ -0,0 +1,49 @@
|
||||
+--TEST--
|
||||
+GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (empty)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\n \r\n charset=utf-8\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html; charset=utf-8
|
||||
+string(4) "body"
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(38) "Content-Type: text/html; charset=utf-8"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..71aed2fa2e8
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
|
||||
@@ -0,0 +1,48 @@
|
||||
+--TEST--
|
||||
+GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (first line)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\n Content-Type: text/html;\r\n \r\n charset=utf-8\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+
|
||||
+Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid response format (folding header at the start)! in %s
|
||||
+bool(false)
|
||||
+array(1) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..49d845d84b4
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
|
||||
@@ -0,0 +1,48 @@
|
||||
+--TEST--
|
||||
+GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (CR before header name)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\n\rIgnored: ignored\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+
|
||||
+Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid header name (cannot start with CR character)! in %s
|
||||
+bool(false)
|
||||
+array(1) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/http_response_header_05.phpt b/ext/standard/tests/http/http_response_header_05.phpt
|
||||
deleted file mode 100644
|
||||
index dbdd7b8b1a0..00000000000
|
||||
--- a/ext/standard/tests/http/http_response_header_05.phpt
|
||||
+++ /dev/null
|
||||
@@ -1,35 +0,0 @@
|
||||
---TEST--
|
||||
-$http_reponse_header (whitespace-only "header")
|
||||
---SKIPIF--
|
||||
-<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:22350'); ?>
|
||||
---INI--
|
||||
-allow_url_fopen=1
|
||||
---FILE--
|
||||
-<?php
|
||||
-require 'server.inc';
|
||||
-
|
||||
-$responses = array(
|
||||
- "data://text/plain,HTTP/1.0 200 Ok\r\n \r\n\r\nBody",
|
||||
-);
|
||||
-
|
||||
-$pid = http_server("tcp://127.0.0.1:22350", $responses, $output);
|
||||
-
|
||||
-function test() {
|
||||
- $f = file_get_contents('http://127.0.0.1:22350/');
|
||||
- var_dump($f);
|
||||
- var_dump($http_response_header);
|
||||
-}
|
||||
-test();
|
||||
-
|
||||
-http_server_kill($pid);
|
||||
-?>
|
||||
-==DONE==
|
||||
---EXPECT--
|
||||
-string(4) "Body"
|
||||
-array(2) {
|
||||
- [0]=>
|
||||
- string(15) "HTTP/1.0 200 Ok"
|
||||
- [1]=>
|
||||
- string(0) ""
|
||||
-}
|
||||
-==DONE==
|
||||
--
|
||||
2.48.1
|
||||
|
||||
1906
SOURCES/php-cve-2025-1219.patch
Normal file
1906
SOURCES/php-cve-2025-1219.patch
Normal file
File diff suppressed because it is too large
Load Diff
154
SOURCES/php-cve-2025-1220.patch
Normal file
154
SOURCES/php-cve-2025-1220.patch
Normal file
@ -0,0 +1,154 @@
|
||||
From d407d8a8735ebf43bee3e6b49fb013b8aa4b6bfc Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Thu, 10 Apr 2025 15:15:36 +0200
|
||||
Subject: [PATCH 2/4] Fix GHSA-3cr5-j632-f35r: Null byte in hostnames
|
||||
|
||||
This fixes stream_socket_client() and fsockopen().
|
||||
|
||||
Specifically it adds a check to parse_ip_address_ex and it also makes
|
||||
sure that the \0 is not ignored in fsockopen() hostname formatting.
|
||||
|
||||
(cherry picked from commit cac8f7f1cf4939f55f06b68120040f057682d89c)
|
||||
(cherry picked from commit 36150278addd8686a9899559241296094bd57282)
|
||||
---
|
||||
ext/standard/fsock.c | 27 +++++++++++++++++--
|
||||
.../tests/network/ghsa-3cr5-j632-f35r.phpt | 21 +++++++++++++++
|
||||
.../tests/streams/ghsa-3cr5-j632-f35r.phpt | 26 ++++++++++++++++++
|
||||
main/streams/xp_socket.c | 9 ++++---
|
||||
4 files changed, 78 insertions(+), 5 deletions(-)
|
||||
create mode 100644 ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
|
||||
create mode 100644 ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
|
||||
|
||||
diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c
|
||||
index fe8fbea85ca..df6a74b078f 100644
|
||||
--- a/ext/standard/fsock.c
|
||||
+++ b/ext/standard/fsock.c
|
||||
@@ -25,6 +25,28 @@
|
||||
#include "php_network.h"
|
||||
#include "file.h"
|
||||
|
||||
+static size_t php_fsockopen_format_host_port(char **message, const char *prefix, size_t prefix_len,
|
||||
+ const char *host, size_t host_len, zend_long port)
|
||||
+{
|
||||
+ char portbuf[32];
|
||||
+ int portlen = snprintf(portbuf, sizeof(portbuf), ":" ZEND_LONG_FMT, port);
|
||||
+ size_t total_len = prefix_len + host_len + portlen;
|
||||
+
|
||||
+ char *result = emalloc(total_len + 1);
|
||||
+
|
||||
+ if (prefix_len > 0) {
|
||||
+ memcpy(result, prefix, prefix_len);
|
||||
+ }
|
||||
+ memcpy(result + prefix_len, host, host_len);
|
||||
+ memcpy(result + prefix_len + host_len, portbuf, portlen);
|
||||
+
|
||||
+ result[total_len] = '\0';
|
||||
+
|
||||
+ *message = result;
|
||||
+
|
||||
+ return total_len;
|
||||
+}
|
||||
+
|
||||
/* {{{ php_fsockopen() */
|
||||
|
||||
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
||||
@@ -59,11 +81,12 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
||||
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
|
||||
|
||||
if (persistent) {
|
||||
- spprintf(&hashkey, 0, "pfsockopen__%s:" ZEND_LONG_FMT, host, port);
|
||||
+ php_fsockopen_format_host_port(&hashkey, "pfsockopen__", strlen("pfsockopen__"), host,
|
||||
+ host_len, port);
|
||||
}
|
||||
|
||||
if (port > 0) {
|
||||
- hostname_len = spprintf(&hostname, 0, "%s:" ZEND_LONG_FMT, host, port);
|
||||
+ hostname_len = php_fsockopen_format_host_port(&hostname, "", 0, host, host_len, port);
|
||||
} else {
|
||||
hostname_len = host_len;
|
||||
hostname = host;
|
||||
diff --git a/ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt b/ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..e16d3fa9060
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
|
||||
@@ -0,0 +1,21 @@
|
||||
+--TEST--
|
||||
+GHSA-3cr5-j632-f35r: Null byte termination in fsockopen()
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+$server = stream_socket_server("tcp://localhost:0");
|
||||
+
|
||||
+if (preg_match('/:(\d+)$/', stream_socket_get_name($server, false), $m)) {
|
||||
+ $client = fsockopen("localhost\0.example.com", intval($m[1]));
|
||||
+ var_dump($client);
|
||||
+ if ($client) {
|
||||
+ fclose($client);
|
||||
+ }
|
||||
+}
|
||||
+fclose($server);
|
||||
+
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+
|
||||
+Warning: fsockopen(): unable to connect to localhost:%d (The hostname must not contain null bytes) in %s
|
||||
+bool(false)
|
||||
diff --git a/ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt b/ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..bc1f34eaf58
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
|
||||
@@ -0,0 +1,26 @@
|
||||
+--TEST--
|
||||
+GHSA-3cr5-j632-f35r: Null byte termination in stream_socket_client()
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+$server = stream_socket_server("tcp://localhost:0");
|
||||
+$socket_name = stream_socket_get_name($server, false);
|
||||
+
|
||||
+if (preg_match('/:(\d+)$/', $socket_name, $m)) {
|
||||
+ $port = $m[1];
|
||||
+ $client = stream_socket_client("tcp://localhost\0.example.com:$port");
|
||||
+ var_dump($client);
|
||||
+ if ($client) {
|
||||
+ fclose($client);
|
||||
+ }
|
||||
+} else {
|
||||
+ echo "Could not extract port from socket name: $socket_name\n";
|
||||
+}
|
||||
+
|
||||
+fclose($server);
|
||||
+
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+
|
||||
+Warning: stream_socket_client(): unable to connect to tcp://localhost\0.example.com:%d (The hostname must not contain null bytes) in %s
|
||||
+bool(false)
|
||||
diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c
|
||||
index 46b23b63ada..7a192ea6c0b 100644
|
||||
--- a/main/streams/xp_socket.c
|
||||
+++ b/main/streams/xp_socket.c
|
||||
@@ -580,12 +580,15 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *po
|
||||
char *colon;
|
||||
char *host = NULL;
|
||||
|
||||
-#ifdef HAVE_IPV6
|
||||
- char *p;
|
||||
+ if (memchr(str, '\0', str_len)) {
|
||||
+ *err = strpprintf(0, "The hostname must not contain null bytes");
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
+#ifdef HAVE_IPV6
|
||||
if (*(str) == '[' && str_len > 1) {
|
||||
/* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
|
||||
- p = memchr(str + 1, ']', str_len - 2);
|
||||
+ char *p = memchr(str + 1, ']', str_len - 2);
|
||||
if (!p || *(p + 1) != ':') {
|
||||
if (get_err) {
|
||||
*err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
|
||||
--
|
||||
2.50.0
|
||||
|
||||
107
SOURCES/php-cve-2025-14177.patch
Normal file
107
SOURCES/php-cve-2025-14177.patch
Normal file
@ -0,0 +1,107 @@
|
||||
From 6cf0fb3c48fda6a236359304e4db663ae77d858c Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+ndossche@users.noreply.github.com>
|
||||
Date: Tue, 25 Nov 2025 23:11:38 +0100
|
||||
Subject: [PATCH 1/5] Fix GH-20584: Information Leak of Memory
|
||||
|
||||
The string added had uninitialized memory due to
|
||||
php_read_stream_all_chunks() not moving the buffer position, resulting
|
||||
in the same data always being overwritten instead of new data being
|
||||
added to the end of the buffer.
|
||||
|
||||
This is backport as there is a security impact as described in
|
||||
GHSA-3237-qqm7-mfv7 .
|
||||
|
||||
(cherry picked from commit c5f28c7cf0a052f48e47877c7aa5c5bcc54f1cfc)
|
||||
(cherry picked from commit ed665eb1903737d2b52b27368b155f6208604ed9)
|
||||
---
|
||||
ext/standard/image.c | 20 +++++++++++---
|
||||
ext/standard/tests/image/gh20584.phpt | 39 +++++++++++++++++++++++++++
|
||||
2 files changed, 56 insertions(+), 3 deletions(-)
|
||||
create mode 100644 ext/standard/tests/image/gh20584.phpt
|
||||
|
||||
diff --git a/ext/standard/image.c b/ext/standard/image.c
|
||||
index 4f2c5a505b4..800c5de8da3 100644
|
||||
--- a/ext/standard/image.c
|
||||
+++ b/ext/standard/image.c
|
||||
@@ -434,8 +434,22 @@ static int php_skip_variable(php_stream * stream)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
-/* {{{ php_read_APP
|
||||
- */
|
||||
+static size_t php_read_stream_all_chunks(php_stream *stream, char *buffer, size_t length)
|
||||
+{
|
||||
+ size_t read_total = 0;
|
||||
+ do {
|
||||
+ ssize_t read_now = php_stream_read(stream, buffer, length - read_total);
|
||||
+ read_total += read_now;
|
||||
+ if (read_now < stream->chunk_size && read_total != length) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ buffer += read_now;
|
||||
+ } while (read_total < length);
|
||||
+
|
||||
+ return read_total;
|
||||
+}
|
||||
+
|
||||
+/* {{{ php_read_APP */
|
||||
static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
|
||||
{
|
||||
unsigned short length;
|
||||
@@ -451,7 +465,7 @@ static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
|
||||
|
||||
buffer = emalloc((size_t)length);
|
||||
|
||||
- if (php_stream_read(stream, buffer, (size_t) length) != length) {
|
||||
+ if (php_read_stream_all_chunks(stream, buffer, length) != length) {
|
||||
efree(buffer);
|
||||
return 0;
|
||||
}
|
||||
diff --git a/ext/standard/tests/image/gh20584.phpt b/ext/standard/tests/image/gh20584.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..d117f218202
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/image/gh20584.phpt
|
||||
@@ -0,0 +1,39 @@
|
||||
+--TEST--
|
||||
+GH-20584 (Information Leak of Memory)
|
||||
+--CREDITS--
|
||||
+Nikita Sveshnikov (Positive Technologies)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+// Minimal PoC: corruption/uninitialized memory leak when reading APP1 via php://filter
|
||||
+$file = __DIR__ . '/gh20584.jpg';
|
||||
+
|
||||
+// Make APP1 large enough so it is read in multiple chunks
|
||||
+$chunk = 8192;
|
||||
+$tail = 123;
|
||||
+$payload = str_repeat('A', $chunk) . str_repeat('B', $chunk) . str_repeat('Z',
|
||||
+$tail);
|
||||
+$app1Len = 2 + strlen($payload);
|
||||
+
|
||||
+// Minimal JPEG: SOI + APP1 + SOF0(1x1) + EOI
|
||||
+$sof = "\xFF\xC0" . pack('n', 11) . "\x08" . pack('n',1) . pack('n',1) .
|
||||
+"\x01\x11\x00";
|
||||
+$jpeg = "\xFF\xD8" . "\xFF\xE1" . pack('n', $app1Len) . $payload . $sof .
|
||||
+"\xFF\xD9";
|
||||
+file_put_contents($file, $jpeg);
|
||||
+
|
||||
+// Read through a filter to enforce multiple reads
|
||||
+$src = 'php://filter/read=string.rot13|string.rot13/resource=' . $file;
|
||||
+$info = null;
|
||||
+@getimagesize($src, $info);
|
||||
+$exp = $payload;
|
||||
+$ret = $info['APP1'];
|
||||
+
|
||||
+var_dump($ret === $exp);
|
||||
+
|
||||
+?>
|
||||
+--CLEAN--
|
||||
+<?php
|
||||
+@unlink(__DIR__ . '/gh20584.jpg');
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+bool(true)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
63
SOURCES/php-cve-2025-14178.patch
Normal file
63
SOURCES/php-cve-2025-14178.patch
Normal file
@ -0,0 +1,63 @@
|
||||
From 84b83e2979bad57618528d4e669636117022f37c Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+ndossche@users.noreply.github.com>
|
||||
Date: Sun, 9 Nov 2025 13:23:11 +0100
|
||||
Subject: [PATCH 3/5] Fix GHSA-h96m-rvf9-jgm2
|
||||
|
||||
(cherry picked from commit 8b801151bd54b36aae4593ed6cfc096e8122b415)
|
||||
(cherry picked from commit e4516e52979e8b67d9d35dfdbcc5dc7368263fa2)
|
||||
---
|
||||
ext/standard/array.c | 7 ++++++-
|
||||
.../tests/array/GHSA-h96m-rvf9-jgm2.phpt | 16 ++++++++++++++++
|
||||
2 files changed, 22 insertions(+), 1 deletion(-)
|
||||
create mode 100644 ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt
|
||||
|
||||
diff --git a/ext/standard/array.c b/ext/standard/array.c
|
||||
index cd2e5287daf..153a4d39d15 100644
|
||||
--- a/ext/standard/array.c
|
||||
+++ b/ext/standard/array.c
|
||||
@@ -3813,7 +3813,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
|
||||
int argc, i;
|
||||
zval *src_entry;
|
||||
HashTable *src, *dest;
|
||||
- uint32_t count = 0;
|
||||
+ uint64_t count = 0;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(0, -1)
|
||||
Z_PARAM_VARIADIC('+', args, argc)
|
||||
@@ -3833,6 +3833,11 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
|
||||
count += zend_hash_num_elements(Z_ARRVAL_P(arg));
|
||||
}
|
||||
|
||||
+ if (UNEXPECTED(count >= HT_MAX_SIZE)) {
|
||||
+ zend_throw_error(NULL, "The total number of elements must be lower than %u", HT_MAX_SIZE);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (argc == 2) {
|
||||
zval *ret = NULL;
|
||||
|
||||
diff --git a/ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt b/ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..2e3e85357e1
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt
|
||||
@@ -0,0 +1,16 @@
|
||||
+--TEST--
|
||||
+GHSA-h96m-rvf9-jgm2
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+$power = 20; // Chosen to be well within a memory_limit
|
||||
+$arr = range(0, 2**$power);
|
||||
+try {
|
||||
+ array_merge(...array_fill(0, 2**(32-$power), $arr));
|
||||
+} catch (Error $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+The total number of elements must be lower than %d
|
||||
--
|
||||
2.52.0
|
||||
|
||||
314
SOURCES/php-cve-2025-1734.patch
Normal file
314
SOURCES/php-cve-2025-1734.patch
Normal file
@ -0,0 +1,314 @@
|
||||
From 0b965cf85f512b1a7b87f100ac77e4aa13f7f421 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Sun, 19 Jan 2025 17:49:53 +0100
|
||||
Subject: [PATCH 02/11] Fix GHSA-pcmh-g36c-qc44: http headers without colon
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The header line must contain colon otherwise it is invalid and it needs
|
||||
to fail.
|
||||
|
||||
Reviewed-by: Tim Düsterhus <tim@tideways-gmbh.com>
|
||||
(cherry picked from commit 0548c4c1756724a89ef8310709419b08aadb2b3b)
|
||||
(cherry picked from commit e81d0cd14bfeb17e899c73e3aece4991bbda76af)
|
||||
---
|
||||
ext/standard/http_fopen_wrapper.c | 51 ++++++++++++++-----
|
||||
ext/standard/tests/http/bug47021.phpt | 26 ++++++----
|
||||
ext/standard/tests/http/bug75535.phpt | 4 +-
|
||||
.../tests/http/ghsa-pcmh-g36c-qc44-001.phpt | 51 +++++++++++++++++++
|
||||
.../tests/http/ghsa-pcmh-g36c-qc44-002.phpt | 51 +++++++++++++++++++
|
||||
5 files changed, 156 insertions(+), 27 deletions(-)
|
||||
create mode 100644 ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
|
||||
|
||||
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
|
||||
index 08386cfafcd..071d6a4d119 100644
|
||||
--- a/ext/standard/http_fopen_wrapper.c
|
||||
+++ b/ext/standard/http_fopen_wrapper.c
|
||||
@@ -119,6 +119,7 @@ static zend_bool check_has_header(const char *headers, const char *header) {
|
||||
typedef struct _php_stream_http_response_header_info {
|
||||
php_stream_filter *transfer_encoding;
|
||||
size_t file_size;
|
||||
+ zend_bool error;
|
||||
zend_bool follow_location;
|
||||
char location[HTTP_HEADER_BLOCK_SIZE];
|
||||
} php_stream_http_response_header_info;
|
||||
@@ -128,6 +129,7 @@ static void php_stream_http_response_header_info_init(
|
||||
{
|
||||
header_info->transfer_encoding = NULL;
|
||||
header_info->file_size = 0;
|
||||
+ header_info->error = 0;
|
||||
header_info->follow_location = 1;
|
||||
header_info->location[0] = '\0';
|
||||
}
|
||||
@@ -165,10 +167,11 @@ static zend_bool php_stream_http_response_header_trim(char *http_header_line,
|
||||
/* Process folding headers of the current line and if there are none, parse last full response
|
||||
* header line. It returns NULL if the last header is finished, otherwise it returns updated
|
||||
* last header line. */
|
||||
-static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
|
||||
- php_stream_context *context, int options, zend_string *last_header_line_str,
|
||||
- char *header_line, size_t *header_line_length, int response_code,
|
||||
- zval *response_header, php_stream_http_response_header_info *header_info)
|
||||
+static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *wrapper,
|
||||
+ php_stream *stream, php_stream_context *context, int options,
|
||||
+ zend_string *last_header_line_str, char *header_line, size_t *header_line_length,
|
||||
+ int response_code, zval *response_header,
|
||||
+ php_stream_http_response_header_info *header_info)
|
||||
{
|
||||
char *last_header_line = ZSTR_VAL(last_header_line_str);
|
||||
size_t last_header_line_length = ZSTR_LEN(last_header_line_str);
|
||||
@@ -211,6 +214,19 @@ static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
|
||||
/* Find header separator position. */
|
||||
char *last_header_value = memchr(last_header_line, ':', last_header_line_length);
|
||||
if (last_header_value) {
|
||||
+ /* Verify there is no space in header name */
|
||||
+ char *last_header_name = last_header_line + 1;
|
||||
+ while (last_header_name < last_header_value) {
|
||||
+ if (*last_header_name == ' ' || *last_header_name == '\t') {
|
||||
+ header_info->error = 1;
|
||||
+ php_stream_wrapper_log_error(wrapper, options,
|
||||
+ "HTTP invalid response format (space in header name)!");
|
||||
+ zend_string_efree(last_header_line_str);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ ++last_header_name;
|
||||
+ }
|
||||
+
|
||||
last_header_value++; /* Skip ':'. */
|
||||
|
||||
/* Strip leading whitespace. */
|
||||
@@ -219,9 +235,12 @@ static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
|
||||
last_header_value++;
|
||||
}
|
||||
} else {
|
||||
- /* There is no colon. Set the value to the end of the header line, which is effectively
|
||||
- * an empty string. */
|
||||
- last_header_value = last_header_line_end;
|
||||
+ /* There is no colon which means invalid response so error. */
|
||||
+ header_info->error = 1;
|
||||
+ php_stream_wrapper_log_error(wrapper, options,
|
||||
+ "HTTP invalid response format (no colon in header line)!");
|
||||
+ zend_string_efree(last_header_line_str);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
zend_bool store_header = 1;
|
||||
@@ -927,10 +946,16 @@ finish:
|
||||
|
||||
if (last_header_line_str != NULL) {
|
||||
/* Parse last header line. */
|
||||
- last_header_line_str = php_stream_http_response_headers_parse(stream, context,
|
||||
- options, last_header_line_str, http_header_line, &http_header_line_length,
|
||||
- response_code, response_header, &header_info);
|
||||
- if (last_header_line_str != NULL) {
|
||||
+ last_header_line_str = php_stream_http_response_headers_parse(wrapper, stream,
|
||||
+ context, options, last_header_line_str, http_header_line,
|
||||
+ &http_header_line_length, response_code, response_header, &header_info);
|
||||
+ if (EXPECTED(last_header_line_str == NULL)) {
|
||||
+ if (UNEXPECTED(header_info.error)) {
|
||||
+ php_stream_close(stream);
|
||||
+ stream = NULL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ } else {
|
||||
/* Folding header present so continue. */
|
||||
continue;
|
||||
}
|
||||
@@ -960,8 +985,8 @@ finish:
|
||||
|
||||
/* If the stream was closed early, we still want to process the last line to keep BC. */
|
||||
if (last_header_line_str != NULL) {
|
||||
- php_stream_http_response_headers_parse(stream, context, options, last_header_line_str,
|
||||
- NULL, NULL, response_code, response_header, &header_info);
|
||||
+ php_stream_http_response_headers_parse(wrapper, stream, context, options,
|
||||
+ last_header_line_str, NULL, NULL, response_code, response_header, &header_info);
|
||||
}
|
||||
|
||||
if (!reqok || (header_info.location[0] != '\0' && header_info.follow_location)) {
|
||||
diff --git a/ext/standard/tests/http/bug47021.phpt b/ext/standard/tests/http/bug47021.phpt
|
||||
index f3db3e1be23..a287b714c62 100644
|
||||
--- a/ext/standard/tests/http/bug47021.phpt
|
||||
+++ b/ext/standard/tests/http/bug47021.phpt
|
||||
@@ -47,9 +47,9 @@ function do_test($num_spaces, $leave_trailing_space=false) {
|
||||
];
|
||||
$pid = http_server('tcp://127.0.0.1:12342', $responses);
|
||||
|
||||
- echo file_get_contents('http://127.0.0.1:12342/', false, $ctx);
|
||||
+ echo file_get_contents('http://127.0.0.1:12342', false, $ctx);
|
||||
echo "\n";
|
||||
- echo file_get_contents('http://127.0.0.1:12342/', false, $ctx);
|
||||
+ echo file_get_contents('http://127.0.0.1:12342', false, $ctx);
|
||||
echo "\n";
|
||||
|
||||
http_server_kill($pid);
|
||||
@@ -70,23 +70,27 @@ do_test(1, true);
|
||||
echo "\n";
|
||||
|
||||
?>
|
||||
---EXPECT--
|
||||
+--EXPECTF--
|
||||
+
|
||||
Type='text/plain'
|
||||
Hello
|
||||
-Size=5
|
||||
-World
|
||||
+
|
||||
+Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
|
||||
+
|
||||
|
||||
Type='text/plain'
|
||||
Hello
|
||||
-Size=5
|
||||
-World
|
||||
+
|
||||
+Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
|
||||
+
|
||||
|
||||
Type='text/plain'
|
||||
Hello
|
||||
-Size=5
|
||||
-World
|
||||
+
|
||||
+Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
|
||||
+
|
||||
|
||||
Type='text/plain'
|
||||
Hello
|
||||
-Size=5
|
||||
-World
|
||||
+
|
||||
+Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
|
||||
diff --git a/ext/standard/tests/http/bug75535.phpt b/ext/standard/tests/http/bug75535.phpt
|
||||
index 9bf298cc065..e3757ba4f1d 100644
|
||||
--- a/ext/standard/tests/http/bug75535.phpt
|
||||
+++ b/ext/standard/tests/http/bug75535.phpt
|
||||
@@ -22,10 +22,8 @@ http_server_kill($pid);
|
||||
==DONE==
|
||||
--EXPECT--
|
||||
string(0) ""
|
||||
-array(2) {
|
||||
+array(1) {
|
||||
[0]=>
|
||||
string(15) "HTTP/1.0 200 Ok"
|
||||
- [1]=>
|
||||
- string(14) "Content-Length"
|
||||
}
|
||||
==DONE==
|
||||
diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..53baa1c92d6
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
|
||||
@@ -0,0 +1,51 @@
|
||||
+--TEST--
|
||||
+GHSA-pcmh-g36c-qc44: Header parser of http stream wrapper does not verify header name and colon (colon)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html\r\nWrong-Header\r\nGood-Header: test\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html
|
||||
+
|
||||
+Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
|
||||
+bool(false)
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(23) "Content-Type: text/html"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..5aa0ee00618
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
|
||||
@@ -0,0 +1,51 @@
|
||||
+--TEST--
|
||||
+GHSA-pcmh-g36c-qc44: Header parser of http stream wrapper does not verify header name and colon (name)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html\r\nWrong-Header : test\r\nGood-Header: test\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html
|
||||
+
|
||||
+Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid response format (space in header name)! in %s
|
||||
+bool(false)
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(23) "Content-Type: text/html"
|
||||
+}
|
||||
--
|
||||
2.48.1
|
||||
|
||||
492
SOURCES/php-cve-2025-1735.patch
Normal file
492
SOURCES/php-cve-2025-1735.patch
Normal file
@ -0,0 +1,492 @@
|
||||
From df2ecf34256c4a301e8959fe2eed0323f8b1b57a Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Tue, 4 Mar 2025 17:23:01 +0100
|
||||
Subject: [PATCH 3/4] Fix GHSA-hrwm-9436-5mv3: pgsql escaping no error checks
|
||||
|
||||
This adds error checks for escape function is pgsql and pdo_pgsql
|
||||
extensions. It prevents possibility of storing not properly escaped
|
||||
data which could potentially lead to some security issues.
|
||||
|
||||
(cherry picked from commit 9376aeef9f8ff81f2705b8016237ec3e30bdee44)
|
||||
(cherry picked from commit 7633d987cc11ee2601223e73cfdb8b31fed5980f)
|
||||
---
|
||||
ext/pdo_pgsql/pgsql_driver.c | 10 +-
|
||||
ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt | 22 ++++
|
||||
ext/pgsql/pgsql.c | 129 +++++++++++++++----
|
||||
ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt | 64 +++++++++
|
||||
4 files changed, 202 insertions(+), 23 deletions(-)
|
||||
create mode 100644 ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
|
||||
create mode 100644 ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
|
||||
|
||||
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
|
||||
index e578bbc2720..021471cefc0 100644
|
||||
--- a/ext/pdo_pgsql/pgsql_driver.c
|
||||
+++ b/ext/pdo_pgsql/pgsql_driver.c
|
||||
@@ -323,11 +323,15 @@ static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
|
||||
unsigned char *escaped;
|
||||
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
|
||||
size_t tmp_len;
|
||||
+ int err;
|
||||
|
||||
switch (paramtype) {
|
||||
case PDO_PARAM_LOB:
|
||||
/* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
|
||||
escaped = PQescapeByteaConn(H->server, (unsigned char *)unquoted, unquotedlen, &tmp_len);
|
||||
+ if (escaped == NULL) {
|
||||
+ return 0;
|
||||
+ }
|
||||
*quotedlen = tmp_len + 1;
|
||||
*quoted = emalloc(*quotedlen + 1);
|
||||
memcpy((*quoted)+1, escaped, *quotedlen-2);
|
||||
@@ -339,7 +343,11 @@ static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
|
||||
default:
|
||||
*quoted = safe_emalloc(2, unquotedlen, 3);
|
||||
(*quoted)[0] = '\'';
|
||||
- *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, NULL);
|
||||
+ *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, &err);
|
||||
+ if (err) {
|
||||
+ efree(*quoted);
|
||||
+ return 0;
|
||||
+ }
|
||||
(*quoted)[*quotedlen + 1] = '\'';
|
||||
(*quoted)[*quotedlen + 2] = '\0';
|
||||
*quotedlen += 2;
|
||||
diff --git a/ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt b/ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..60e13613d04
|
||||
--- /dev/null
|
||||
+++ b/ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
|
||||
@@ -0,0 +1,22 @@
|
||||
+--TEST--
|
||||
+#GHSA-hrwm-9436-5mv3: pdo_pgsql extension does not check for errors during escaping
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
|
||||
+require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
|
||||
+require_once dirname(__FILE__) . '/config.inc';
|
||||
+PDOTest::skip();
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
|
||||
+require_once dirname(__FILE__) . '/config.inc';
|
||||
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
|
||||
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
+
|
||||
+$invalid = "ABC\xff\x30';";
|
||||
+var_dump($db->quote($invalid));
|
||||
+
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+bool(false)
|
||||
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
|
||||
index 7dcd56cf144..9e06497125c 100644
|
||||
--- a/ext/pgsql/pgsql.c
|
||||
+++ b/ext/pgsql/pgsql.c
|
||||
@@ -4393,10 +4393,16 @@ PHP_FUNCTION(pg_escape_string)
|
||||
to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
|
||||
#ifdef HAVE_PQESCAPE_CONN
|
||||
if (link) {
|
||||
+ int err;
|
||||
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
- ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
|
||||
+ ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), &err);
|
||||
+ if (err) {
|
||||
+ zend_throw_exception(zend_ce_exception, "Escaping string failed", 0);
|
||||
+ zend_string_efree(to);
|
||||
+ return;
|
||||
+ }
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -4445,6 +4451,10 @@ PHP_FUNCTION(pg_escape_bytea)
|
||||
} else
|
||||
#endif
|
||||
to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
|
||||
+ if (to == NULL) {
|
||||
+ zend_throw_exception(zend_ce_exception, "Escape failure", 0);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
|
||||
PQfreemem(to);
|
||||
@@ -5529,7 +5539,7 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
|
||||
char *escaped;
|
||||
smart_str querystr = {0};
|
||||
size_t new_len;
|
||||
- int i, num_rows;
|
||||
+ int i, num_rows, err;
|
||||
zval elem;
|
||||
|
||||
if (!*table_name) {
|
||||
@@ -5570,7 +5580,14 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
|
||||
"WHERE a.attnum > 0 AND c.relname = '");
|
||||
}
|
||||
escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
|
||||
- new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
|
||||
+ new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), &err);
|
||||
+ if (err) {
|
||||
+ php_error_docref(NULL, E_WARNING, "Escaping table name '%s' failed", table_name);
|
||||
+ efree(src);
|
||||
+ efree(escaped);
|
||||
+ smart_str_free(&querystr);
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
if (new_len) {
|
||||
smart_str_appendl(&querystr, escaped, new_len);
|
||||
}
|
||||
@@ -5578,7 +5595,14 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
|
||||
|
||||
smart_str_appends(&querystr, "' AND n.nspname = '");
|
||||
escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
|
||||
- new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
|
||||
+ new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), &err);
|
||||
+ if (err) {
|
||||
+ php_error_docref(NULL, E_WARNING, "Escaping table namespace '%s' failed", table_name);
|
||||
+ efree(src);
|
||||
+ efree(escaped);
|
||||
+ smart_str_free(&querystr);
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
if (new_len) {
|
||||
smart_str_appendl(&querystr, escaped, new_len);
|
||||
}
|
||||
@@ -5850,7 +5874,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
|
||||
{
|
||||
zend_string *field = NULL;
|
||||
zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
|
||||
- int err = 0, skip_field;
|
||||
+ int err = 0, escape_err = 0, skip_field;
|
||||
php_pgsql_data_type data_type;
|
||||
|
||||
assert(pg_link != NULL);
|
||||
@@ -6101,10 +6125,14 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
|
||||
/* PostgreSQL ignores \0 */
|
||||
str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
|
||||
/* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
|
||||
- ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
|
||||
- str = zend_string_truncate(str, ZSTR_LEN(str), 0);
|
||||
- ZVAL_NEW_STR(&new_val, str);
|
||||
- php_pgsql_add_quotes(&new_val, 1);
|
||||
+ ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err);
|
||||
+ if (escape_err) {
|
||||
+ err = 1;
|
||||
+ } else {
|
||||
+ str = zend_string_truncate(str, ZSTR_LEN(str), 0);
|
||||
+ ZVAL_NEW_STR(&new_val, str);
|
||||
+ php_pgsql_add_quotes(&new_val, 1);
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -6126,7 +6154,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
|
||||
}
|
||||
PGSQL_CONV_CHECK_IGNORE();
|
||||
if (err) {
|
||||
- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
|
||||
+ if (escape_err) {
|
||||
+ php_error_docref(NULL, E_NOTICE,
|
||||
+ "String value escaping failed for PostgreSQL '%s' (%s)",
|
||||
+ Z_STRVAL_P(type), ZSTR_VAL(field));
|
||||
+ } else {
|
||||
+ php_error_docref(NULL, E_NOTICE,
|
||||
+ "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)",
|
||||
+ Z_STRVAL_P(type), ZSTR_VAL(field));
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -6406,6 +6442,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
|
||||
#else
|
||||
tmp = PQescapeBytea(Z_STRVAL_P(val), (unsigned char *)Z_STRLEN_P(val), &to_len);
|
||||
#endif
|
||||
+ if (tmp == NULL) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Escaping value failed for %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
|
||||
+ err = 1;
|
||||
+ break;
|
||||
+ }
|
||||
ZVAL_STRINGL(&new_val, (char *)tmp, to_len - 1); /* PQescapeBytea's to_len includes additional '\0' */
|
||||
PQfreemem(tmp);
|
||||
php_pgsql_add_quotes(&new_val, 1);
|
||||
@@ -6488,6 +6529,12 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
|
||||
zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
|
||||
} else {
|
||||
char *escaped = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
|
||||
+ if (escaped == NULL) {
|
||||
+ /* This cannot fail because of invalid string but only due to failed memory allocation */
|
||||
+ php_error_docref(NULL, E_NOTICE, "Escaping field '%s' failed", ZSTR_VAL(field));
|
||||
+ err = 1;
|
||||
+ break;
|
||||
+ }
|
||||
add_assoc_zval(result, escaped, &new_val);
|
||||
PGSQLfree(escaped);
|
||||
}
|
||||
@@ -6566,7 +6613,7 @@ static int do_exec(smart_str *querystr, ExecStatusType expect, PGconn *pg_link,
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
-static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
|
||||
+static inline int build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
|
||||
{
|
||||
size_t table_len = strlen(table);
|
||||
|
||||
@@ -6577,6 +6624,10 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const c
|
||||
smart_str_appendl(querystr, table, len);
|
||||
} else {
|
||||
char *escaped = PGSQLescapeIdentifier(pg_link, table, len);
|
||||
+ if (escaped == NULL) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", table);
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
smart_str_appends(querystr, escaped);
|
||||
PGSQLfree(escaped);
|
||||
}
|
||||
@@ -6589,11 +6640,17 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const c
|
||||
smart_str_appendl(querystr, after_dot, len);
|
||||
} else {
|
||||
char *escaped = PGSQLescapeIdentifier(pg_link, after_dot, len);
|
||||
+ if (escaped == NULL) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", table);
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
smart_str_appendc(querystr, '.');
|
||||
smart_str_appends(querystr, escaped);
|
||||
PGSQLfree(escaped);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -6615,7 +6672,9 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
|
||||
ZVAL_UNDEF(&converted);
|
||||
if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
|
||||
smart_str_appends(&querystr, "INSERT INTO ");
|
||||
- build_tablename(&querystr, pg_link, table);
|
||||
+ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appends(&querystr, " DEFAULT VALUES");
|
||||
|
||||
goto no_values;
|
||||
@@ -6631,7 +6690,9 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
|
||||
}
|
||||
|
||||
smart_str_appends(&querystr, "INSERT INTO ");
|
||||
- build_tablename(&querystr, pg_link, table);
|
||||
+ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appends(&querystr, " (");
|
||||
|
||||
ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
|
||||
@@ -6641,6 +6702,10 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
|
||||
}
|
||||
if (opt & PGSQL_DML_ESCAPE) {
|
||||
tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
|
||||
+ if (tmp == NULL) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld));
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appends(&querystr, tmp);
|
||||
PGSQLfree(tmp);
|
||||
} else {
|
||||
@@ -6652,15 +6717,19 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
|
||||
smart_str_appends(&querystr, ") VALUES (");
|
||||
|
||||
/* make values string */
|
||||
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
|
||||
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(var_array), fld, val) {
|
||||
/* we can avoid the key_type check here, because we tested it in the other loop */
|
||||
switch (Z_TYPE_P(val)) {
|
||||
case IS_STRING:
|
||||
if (opt & PGSQL_DML_ESCAPE) {
|
||||
- size_t new_len;
|
||||
- char *tmp;
|
||||
- tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
|
||||
- new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
|
||||
+ int error;
|
||||
+ char *tmp = safe_emalloc(Z_STRLEN_P(val), 2, 1);
|
||||
+ size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error);
|
||||
+ if (error) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld));
|
||||
+ efree(tmp);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appendc(&querystr, '\'');
|
||||
smart_str_appendl(&querystr, tmp, new_len);
|
||||
smart_str_appendc(&querystr, '\'');
|
||||
@@ -6810,6 +6879,10 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
|
||||
}
|
||||
if (opt & PGSQL_DML_ESCAPE) {
|
||||
char *tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
|
||||
+ if (tmp == NULL) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld));
|
||||
+ return -1;
|
||||
+ }
|
||||
smart_str_appends(querystr, tmp);
|
||||
PGSQLfree(tmp);
|
||||
} else {
|
||||
@@ -6824,8 +6897,14 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
|
||||
switch (Z_TYPE_P(val)) {
|
||||
case IS_STRING:
|
||||
if (opt & PGSQL_DML_ESCAPE) {
|
||||
+ int error;
|
||||
char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
|
||||
- size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
|
||||
+ size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error);
|
||||
+ if (error) {
|
||||
+ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld));
|
||||
+ efree(tmp);
|
||||
+ return -1;
|
||||
+ }
|
||||
smart_str_appendc(querystr, '\'');
|
||||
smart_str_appendl(querystr, tmp, new_len);
|
||||
smart_str_appendc(querystr, '\'');
|
||||
@@ -6894,7 +6973,9 @@ PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var
|
||||
}
|
||||
|
||||
smart_str_appends(&querystr, "UPDATE ");
|
||||
- build_tablename(&querystr, pg_link, table);
|
||||
+ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appends(&querystr, " SET ");
|
||||
|
||||
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
|
||||
@@ -6992,7 +7073,9 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids
|
||||
}
|
||||
|
||||
smart_str_appends(&querystr, "DELETE FROM ");
|
||||
- build_tablename(&querystr, pg_link, table);
|
||||
+ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appends(&querystr, " WHERE ");
|
||||
|
||||
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
|
||||
@@ -7130,7 +7213,9 @@ PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array, l
|
||||
}
|
||||
|
||||
smart_str_appends(&querystr, "SELECT * FROM ");
|
||||
- build_tablename(&querystr, pg_link, table);
|
||||
+ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
smart_str_appends(&querystr, " WHERE ");
|
||||
|
||||
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
|
||||
diff --git a/ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt b/ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..c1c5e05dce6
|
||||
--- /dev/null
|
||||
+++ b/ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
|
||||
@@ -0,0 +1,64 @@
|
||||
+--TEST--
|
||||
+#GHSA-hrwm-9436-5mv3: pgsql extension does not check for errors during escaping
|
||||
+--EXTENSIONS--
|
||||
+pgsql
|
||||
+--SKIPIF--
|
||||
+<?php include("skipif.inc"); ?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+include 'config.inc';
|
||||
+define('FILE_NAME', __DIR__ . '/php.gif');
|
||||
+
|
||||
+$db = pg_connect($conn_str);
|
||||
+pg_query($db, "DROP TABLE IF EXISTS ghsa_hrmw_9436_5mv3");
|
||||
+pg_query($db, "CREATE TABLE ghsa_hrmw_9436_5mv3 (bar text);");
|
||||
+
|
||||
+// pg_escape_literal/pg_escape_identifier
|
||||
+
|
||||
+$invalid = "ABC\xff\x30';";
|
||||
+$flags = PGSQL_DML_NO_CONV | PGSQL_DML_ESCAPE;
|
||||
+
|
||||
+var_dump(pg_insert($db, $invalid, ['bar' => 'test'])); // table name str escape in php_pgsql_meta_data
|
||||
+var_dump(pg_insert($db, "$invalid.tbl", ['bar' => 'test'])); // schema name str escape in php_pgsql_meta_data
|
||||
+var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', ['bar' => $invalid])); // converted value str escape in php_pgsql_convert
|
||||
+var_dump(pg_insert($db, $invalid, [])); // ident escape in build_tablename
|
||||
+var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', [$invalid => 'foo'], $flags)); // ident escape for field php_pgsql_insert
|
||||
+var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', ['bar' => $invalid], $flags)); // str escape for field value in php_pgsql_insert
|
||||
+var_dump(pg_update($db, 'ghsa_hrmw_9436_5mv3', ['bar' => 'val'], [$invalid => 'test'], $flags)); // ident escape in build_assignment_string
|
||||
+var_dump(pg_update($db, 'ghsa_hrmw_9436_5mv3', ['bar' => 'val'], ['bar' => $invalid], $flags)); // invalid str escape in build_assignment_string
|
||||
+var_dump(pg_escape_literal($db, $invalid)); // pg_escape_literal escape
|
||||
+var_dump(pg_escape_identifier($db, $invalid)); // pg_escape_identifier escape
|
||||
+
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+
|
||||
+Warning: pg_insert(): Escaping table name 'ABC%s';' failed in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Warning: pg_insert(): Escaping table namespace 'ABC%s';.tbl' failed in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Notice: pg_insert(): String value escaping failed for PostgreSQL 'text' (bar) in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Notice: pg_insert(): Failed to escape table name 'ABC%s';' in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Notice: pg_insert(): Failed to escape field 'ABC%s';' in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Notice: pg_insert(): Failed to escape field 'bar' value in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Notice: pg_update(): Failed to escape field 'ABC%s';' in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Notice: pg_update(): Failed to escape field 'bar' value in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Warning: pg_escape_literal(): Failed to escape in %s on line %d
|
||||
+bool(false)
|
||||
+
|
||||
+Warning: pg_escape_identifier(): Failed to escape in %s on line %d
|
||||
+bool(false)
|
||||
--
|
||||
2.50.0
|
||||
|
||||
From d52bcc1e66edd421dfea1698b1f897ad26c5f15f Mon Sep 17 00:00:00 2001
|
||||
From: Remi Collet <remi@remirepo.net>
|
||||
Date: Thu, 3 Jul 2025 09:32:25 +0200
|
||||
Subject: [PATCH 4/4] NEWS
|
||||
|
||||
(cherry picked from commit 970548b94b7f23be32154d05a9545b10c98bfd62)
|
||||
---
|
||||
NEWS | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/NEWS b/NEWS
|
||||
index fda646c7010..a9dd716c003 100644
|
||||
--- a/NEWS
|
||||
+++ b/NEWS
|
||||
@@ -1,6 +1,20 @@
|
||||
PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
|
||||
+Backported from 8.1.33
|
||||
+
|
||||
+- PGSQL:
|
||||
+ . Fixed GHSA-hrwm-9436-5mv3 (pgsql extension does not check for errors during
|
||||
+ escaping). (CVE-2025-1735) (Jakub Zelenka)
|
||||
+
|
||||
+- SOAP:
|
||||
+ . Fixed GHSA-453j-q27h-5p8x (NULL Pointer Dereference in PHP SOAP Extension
|
||||
+ via Large XML Namespace Prefix). (CVE-2025-6491) (Lekssays, nielsdos)
|
||||
+
|
||||
+- Standard:
|
||||
+ . Fixed GHSA-3cr5-j632-f35r (Null byte termination in hostnames).
|
||||
+ (CVE-2025-1220) (Jakub Zelenka)
|
||||
+
|
||||
Backported from 8.1.32
|
||||
|
||||
- LibXML:
|
||||
--
|
||||
2.50.0
|
||||
|
||||
242
SOURCES/php-cve-2025-1736.patch
Normal file
242
SOURCES/php-cve-2025-1736.patch
Normal file
@ -0,0 +1,242 @@
|
||||
From 134f821622e2d2b68d66bea16e16c05b7b0f5114 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Fri, 14 Feb 2025 19:17:22 +0100
|
||||
Subject: [PATCH 04/11] Fix GHSA-hgf5-96fm-v528: http user header check of crlf
|
||||
|
||||
(cherry picked from commit 41d49abbd99dab06cdae4834db664435f8177174)
|
||||
(cherry picked from commit 8f65ef50929f6781f4973325f9b619f02cce19d8)
|
||||
---
|
||||
ext/standard/http_fopen_wrapper.c | 2 +-
|
||||
.../tests/http/ghsa-hgf5-96fm-v528-001.phpt | 65 +++++++++++++++++++
|
||||
.../tests/http/ghsa-hgf5-96fm-v528-002.phpt | 62 ++++++++++++++++++
|
||||
.../tests/http/ghsa-hgf5-96fm-v528-003.phpt | 64 ++++++++++++++++++
|
||||
4 files changed, 192 insertions(+), 1 deletion(-)
|
||||
create mode 100644 ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
|
||||
|
||||
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
|
||||
index b64a7c95446..46f7c7ebcee 100644
|
||||
--- a/ext/standard/http_fopen_wrapper.c
|
||||
+++ b/ext/standard/http_fopen_wrapper.c
|
||||
@@ -109,7 +109,7 @@ static inline void strip_header(char *header_bag, char *lc_header_bag,
|
||||
static zend_bool check_has_header(const char *headers, const char *header) {
|
||||
const char *s = headers;
|
||||
while ((s = strstr(s, header))) {
|
||||
- if (s == headers || *(s-1) == '\n') {
|
||||
+ if (s == headers || (*(s-1) == '\n' && *(s-2) == '\r')) {
|
||||
return 1;
|
||||
}
|
||||
s++;
|
||||
diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..c8dcd47a4a4
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
|
||||
@@ -0,0 +1,65 @@
|
||||
+--TEST--
|
||||
+GHSA-hgf5-96fm-v528: Stream HTTP wrapper header check might omit basic auth header (incorrect inside pos)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ $result = fread($conn, 1024);
|
||||
+ $encoded_result = base64_encode($result);
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
|
||||
+
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ $opts = [
|
||||
+ "http" => [
|
||||
+ "method" => "GET",
|
||||
+ "header" => "Cookie: foo=bar\nauthorization:x\r\n"
|
||||
+ ]
|
||||
+ ];
|
||||
+ $ctx = stream_context_create($opts);
|
||||
+ var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+array(7) {
|
||||
+ [0]=>
|
||||
+ string(14) "GET / HTTP/1.%d"
|
||||
+ [1]=>
|
||||
+ string(33) "Authorization: Basic dXNlcjpwd2Q="
|
||||
+ [2]=>
|
||||
+ string(21) "Host: 127.0.0.1:%d"
|
||||
+ [3]=>
|
||||
+ string(17) "Connection: close"
|
||||
+ [4]=>
|
||||
+ string(31) "Cookie: foo=bar
|
||||
+authorization:x"
|
||||
+ [5]=>
|
||||
+ string(0) ""
|
||||
+ [6]=>
|
||||
+ string(0) ""
|
||||
+}
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(38) "Content-Type: text/html; charset=utf-8"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..ca8f75f0327
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
|
||||
@@ -0,0 +1,62 @@
|
||||
+--TEST--
|
||||
+GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct start pos)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ $result = fread($conn, 1024);
|
||||
+ $encoded_result = base64_encode($result);
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
|
||||
+
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ $opts = [
|
||||
+ "http" => [
|
||||
+ "method" => "GET",
|
||||
+ "header" => "Authorization: Bearer x\r\n"
|
||||
+ ]
|
||||
+ ];
|
||||
+ $ctx = stream_context_create($opts);
|
||||
+ var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+array(6) {
|
||||
+ [0]=>
|
||||
+ string(14) "GET / HTTP/1.%d"
|
||||
+ [1]=>
|
||||
+ string(21) "Host: 127.0.0.1:%d"
|
||||
+ [2]=>
|
||||
+ string(17) "Connection: close"
|
||||
+ [3]=>
|
||||
+ string(23) "Authorization: Bearer x"
|
||||
+ [4]=>
|
||||
+ string(0) ""
|
||||
+ [5]=>
|
||||
+ string(0) ""
|
||||
+}
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(38) "Content-Type: text/html; charset=utf-8"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..4cfbc7ee804
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
|
||||
@@ -0,0 +1,64 @@
|
||||
+--TEST--
|
||||
+GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct middle pos)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+ $ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ $result = fread($conn, 1024);
|
||||
+ $encoded_result = base64_encode($result);
|
||||
+
|
||||
+ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
|
||||
+
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ $opts = [
|
||||
+ "http" => [
|
||||
+ "method" => "GET",
|
||||
+ "header" => "Cookie: x=y\r\nAuthorization: Bearer x\r\n"
|
||||
+ ]
|
||||
+ ];
|
||||
+ $ctx = stream_context_create($opts);
|
||||
+ var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+array(7) {
|
||||
+ [0]=>
|
||||
+ string(14) "GET / HTTP/1.%d"
|
||||
+ [1]=>
|
||||
+ string(21) "Host: 127.0.0.1:%d"
|
||||
+ [2]=>
|
||||
+ string(17) "Connection: close"
|
||||
+ [3]=>
|
||||
+ string(11) "Cookie: x=y"
|
||||
+ [4]=>
|
||||
+ string(23) "Authorization: Bearer x"
|
||||
+ [5]=>
|
||||
+ string(0) ""
|
||||
+ [6]=>
|
||||
+ string(0) ""
|
||||
+}
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 200 Ok"
|
||||
+ [1]=>
|
||||
+ string(38) "Content-Type: text/html; charset=utf-8"
|
||||
+}
|
||||
--
|
||||
2.48.1
|
||||
|
||||
349
SOURCES/php-cve-2025-1861.patch
Normal file
349
SOURCES/php-cve-2025-1861.patch
Normal file
@ -0,0 +1,349 @@
|
||||
From 5418040dcaaca46965ed6f8a4ad1541709c32e9f Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Zelenka <bukka@php.net>
|
||||
Date: Tue, 4 Mar 2025 09:01:34 +0100
|
||||
Subject: [PATCH 03/11] Fix GHSA-52jp-hrpf-2jff: http redirect location
|
||||
truncation
|
||||
|
||||
It converts the allocation of location to be on heap instead of stack
|
||||
and errors if the location length is greater than 8086 bytes.
|
||||
|
||||
(cherry picked from commit ac1a054bb3eb5994a199e8b18cca28cbabf5943e)
|
||||
(cherry picked from commit adc7e9f20c9a9aab9cd23ca47ec3fb96287898ae)
|
||||
---
|
||||
ext/standard/http_fopen_wrapper.c | 87 ++++++++++++-------
|
||||
.../tests/http/ghsa-52jp-hrpf-2jff-001.phpt | 58 +++++++++++++
|
||||
.../tests/http/ghsa-52jp-hrpf-2jff-002.phpt | 55 ++++++++++++
|
||||
3 files changed, 168 insertions(+), 32 deletions(-)
|
||||
create mode 100644 ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
|
||||
create mode 100644 ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
|
||||
|
||||
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
|
||||
index 071d6a4d119..b64a7c95446 100644
|
||||
--- a/ext/standard/http_fopen_wrapper.c
|
||||
+++ b/ext/standard/http_fopen_wrapper.c
|
||||
@@ -69,15 +69,16 @@
|
||||
|
||||
#include "php_fopen_wrappers.h"
|
||||
|
||||
-#define HTTP_HEADER_BLOCK_SIZE 1024
|
||||
-#define PHP_URL_REDIRECT_MAX 20
|
||||
-#define HTTP_HEADER_USER_AGENT 1
|
||||
-#define HTTP_HEADER_HOST 2
|
||||
-#define HTTP_HEADER_AUTH 4
|
||||
-#define HTTP_HEADER_FROM 8
|
||||
-#define HTTP_HEADER_CONTENT_LENGTH 16
|
||||
-#define HTTP_HEADER_TYPE 32
|
||||
-#define HTTP_HEADER_CONNECTION 64
|
||||
+#define HTTP_HEADER_BLOCK_SIZE 1024
|
||||
+#define HTTP_HEADER_MAX_LOCATION_SIZE 8182 /* 8192 - 10 (size of "Location: ") */
|
||||
+#define PHP_URL_REDIRECT_MAX 20
|
||||
+#define HTTP_HEADER_USER_AGENT 1
|
||||
+#define HTTP_HEADER_HOST 2
|
||||
+#define HTTP_HEADER_AUTH 4
|
||||
+#define HTTP_HEADER_FROM 8
|
||||
+#define HTTP_HEADER_CONTENT_LENGTH 16
|
||||
+#define HTTP_HEADER_TYPE 32
|
||||
+#define HTTP_HEADER_CONNECTION 64
|
||||
|
||||
#define HTTP_WRAPPER_HEADER_INIT 1
|
||||
#define HTTP_WRAPPER_REDIRECTED 2
|
||||
@@ -121,17 +122,15 @@ typedef struct _php_stream_http_response_header_info {
|
||||
size_t file_size;
|
||||
zend_bool error;
|
||||
zend_bool follow_location;
|
||||
- char location[HTTP_HEADER_BLOCK_SIZE];
|
||||
+ char *location;
|
||||
+ size_t location_len;
|
||||
} php_stream_http_response_header_info;
|
||||
|
||||
static void php_stream_http_response_header_info_init(
|
||||
php_stream_http_response_header_info *header_info)
|
||||
{
|
||||
- header_info->transfer_encoding = NULL;
|
||||
- header_info->file_size = 0;
|
||||
- header_info->error = 0;
|
||||
+ memset(header_info, 0, sizeof(php_stream_http_response_header_info));
|
||||
header_info->follow_location = 1;
|
||||
- header_info->location[0] = '\0';
|
||||
}
|
||||
|
||||
/* Trim white spaces from response header line and update its length */
|
||||
@@ -258,7 +257,22 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w
|
||||
* RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
|
||||
header_info->follow_location = 0;
|
||||
}
|
||||
- strlcpy(header_info->location, last_header_value, sizeof(header_info->location));
|
||||
+ size_t last_header_value_len = strlen(last_header_value);
|
||||
+ if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) {
|
||||
+ header_info->error = 1;
|
||||
+ php_stream_wrapper_log_error(wrapper, options,
|
||||
+ "HTTP Location header size is over the limit of %d bytes",
|
||||
+ HTTP_HEADER_MAX_LOCATION_SIZE);
|
||||
+ zend_string_efree(last_header_line_str);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ if (header_info->location_len == 0) {
|
||||
+ header_info->location = emalloc(last_header_value_len + 1);
|
||||
+ } else if (header_info->location_len <= last_header_value_len) {
|
||||
+ header_info->location = erealloc(header_info->location, last_header_value_len + 1);
|
||||
+ }
|
||||
+ header_info->location_len = last_header_value_len;
|
||||
+ memcpy(header_info->location, last_header_value, last_header_value_len + 1);
|
||||
} else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) {
|
||||
php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0);
|
||||
} else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) {
|
||||
@@ -541,6 +555,8 @@ finish:
|
||||
}
|
||||
}
|
||||
|
||||
+ php_stream_http_response_header_info_init(&header_info);
|
||||
+
|
||||
if (stream == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -918,8 +934,6 @@ finish:
|
||||
}
|
||||
}
|
||||
|
||||
- php_stream_http_response_header_info_init(&header_info);
|
||||
-
|
||||
/* read past HTTP headers */
|
||||
while (!php_stream_eof(stream)) {
|
||||
size_t http_header_line_length;
|
||||
@@ -989,12 +1003,12 @@ finish:
|
||||
last_header_line_str, NULL, NULL, response_code, response_header, &header_info);
|
||||
}
|
||||
|
||||
- if (!reqok || (header_info.location[0] != '\0' && header_info.follow_location)) {
|
||||
+ if (!reqok || (header_info.location != NULL && header_info.follow_location)) {
|
||||
if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (header_info.location[0] != '\0')
|
||||
+ if (header_info.location != NULL)
|
||||
php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0);
|
||||
|
||||
php_stream_close(stream);
|
||||
@@ -1005,18 +1019,17 @@ finish:
|
||||
header_info.transfer_encoding = NULL;
|
||||
}
|
||||
|
||||
- if (header_info.location[0] != '\0') {
|
||||
+ if (header_info.location != NULL) {
|
||||
|
||||
- char new_path[HTTP_HEADER_BLOCK_SIZE];
|
||||
- char loc_path[HTTP_HEADER_BLOCK_SIZE];
|
||||
+ char *new_path = NULL;
|
||||
|
||||
- *new_path='\0';
|
||||
if (strlen(header_info.location) < 8 ||
|
||||
(strncasecmp(header_info.location, "http://", sizeof("http://")-1) &&
|
||||
strncasecmp(header_info.location, "https://", sizeof("https://")-1) &&
|
||||
strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) &&
|
||||
strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1)))
|
||||
{
|
||||
+ char *loc_path = NULL;
|
||||
if (*header_info.location != '/') {
|
||||
if (*(header_info.location+1) != '\0' && resource->path) {
|
||||
char *s = strrchr(ZSTR_VAL(resource->path), '/');
|
||||
@@ -1034,31 +1047,35 @@ finish:
|
||||
if (resource->path &&
|
||||
ZSTR_VAL(resource->path)[0] == '/' &&
|
||||
ZSTR_VAL(resource->path)[1] == '\0') {
|
||||
- snprintf(loc_path, sizeof(loc_path) - 1, "%s%s",
|
||||
- ZSTR_VAL(resource->path), header_info.location);
|
||||
+ spprintf(&loc_path, 0, "%s%s", ZSTR_VAL(resource->path), header_info.location);
|
||||
} else {
|
||||
- snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s",
|
||||
- ZSTR_VAL(resource->path), header_info.location);
|
||||
+ spprintf(&loc_path, 0, "%s/%s", ZSTR_VAL(resource->path), header_info.location);
|
||||
}
|
||||
} else {
|
||||
- snprintf(loc_path, sizeof(loc_path) - 1, "/%s", header_info.location);
|
||||
+ spprintf(&loc_path, 0, "/%s", header_info.location);
|
||||
}
|
||||
} else {
|
||||
- strlcpy(loc_path, header_info.location, sizeof(loc_path));
|
||||
+ loc_path = header_info.location;
|
||||
+ header_info.location = NULL;
|
||||
}
|
||||
if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
|
||||
- snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path);
|
||||
+ spprintf(&new_path, 0, "%s://%s:%d%s", ZSTR_VAL(resource->scheme),
|
||||
+ ZSTR_VAL(resource->host), resource->port, loc_path);
|
||||
} else {
|
||||
- snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path);
|
||||
+ spprintf(&new_path, 0, "%s://%s%s", ZSTR_VAL(resource->scheme),
|
||||
+ ZSTR_VAL(resource->host), loc_path);
|
||||
}
|
||||
+ efree(loc_path);
|
||||
} else {
|
||||
- strlcpy(new_path, header_info.location, sizeof(new_path));
|
||||
+ new_path = header_info.location;
|
||||
+ header_info.location = NULL;
|
||||
}
|
||||
|
||||
php_url_free(resource);
|
||||
/* check for invalid redirection URLs */
|
||||
if ((resource = php_url_parse(new_path)) == NULL) {
|
||||
php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path);
|
||||
+ efree(new_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1070,6 +1087,7 @@ finish:
|
||||
while (s < e) { \
|
||||
if (iscntrl(*s)) { \
|
||||
php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \
|
||||
+ efree(new_path); \
|
||||
goto out; \
|
||||
} \
|
||||
s++; \
|
||||
@@ -1085,6 +1103,7 @@ finish:
|
||||
stream = php_stream_url_wrap_http_ex(
|
||||
wrapper, new_path, mode, options, opened_path, context,
|
||||
--redirect_max, HTTP_WRAPPER_REDIRECTED, response_header STREAMS_CC);
|
||||
+ efree(new_path);
|
||||
} else {
|
||||
php_stream_wrapper_log_error(wrapper, options, "HTTP request failed! %s", tmp_line);
|
||||
}
|
||||
@@ -1097,6 +1116,10 @@ out:
|
||||
efree(http_header_line);
|
||||
}
|
||||
|
||||
+ if (header_info.location != NULL) {
|
||||
+ efree(header_info.location);
|
||||
+ }
|
||||
+
|
||||
if (resource) {
|
||||
php_url_free(resource);
|
||||
}
|
||||
diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..46d77ec4aff
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
|
||||
@@ -0,0 +1,58 @@
|
||||
+--TEST--
|
||||
+GHSA-52jp-hrpf-2jff: HTTP stream wrapper truncate redirect location to 1024 bytes (success)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+$ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ $loc = str_repeat("y", 8000);
|
||||
+ fwrite($conn, "HTTP/1.0 301 Ok\r\nContent-Type: text/html;\r\nLocation: $loc\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ case STREAM_NOTIFY_REDIRECTED:
|
||||
+ echo "Redirected: ";
|
||||
+ var_dump($message);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html;
|
||||
+Redirected: string(8000) "%s"
|
||||
+
|
||||
+Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: %s
|
||||
+string(0) ""
|
||||
+array(3) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 301 Ok"
|
||||
+ [1]=>
|
||||
+ string(24) "Content-Type: text/html;"
|
||||
+ [2]=>
|
||||
+ string(8010) "Location: %s"
|
||||
+}
|
||||
diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..d25c89d06e5
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
|
||||
@@ -0,0 +1,55 @@
|
||||
+--TEST--
|
||||
+GHSA-52jp-hrpf-2jff: HTTP stream wrapper truncate redirect location to 1024 bytes (over limit)
|
||||
+--FILE--
|
||||
+<?php
|
||||
+$serverCode = <<<'CODE'
|
||||
+$ctxt = stream_context_create([
|
||||
+ "socket" => [
|
||||
+ "tcp_nodelay" => true
|
||||
+ ]
|
||||
+ ]);
|
||||
+
|
||||
+ $server = stream_socket_server(
|
||||
+ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
+ phpt_notify_server_start($server);
|
||||
+
|
||||
+ $conn = stream_socket_accept($server);
|
||||
+
|
||||
+ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
|
||||
+
|
||||
+ $loc = str_repeat("y", 9000);
|
||||
+ fwrite($conn, "HTTP/1.0 301 Ok\r\nContent-Type: text/html;\r\nLocation: $loc\r\n\r\nbody\r\n");
|
||||
+CODE;
|
||||
+
|
||||
+$clientCode = <<<'CODE'
|
||||
+ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
|
||||
+ switch($notification_code) {
|
||||
+ case STREAM_NOTIFY_MIME_TYPE_IS:
|
||||
+ echo "Found the mime-type: ", $message, PHP_EOL;
|
||||
+ break;
|
||||
+ case STREAM_NOTIFY_REDIRECTED:
|
||||
+ echo "Redirected: ";
|
||||
+ var_dump($message);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ $ctx = stream_context_create();
|
||||
+ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
|
||||
+ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
|
||||
+ var_dump($http_response_header);
|
||||
+CODE;
|
||||
+
|
||||
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
|
||||
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Found the mime-type: text/html;
|
||||
+
|
||||
+Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP Location header size is over the limit of 8182 bytes in %s
|
||||
+string(0) ""
|
||||
+array(2) {
|
||||
+ [0]=>
|
||||
+ string(15) "HTTP/1.0 301 Ok"
|
||||
+ [1]=>
|
||||
+ string(24) "Content-Type: text/html;"
|
||||
+}
|
||||
--
|
||||
2.48.1
|
||||
|
||||
103
SOURCES/php-cve-2025-6491.patch
Normal file
103
SOURCES/php-cve-2025-6491.patch
Normal file
@ -0,0 +1,103 @@
|
||||
From c13a3b2a3710c66231f0cad16ff74ef75c8672a7 Mon Sep 17 00:00:00 2001
|
||||
From: Ahmed Lekssays <lekssaysahmed@gmail.com>
|
||||
Date: Tue, 3 Jun 2025 09:00:55 +0000
|
||||
Subject: [PATCH 1/4] Fix GHSA-453j-q27h-5p8x
|
||||
|
||||
Libxml versions prior to 2.13 cannot correctly handle a call to
|
||||
xmlNodeSetName() with a name longer than 2G. It will leave the node
|
||||
object in an invalid state with a NULL name. This later causes a NULL
|
||||
pointer dereference when using the name during message serialization.
|
||||
|
||||
To solve this, implement a workaround that resets the name to the
|
||||
sentinel name if this situation arises.
|
||||
|
||||
Versions of libxml of 2.13 and higher are not affected.
|
||||
|
||||
This can be exploited if a SoapVar is created with a fully qualified
|
||||
name that is longer than 2G. This would be possible if some application
|
||||
code uses a namespace prefix from an untrusted source like from a remote
|
||||
SOAP service.
|
||||
|
||||
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
|
||||
(cherry picked from commit 9cb3d8d200f0c822b17bda35a2a67a97b039d3e1)
|
||||
(cherry picked from commit 1b7410a57f8a5fd1dd43854bcf7b9200517c9fd2)
|
||||
---
|
||||
ext/soap/soap.c | 6 ++--
|
||||
ext/soap/tests/soap_qname_crash.phpt | 48 ++++++++++++++++++++++++++++
|
||||
2 files changed, 52 insertions(+), 2 deletions(-)
|
||||
create mode 100644 ext/soap/tests/soap_qname_crash.phpt
|
||||
|
||||
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
|
||||
index 7429aebbf70..94f1db526c6 100644
|
||||
--- a/ext/soap/soap.c
|
||||
+++ b/ext/soap/soap.c
|
||||
@@ -4457,8 +4457,10 @@ static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName,
|
||||
}
|
||||
xmlParam = master_to_xml(enc, val, style, parent);
|
||||
zval_ptr_dtor(&defval);
|
||||
- if (!strcmp((char*)xmlParam->name, "BOGUS")) {
|
||||
- xmlNodeSetName(xmlParam, BAD_CAST(paramName));
|
||||
+ if (xmlParam != NULL) {
|
||||
+ if (xmlParam->name == NULL || strcmp((char*)xmlParam->name, "BOGUS") == 0) {
|
||||
+ xmlNodeSetName(xmlParam, BAD_CAST(paramName));
|
||||
+ }
|
||||
}
|
||||
return xmlParam;
|
||||
}
|
||||
diff --git a/ext/soap/tests/soap_qname_crash.phpt b/ext/soap/tests/soap_qname_crash.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..7a1bf026022
|
||||
--- /dev/null
|
||||
+++ b/ext/soap/tests/soap_qname_crash.phpt
|
||||
@@ -0,0 +1,48 @@
|
||||
+--TEST--
|
||||
+Test SoapClient with excessively large QName prefix in SoapVar
|
||||
+--EXTENSIONS--
|
||||
+soap
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (PHP_INT_SIZE != 8) die("skip: 64-bit only");
|
||||
+?>
|
||||
+--INI--
|
||||
+memory_limit=8G
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+class TestSoapClient extends SoapClient {
|
||||
+ public function __doRequest(
|
||||
+ $request,
|
||||
+ $location,
|
||||
+ $action,
|
||||
+ $version,
|
||||
+ $one_way = false
|
||||
+ ): ?string {
|
||||
+ die($request);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+$prefix = str_repeat("A", 2 * 1024 * 1024 * 1024);
|
||||
+$qname = "{$prefix}:tag";
|
||||
+
|
||||
+echo "Attempting to create SoapVar with very large QName\n";
|
||||
+
|
||||
+$var = new SoapVar("value", XSD_QNAME, null, null, $qname);
|
||||
+
|
||||
+echo "Attempting encoding\n";
|
||||
+
|
||||
+$options = [
|
||||
+ 'location' => 'http://127.0.0.1/',
|
||||
+ 'uri' => 'urn:dummy',
|
||||
+ 'trace' => 1,
|
||||
+ 'exceptions' => true,
|
||||
+];
|
||||
+$client = new TestSoapClient(null, $options);
|
||||
+$client->__soapCall("DummyFunction", [$var]);
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+Attempting to create SoapVar with very large QName
|
||||
+Attempting encoding
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:dummy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:DummyFunction><param0 xsi:type="xsd:QName">value</param0></ns1:DummyFunction></SOAP-ENV:Body></SOAP-ENV:Envelope>
|
||||
--
|
||||
2.50.0
|
||||
|
||||
135
SOURCES/php-ghsa-4w77-75f9-2c8w.patch
Normal file
135
SOURCES/php-ghsa-4w77-75f9-2c8w.patch
Normal file
@ -0,0 +1,135 @@
|
||||
From 56488a8a4ec68e58eecc9e78dd75e41adf56984c Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
|
||||
Date: Sat, 9 Nov 2024 15:29:52 +0100
|
||||
Subject: [PATCH 6/7] Fix GHSA-4w77-75f9-2c8w
|
||||
|
||||
(cherry picked from commit 7dd336ae838bbf2c62dc47e3c900d657d3534c02)
|
||||
(cherry picked from commit 462092a48aa0dbad24d9fa8a4a9d418faa14d309)
|
||||
---
|
||||
sapi/cli/php_cli_server.c | 6 +---
|
||||
sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt | 41 +++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+), 5 deletions(-)
|
||||
create mode 100644 sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt
|
||||
|
||||
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
|
||||
index c3097861e3f..8717dc57418 100644
|
||||
--- a/sapi/cli/php_cli_server.c
|
||||
+++ b/sapi/cli/php_cli_server.c
|
||||
@@ -1923,8 +1923,6 @@ static size_t php_cli_server_client_send_through(php_cli_server_client *client,
|
||||
|
||||
static void php_cli_server_client_populate_request_info(const php_cli_server_client *client, sapi_request_info *request_info) /* {{{ */
|
||||
{
|
||||
- char *val;
|
||||
-
|
||||
request_info->request_method = php_http_method_str(client->request.request_method);
|
||||
request_info->proto_num = client->request.protocol_version;
|
||||
request_info->request_uri = client->request.request_uri;
|
||||
@@ -1932,9 +1930,7 @@ static void php_cli_server_client_populate_request_info(const php_cli_server_cli
|
||||
request_info->query_string = client->request.query_string;
|
||||
request_info->content_length = client->request.content_len;
|
||||
request_info->auth_user = request_info->auth_password = request_info->auth_digest = NULL;
|
||||
- if (NULL != (val = zend_hash_str_find_ptr(&client->request.headers, "content-type", sizeof("content-type")-1))) {
|
||||
- request_info->content_type = val;
|
||||
- }
|
||||
+ request_info->content_type = zend_hash_str_find_ptr(&client->request.headers, "content-type", sizeof("content-type")-1);
|
||||
} /* }}} */
|
||||
|
||||
static void destroy_request_info(sapi_request_info *request_info) /* {{{ */
|
||||
diff --git a/sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt b/sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..80944c3d14f
|
||||
--- /dev/null
|
||||
+++ b/sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt
|
||||
@@ -0,0 +1,41 @@
|
||||
+--TEST--
|
||||
+GHSA-4w77-75f9-2c8w (Heap-Use-After-Free in sapi_read_post_data Processing in CLI SAPI Interface)
|
||||
+--INI--
|
||||
+allow_url_fopen=1
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+include "skipif.inc";
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+include "php_cli_server.inc";
|
||||
+
|
||||
+$serverCode = <<<'CODE'
|
||||
+var_dump(file_get_contents('php://input'));
|
||||
+CODE;
|
||||
+
|
||||
+php_cli_server_start($serverCode, null, []);
|
||||
+
|
||||
+$options = [
|
||||
+ "http" => [
|
||||
+ "method" => "POST",
|
||||
+ "header" => "Content-Type: application/x-www-form-urlencoded",
|
||||
+ "content" => "AAAAA",
|
||||
+ ],
|
||||
+];
|
||||
+$context = stream_context_create($options);
|
||||
+
|
||||
+echo file_get_contents("http://" . PHP_CLI_SERVER_ADDRESS . "/", false, $context);
|
||||
+
|
||||
+$options = [
|
||||
+ "http" => [
|
||||
+ "method" => "POST",
|
||||
+ ],
|
||||
+];
|
||||
+$context = stream_context_create($options);
|
||||
+
|
||||
+echo file_get_contents("http://" . PHP_CLI_SERVER_ADDRESS . "/", false, $context);
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+string(5) "AAAAA"
|
||||
+string(0) ""
|
||||
--
|
||||
2.47.0
|
||||
|
||||
From d8d682d3d6a4d027771806c8fc77128cae078d29 Mon Sep 17 00:00:00 2001
|
||||
From: Remi Collet <remi@remirepo.net>
|
||||
Date: Fri, 22 Nov 2024 08:58:10 +0100
|
||||
Subject: [PATCH 7/7] NEWS for 8.1.31 backports
|
||||
|
||||
(cherry picked from commit 22bdb43da0ecd6e72d63b63aa6c1f3a25d1bca3a)
|
||||
---
|
||||
NEWS | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/NEWS b/NEWS
|
||||
index 62616d6312d..f600d6aea65 100644
|
||||
--- a/NEWS
|
||||
+++ b/NEWS
|
||||
@@ -1,6 +1,30 @@
|
||||
PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
|
||||
+Backported from 8.1.31
|
||||
+
|
||||
+- CLI:
|
||||
+ . Fixed bug GHSA-4w77-75f9-2c8w (Heap-Use-After-Free in sapi_read_post_data
|
||||
+ Processing in CLI SAPI Interface). (nielsdos)
|
||||
+
|
||||
+- LDAP:
|
||||
+ . Fixed bug GHSA-g665-fm4p-vhff (OOB access in ldap_escape). (CVE-2024-8932)
|
||||
+ (nielsdos)
|
||||
+
|
||||
+- PDO DBLIB:
|
||||
+ . Fixed bug GHSA-5hqh-c84r-qjcv (Integer overflow in the dblib quoter causing
|
||||
+ OOB writes). (CVE-2024-11236) (nielsdos)
|
||||
+
|
||||
+- PDO Firebird:
|
||||
+ . Fixed bug GHSA-5hqh-c84r-qjcv (Integer overflow in the firebird quoter
|
||||
+ causing OOB writes). (CVE-2024-11236) (nielsdos)
|
||||
+
|
||||
+- Streams:
|
||||
+ . Fixed bug GHSA-c5f2-jwm7-mmq2 (Configuring a proxy in a stream context
|
||||
+ might allow for CRLF injection in URIs). (CVE-2024-11234) (Jakub Zelenka)
|
||||
+ . Fixed bug GHSA-r977-prxv-hc43 (Single byte overread with
|
||||
+ convert.quoted-printable-decode filter). (CVE-2024-11233) (nielsdos)
|
||||
+
|
||||
Backported from 8.1.30
|
||||
|
||||
- CGI:
|
||||
--
|
||||
2.47.0
|
||||
|
||||
256
SOURCES/php-ghsa-www2-q4fc-65wf.patch
Normal file
256
SOURCES/php-ghsa-www2-q4fc-65wf.patch
Normal file
@ -0,0 +1,256 @@
|
||||
From 3e9d47f6cc04c9978bb384e2d487cf28d37889f0 Mon Sep 17 00:00:00 2001
|
||||
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
|
||||
Date: Sat, 6 Sep 2025 21:55:13 +0200
|
||||
Subject: [PATCH 4/5] Fix GHSA-www2-q4fc-65wf
|
||||
|
||||
(cherry picked from commit ed70b1ea43a9b7ffa2f53b3e5d6ba403f37ae81c)
|
||||
(cherry picked from commit 52c5762a902e8731b7068ded027fbd780f5a1991)
|
||||
---
|
||||
ext/standard/basic_functions.c | 12 ++--
|
||||
ext/standard/dns.c | 6 +-
|
||||
ext/standard/dns_win32.c | 6 +-
|
||||
.../tests/network/ghsa-www2-q4fc-65wf.phpt | 71 +++++++++++++++++++
|
||||
ext/standard/tests/network/ip_x86_64.phpt | 2 +-
|
||||
5 files changed, 84 insertions(+), 13 deletions(-)
|
||||
create mode 100644 ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt
|
||||
|
||||
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
|
||||
index 64f27ef5af7..45746335689 100644
|
||||
--- a/ext/standard/basic_functions.c
|
||||
+++ b/ext/standard/basic_functions.c
|
||||
@@ -3960,7 +3960,7 @@ PHP_NAMED_FUNCTION(php_inet_pton)
|
||||
char buffer[17];
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
- Z_PARAM_STRING(address, address_len)
|
||||
+ Z_PARAM_PATH(address, address_len)
|
||||
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
@@ -3998,7 +3998,7 @@ PHP_FUNCTION(ip2long)
|
||||
#endif
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
- Z_PARAM_STRING(addr, addr_len)
|
||||
+ Z_PARAM_PATH(addr, addr_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
#ifdef HAVE_INET_PTON
|
||||
@@ -5714,8 +5714,8 @@ PHP_FUNCTION(getservbyname)
|
||||
struct servent *serv;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(2, 2)
|
||||
- Z_PARAM_STRING(name, name_len)
|
||||
- Z_PARAM_STRING(proto, proto_len)
|
||||
+ Z_PARAM_PATH(name, name_len)
|
||||
+ Z_PARAM_PATH(proto, proto_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
|
||||
@@ -5759,7 +5759,7 @@ PHP_FUNCTION(getservbyport)
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(2, 2)
|
||||
Z_PARAM_LONG(port)
|
||||
- Z_PARAM_STRING(proto, proto_len)
|
||||
+ Z_PARAM_PATH(proto, proto_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
serv = getservbyport(htons((unsigned short) port), proto);
|
||||
@@ -5783,7 +5783,7 @@ PHP_FUNCTION(getprotobyname)
|
||||
struct protoent *ent;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
- Z_PARAM_STRING(name, name_len)
|
||||
+ Z_PARAM_PATH(name, name_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
ent = getprotobyname(name);
|
||||
diff --git a/ext/standard/dns.c b/ext/standard/dns.c
|
||||
index dc85c45e1d7..698ad4f661d 100644
|
||||
--- a/ext/standard/dns.c
|
||||
+++ b/ext/standard/dns.c
|
||||
@@ -377,7 +377,7 @@ PHP_FUNCTION(dns_check_record)
|
||||
#endif
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||
- Z_PARAM_STRING(hostname, hostname_len)
|
||||
+ Z_PARAM_PATH(hostname, hostname_len)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_STRING(rectype, rectype_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
@@ -825,7 +825,7 @@ PHP_FUNCTION(dns_get_record)
|
||||
zend_bool raw = 0;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 5)
|
||||
- Z_PARAM_STRING(hostname, hostname_len)
|
||||
+ Z_PARAM_PATH(hostname, hostname_len)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_LONG(type_param)
|
||||
Z_PARAM_ZVAL(authns)
|
||||
@@ -1065,7 +1065,7 @@ PHP_FUNCTION(dns_get_mx)
|
||||
#endif
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(2, 3)
|
||||
- Z_PARAM_STRING(hostname, hostname_len)
|
||||
+ Z_PARAM_PATH(hostname, hostname_len)
|
||||
Z_PARAM_ZVAL(mx_list)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(weight_list)
|
||||
diff --git a/ext/standard/dns_win32.c b/ext/standard/dns_win32.c
|
||||
index 466d927ea3e..f5b6e03a128 100644
|
||||
--- a/ext/standard/dns_win32.c
|
||||
+++ b/ext/standard/dns_win32.c
|
||||
@@ -50,7 +50,7 @@ PHP_FUNCTION(dns_get_mx) /* {{{ */
|
||||
DNS_STATUS status; /* Return value of DnsQuery_A() function */
|
||||
PDNS_RECORD pResult, pRec; /* Pointer to DNS_RECORD structure */
|
||||
|
||||
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
|
||||
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "pz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ PHP_FUNCTION(dns_check_record)
|
||||
DNS_STATUS status; /* Return value of DnsQuery_A() function */
|
||||
PDNS_RECORD pResult; /* Pointer to DNS_RECORD structure */
|
||||
|
||||
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
|
||||
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ PHP_FUNCTION(dns_get_record)
|
||||
int type, type_to_fetch, first_query = 1, store_results = 1;
|
||||
zend_bool raw = 0;
|
||||
|
||||
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b",
|
||||
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|lz!z!b",
|
||||
&hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
diff --git a/ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt b/ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt
|
||||
new file mode 100644
|
||||
index 00000000000..b14c8ca719b
|
||||
--- /dev/null
|
||||
+++ b/ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt
|
||||
@@ -0,0 +1,71 @@
|
||||
+--TEST--
|
||||
+GHSA-www2-q4fc-65wf
|
||||
+--DESCRIPTION--
|
||||
+This is a ZPP test but *keep* this as it is security-sensitive!
|
||||
+--FILE--
|
||||
+<?php
|
||||
+try {
|
||||
+ dns_check_record("\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ dns_get_mx("\0", $out);
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ dns_get_record("\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ getprotobyname("\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ getservbyname("\0", "tcp");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ getservbyname("x", "tcp\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ getservbyport(0, "tcp\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ inet_pton("\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+try {
|
||||
+ ip2long("\0");
|
||||
+} catch (ValueError $e) {
|
||||
+ echo $e->getMessage(), "\n";
|
||||
+}
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Warning: dns_check_record() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: dns_get_mx() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: dns_get_record() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: getprotobyname() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: getservbyname() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: getservbyname() expects parameter 2 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: getservbyport() expects parameter 2 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: inet_pton() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
+Warning: ip2long() expects parameter 1 to be a valid path, string given in %s
|
||||
+
|
||||
diff --git a/ext/standard/tests/network/ip_x86_64.phpt b/ext/standard/tests/network/ip_x86_64.phpt
|
||||
index 3c530b83713..2158e289bae 100644
|
||||
--- a/ext/standard/tests/network/ip_x86_64.phpt
|
||||
+++ b/ext/standard/tests/network/ip_x86_64.phpt
|
||||
@@ -54,7 +54,7 @@ bool(false)
|
||||
bool(false)
|
||||
int(1869573999)
|
||||
|
||||
-Warning: ip2long() expects parameter 1 to be string, array given in %sip_x86_64.php on line %d
|
||||
+Warning: ip2long() expects parameter 1 to be a valid path, array given in %sip_x86_64.php on line %d
|
||||
NULL
|
||||
|
||||
Warning: long2ip() expects exactly 1 parameter, 0 given in %sip_x86_64.php on line %d
|
||||
--
|
||||
2.52.0
|
||||
|
||||
From f2cb8ad2342a7b58b8e467ed60233bb9be30f42e Mon Sep 17 00:00:00 2001
|
||||
From: Remi Collet <remi@remirepo.net>
|
||||
Date: Thu, 18 Dec 2025 07:17:43 +0100
|
||||
Subject: [PATCH 5/5] NEWS from 8.1.34
|
||||
|
||||
(cherry picked from commit 52b3bdaa74078e4ea8abd9696cdbdc35a8091446)
|
||||
---
|
||||
NEWS | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/NEWS b/NEWS
|
||||
index a9dd716c003..f212d40b2e9 100644
|
||||
--- a/NEWS
|
||||
+++ b/NEWS
|
||||
@@ -1,6 +1,16 @@
|
||||
PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
|
||||
+Backported from 8.1.34
|
||||
+
|
||||
+- Standard:
|
||||
+ . Fixed GHSA-www2-q4fc-65wf (Null byte termination in dns_get_record()).
|
||||
+ (ndossche)
|
||||
+ . Fixed GHSA-h96m-rvf9-jgm2 (Heap buffer overflow in array_merge()).
|
||||
+ (CVE-2025-14178) (ndossche)
|
||||
+ . Fixed GHSA-3237-qqm7-mfv7 (Information Leak of Memory in getimagesize).
|
||||
+ (CVE-2025-14177) (ndossche)
|
||||
+
|
||||
Backported from 8.1.33
|
||||
|
||||
- PGSQL:
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
Summary: PHP scripting language for creating dynamic web sites
|
||||
Name: php
|
||||
Version: %{upver}%{?rcver:~%{rcver}}
|
||||
Release: 2%{?dist}
|
||||
Release: 3%{?dist}
|
||||
# All files licensed under PHP version 3.01, except
|
||||
# Zend is licensed under Zend
|
||||
# TSRM is licensed under BSD
|
||||
@ -122,6 +122,23 @@ Patch210: php-cve-2024-8925.patch
|
||||
Patch211: php-cve-2024-8926.patch
|
||||
Patch212: php-cve-2024-8927.patch
|
||||
Patch213: php-cve-2024-9026.patch
|
||||
Patch214: php-cve-2024-11236.patch
|
||||
Patch215: php-cve-2024-11234.patch
|
||||
Patch216: php-cve-2024-8932.patch
|
||||
Patch217: php-cve-2024-11233.patch
|
||||
Patch218: php-ghsa-4w77-75f9-2c8w.patch
|
||||
Patch219: php-cve-2024-8929.patch
|
||||
Patch220: php-cve-2025-1217.patch
|
||||
Patch221: php-cve-2025-1734.patch
|
||||
Patch222: php-cve-2025-1861.patch
|
||||
Patch223: php-cve-2025-1736.patch
|
||||
Patch224: php-cve-2025-1219.patch
|
||||
Patch225: php-cve-2025-6491.patch
|
||||
Patch226: php-cve-2025-1220.patch
|
||||
Patch227: php-cve-2025-1735.patch
|
||||
Patch228: php-cve-2025-14177.patch
|
||||
Patch229: php-cve-2025-14178.patch
|
||||
Patch230: php-ghsa-www2-q4fc-65wf.patch
|
||||
|
||||
# Fixes for tests (300+)
|
||||
# Factory is droped from system tzdata
|
||||
@ -745,6 +762,23 @@ in pure PHP.
|
||||
%patch -P211 -p1 -b .cve8926
|
||||
%patch -P212 -p1 -b .cve8927
|
||||
%patch -P213 -p1 -b .cve9026
|
||||
%patch -P214 -p1 -b .cve11236
|
||||
%patch -P215 -p1 -b .cve11234
|
||||
%patch -P216 -p1 -b .cve8932
|
||||
%patch -P217 -p1 -b .cve11233
|
||||
%patch -P218 -p1 -b .ghsa4w77
|
||||
%patch -P219 -p1 -b .cve8929
|
||||
%patch -P220 -p1 -b .cve1217
|
||||
%patch -P221 -p1 -b .cve1734
|
||||
%patch -P222 -p1 -b .cve1861
|
||||
%patch -P223 -p1 -b .cve1736
|
||||
%patch -P224 -p1 -b .cve1219
|
||||
%patch -P225 -p1 -b .cve6491
|
||||
%patch -P226 -p1 -b .cve1220
|
||||
%patch -P227 -p1 -b .cve1735
|
||||
%patch -P228 -p1 -b .cve14177
|
||||
%patch -P229 -p1 -b .cve14178
|
||||
%patch -P230 -p1 -b .ghsawwww2
|
||||
|
||||
# Fixes for tests
|
||||
%patch -P300 -p1 -b .datetests
|
||||
@ -1534,6 +1568,38 @@ systemctl try-restart php-fpm.service >/dev/null 2>&1 || :
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Jan 19 2026 Remi Collet <rcollet@redhat.com> - 7.4.33-3
|
||||
- Fix Heap-Use-After-Free in sapi_read_post_data Processing in CLI SAPI Interface
|
||||
GHSA-4w77-75f9-2c8w
|
||||
- Fix Configuring a proxy in a stream context might allow for CRLF injection in URIs
|
||||
CVE-2024-11234
|
||||
- Fix Single byte overread with convert.quoted-printable-decode filter
|
||||
CVE-2024-11233
|
||||
- Fix Leak partial content of the heap through heap buffer over-read
|
||||
CVE-2024-8929
|
||||
- Fix libxml streams use wrong `content-type` header when requesting a redirected resource
|
||||
CVE-2025-1219
|
||||
- Fix Stream HTTP wrapper header check might omit basic auth header
|
||||
CVE-2025-1736
|
||||
- Fix Stream HTTP wrapper truncate redirect location to 1024 bytes
|
||||
CVE-2025-1861
|
||||
- Fix Streams HTTP wrapper does not fail for headers without colon
|
||||
CVE-2025-1734
|
||||
- Fix Header parser of `http` stream wrapper does not handle folded headers
|
||||
CVE-2025-1217
|
||||
- Fix pgsql extension does not check for errors during escaping
|
||||
CVE-2025-1735
|
||||
- Fix NULL Pointer Dereference in PHP SOAP Extension via Large XML Namespace Prefix
|
||||
CVE-2025-6491
|
||||
- Fix Null byte termination in hostnames
|
||||
CVE-2025-1220
|
||||
- Fix Null byte termination in dns_get_record()
|
||||
GHSA-www2-q4fc-65wf
|
||||
- Fix Heap buffer overflow in array_merge()
|
||||
CVE-2025-14178
|
||||
- Fix Information Leak of Memory in getimagesize
|
||||
CVE-2025-14177
|
||||
|
||||
* Wed Nov 13 2024 Remi Collet <rcollet@redhat.com> - 7.4.33-2
|
||||
- fix low/moderate CVEs
|
||||
RHEL-66589
|
||||
|
||||
Loading…
Reference in New Issue
Block a user