summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--failed.txt12
-rw-r--r--php-cve-2024-11233.patch67
-rw-r--r--php-cve-2024-11234.patch118
-rw-r--r--php-cve-2024-11236.patch117
-rw-r--r--php-cve-2024-8929.patch2301
-rw-r--r--php-cve-2024-8932.patch130
-rw-r--r--php-ghsa-4w77-75f9-2c8w.patch133
-rw-r--r--php80.spec36
8 files changed, 2907 insertions, 7 deletions
diff --git a/failed.txt b/failed.txt
index 6e6234c..1ed4a9f 100644
--- a/failed.txt
+++ b/failed.txt
@@ -1,11 +1,13 @@
-===== 8.0.30-9 (2024-09-26)
+===== 8.0.30-10 (2024-11-22)
$ grep -ar 'Tests failed' /var/lib/mock/*/build.log
/var/lib/mock/el8a80/build.log:Tests failed : 3
/var/lib/mock/el8x80/build.log:Tests failed : 3
-/var/lib/mock/el9a80/build.log:Tests failed : 2
-/var/lib/mock/el9x80/build.log:Tests failed : 2
+/var/lib/mock/el9a80/build.log:Tests failed : 3
+/var/lib/mock/el9x80/build.log:Tests failed : 3
+/var/lib/mock/el10a80/build.log:Tests failed : 3
+/var/lib/mock/el10x80/build.log:Tests failed : 3
/var/lib/mock/fc39a80/build.log:Tests failed : 2
/var/lib/mock/fc39x80/build.log:Tests failed : 2
/var/lib/mock/fc40a80/build.log:Tests failed : 3
@@ -19,9 +21,9 @@ el8:
3 openssl_open() tests [ext/openssl/tests/openssl_open_basic.phpt]
all:
3 openssl_private_decrypt() tests [ext/openssl/tests/openssl_private_decrypt_basic.phpt]
-fc39, fc40, fc41, el9:
+fc39, fc40, fc41, el9, el10:
3 openssl_error_string() tests (OpenSSL >= 3.0) [ext/openssl/tests/openssl_error_string_basic_openssl3.phpt]
-fc40, fc41:
+fc40, fc41, el9, el10:
3 openssl_x509_parse() tests [ext/openssl/tests/openssl_x509_parse_basic.phpt]
diff --git a/php-cve-2024-11233.patch b/php-cve-2024-11233.patch
new file mode 100644
index 0000000..d372560
--- /dev/null
+++ b/php-cve-2024-11233.patch
@@ -0,0 +1,67 @@
+From 2cee10a1206f5bc7724232d3988be2cfcb0bc9df Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 8 Nov 2024 22:04:21 +0100
+Subject: [PATCH 5/8] Fix GHSA-r977-prxv-hc43
+
+Move the bound check upwards. Since this doesn't generate output we can
+check the bound first.
+
+(cherry picked from commit 81030c9bbb5cd2e740b8398bb7212df9709f0274)
+---
+ ext/standard/filters.c | 7 ++++---
+ ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt | 12 ++++++++++++
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+ create mode 100644 ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt
+
+diff --git a/ext/standard/filters.c b/ext/standard/filters.c
+index d5e65644439..ff0bda0cbcd 100644
+--- a/ext/standard/filters.c
++++ b/ext/standard/filters.c
+@@ -996,6 +996,9 @@ static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *ins
+ } break;
+
+ case 5: {
++ if (icnt == 0) {
++ goto out;
++ }
+ if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
+ /* auto-detect soft line breaks, found network line break */
+ lb_cnt = lb_ptr = 0;
+@@ -1009,15 +1012,13 @@ static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *ins
+ /* soft line break */
+ lb_cnt = lb_ptr = 0;
+ scan_stat = 0;
+- } else if (icnt > 0) {
++ } else {
+ if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
+ lb_cnt++;
+ ps++, icnt--;
+ } else {
+ scan_stat = 6; /* no break for short-cut */
+ }
+- } else {
+- goto out;
+ }
+ } break;
+
+diff --git a/ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt b/ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt
+new file mode 100644
+index 00000000000..8fdcce8ff22
+--- /dev/null
++++ b/ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt
+@@ -0,0 +1,12 @@
++--TEST--
++GHSA-r977-prxv-hc43: Single byte overread with convert.quoted-printable-decode filter
++--FILE--
++<?php
++
++$input_data = str_repeat('A', 8189)."X=\r";
++$filter_url = "php://filter/convert.quoted-printable-decode/resource=data:," . urlencode($input_data);
++var_dump(file_get_contents($filter_url));
++
++?>
++--EXPECT--
++string(8190) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX"
+--
+2.47.0
+
diff --git a/php-cve-2024-11234.patch b/php-cve-2024-11234.patch
new file mode 100644
index 0000000..59afbcc
--- /dev/null
+++ b/php-cve-2024-11234.patch
@@ -0,0 +1,118 @@
+From bc1f192102dd8cbda028e40aa31604c4885d387c 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/8] Fix GHSA-c5f2-jwm7-mmq2: stream HTTP fulluri CRLF
+ injection
+
+(cherry picked from commit 426a6d4539ebee34879ac5de857036bb6ff0e732)
+---
+ 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 45677c396ac..6859a4e5181 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -184,6 +184,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)
+@@ -203,6 +208,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);
++ zend_string_release(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
+@@ -383,12 +395,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..e7dd194dbbe
+--- /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
+
+From 8d130e16fbfda7d154fedfa0f1ff1d5ad5e26815 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Fri, 22 Nov 2024 09:41:12 +0100
+Subject: [PATCH 8/8] fix transport_string release
+
+---
+ ext/standard/http_fopen_wrapper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
+index 6859a4e5181..40e6f3dd4c3 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -211,7 +211,7 @@ 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);
+- zend_string_release(transport_string);
++ efree(transport_string);
+ return NULL;
+ }
+
+--
+2.47.0
+
diff --git a/php-cve-2024-11236.patch b/php-cve-2024-11236.patch
new file mode 100644
index 0000000..d793ed6
--- /dev/null
+++ b/php-cve-2024-11236.patch
@@ -0,0 +1,117 @@
+From 5d9e54065ed18c51e4f25d8900635f90810c7394 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/8] Fix GHSA-5hqh-c84r-qjcv: Integer overflow in the dblib
+ quoter causing OOB writes
+
+(cherry picked from commit d9baa9fed8c3ba692a36b388c0c7762e5102e2e0)
+---
+ 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 7f160a402f7..d7d0901ea1a 100644
+--- a/ext/pdo_dblib/dblib_driver.c
++++ b/ext/pdo_dblib/dblib_driver.c
+@@ -152,6 +152,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) {
+@@ -166,7 +167,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;
+ }
+
+@@ -174,6 +175,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 b4f73be75dbdde970a18cc7a636898b10400fb3f 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/8] Fix GHSA-5hqh-c84r-qjcv: Integer overflow in the firebird
+ quoter causing OOB writes
+
+(cherry picked from commit 69c5f68fdc3deed9ebce2cc44b4bf5e0c47cd28f)
+---
+ 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 e0a424c56ab..fb697978503 100644
+--- a/ext/pdo_firebird/firebird_driver.c
++++ b/ext/pdo_firebird/firebird_driver.c
+@@ -663,7 +663,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;
+
+@@ -678,6 +678,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
+
diff --git a/php-cve-2024-8929.patch b/php-cve-2024-8929.patch
new file mode 100644
index 0000000..82768c7
--- /dev/null
+++ b/php-cve-2024-8929.patch
@@ -0,0 +1,2301 @@
+From 0d3ccf4cc54d3844bc9d1c8f6bdcd36180752a2c Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Tue, 8 Oct 2024 16:17:53 +0100
+Subject: [PATCH 1/6] Fix GHSA-h35g-vwh6-m678: Mysqlnd - various heap buffer
+ over-reads
+
+This fixes issues causing buffer over-read that leak heap content:
+- RESP packet field default left over for COM_LIST
+- RESP packet upsert filename
+- OK packet message
+- RESP packet for stmt row data
+ - ps_fetch_from_1_to_8_bytes
+ - ps_fetch_float
+ - ps_fetch_double
+ - ps_fetch_time
+ - ps_fetch_date
+ - ps_fetch_datetime
+ - ps_fetch_string
+ - ps_fetch_bit
+- RESP packet for query row data (just possible overflow on 32bit)
+
+It also adds various protocol tests using a new fake server.
+
+(cherry picked from commit 2f5aa9f9d150ca56e356f3ca9acf9d530108cb08)
+---
+ ext/mysqli/tests/fake_server.inc | 856 ++++++++++++++++++
+ .../ghsa-h35g-vwh6-m678-auth-message.phpt | 38 +
+ ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt | 47 +
+ .../tests/ghsa-h35g-vwh6-m678-filename.phpt | 43 +
+ ...hsa-h35g-vwh6-m678-query-len-overflow.phpt | 48 +
+ .../ghsa-h35g-vwh6-m678-stmt-row-bit.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-date.phpt | 53 ++
+ ...ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-double.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-float.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-int.phpt | 53 ++
+ ...ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-string.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-time.phpt | 53 ++
+ .../tests/protocol_query_row_fetch_data.phpt | 74 ++
+ .../tests/protocol_stmt_row_fetch_data.phpt | 91 ++
+ ext/mysqlnd/mysqlnd_ps_codec.c | 69 ++
+ ext/mysqlnd/mysqlnd_result.c | 2 +-
+ ext/mysqlnd/mysqlnd_wireprotocol.c | 71 +-
+ 19 files changed, 1794 insertions(+), 22 deletions(-)
+ create mode 100644 ext/mysqli/tests/fake_server.inc
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt
+ create mode 100644 ext/mysqli/tests/protocol_query_row_fetch_data.phpt
+ create mode 100644 ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt
+
+diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc
+new file mode 100644
+index 00000000000..b02fabc584c
+--- /dev/null
++++ b/ext/mysqli/tests/fake_server.inc
+@@ -0,0 +1,856 @@
++<?php
++
++function my_mysqli_data_fields(): array
++{
++ return [
++ 'intval' => [
++ 'type' => '03',
++ 'charset' => '3f00',
++ 'length' => '0b000000',
++ 'flags' => '0110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '080000',
++ 'query_data_value' => '023134',
++ 'stmt_data_packet_length' => '0b0000',
++ 'stmt_data_value' => '0e000000'
++ ],
++ 'fltval' => [
++ 'type' => '04',
++ 'charset' => '3f00',
++ 'length' => '0c000000',
++ 'flags' => '0110',
++ 'decimal' => '1f',
++ 'query_data_packet_length' => '090000',
++ 'query_data_value' => '03322e33',
++ 'stmt_data_packet_length' => '0b0000',
++ 'stmt_data_value' => '33331340',
++ ],
++ 'dblval' => [
++ 'type' => '05',
++ 'charset' => '3f00',
++ 'length' => '16000000',
++ 'flags' => '0110',
++ 'decimal' => '1f',
++ 'query_data_packet_length' => '090000',
++ 'query_data_value' => '03312e32',
++ 'stmt_data_packet_length' => '0f0000',
++ 'stmt_data_value' => '333333333333f33f'
++ ],
++ 'datval' => [
++ 'type' => '0a',
++ 'charset' => '3f00',
++ 'length' => '0a000000',
++ 'flags' => '8110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '100000',
++ 'query_data_value' => '0a323031342d31322d3135',
++ 'stmt_data_packet_length' => '0c0000',
++ 'stmt_data_value' => '04de070c0f'
++ ],
++ 'timval' => [
++ 'type' => '0b',
++ 'charset' => '3f00',
++ 'length' => '0a000000',
++ 'flags' => '8110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '0e0000',
++ 'query_data_value' => '0831333a30303a3032',
++ 'stmt_data_packet_length' => '100000',
++ 'stmt_data_value' => '080000000000150801'
++ ],
++ 'dtival' => [
++ 'type' => '0c',
++ 'charset' => '3f00',
++ 'length' => '13000000',
++ 'flags' => '8110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '190000',
++ 'query_data_value' => '13323031342d31322d31362031333a30303a3031',
++ 'stmt_data_packet_length' => '0f0000',
++ 'stmt_data_value' => '07de070c100d0001'
++ ],
++ 'bitval' => [
++ 'type' => '10',
++ 'charset' => '3f00',
++ 'length' => '40000000',
++ 'flags' => '2110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '0e0000',
++ 'query_data_value' => '080808080808080808',
++ 'stmt_data_packet_length' => '100000',
++ 'stmt_data_value' => '080808080808080808'
++ ],
++ 'strval' => [
++ 'type' => 'fd',
++ 'charset' => 'e000',
++ 'length' => 'c8000000',
++ 'flags' => '0110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '0a0000',
++ 'query_data_value' => '0474657374',
++ 'stmt_data_packet_length' => '0c0000',
++ 'stmt_data_value' => '0474657374'
++ ],
++ ];
++}
++
++function my_mysqli_data_field(string $field): array
++{
++ $fields = my_mysqli_data_fields();
++ if (!isset($fields[$field])) {
++ throw new Exception("Unknown field $field");
++ }
++ return $fields[$field];
++}
++
++
++
++class my_mysqli_fake_packet_item
++{
++ public function __construct(public string|null $name, public string $value, public bool $is_hex = true)
++ {
++ }
++}
++
++class my_mysqli_fake_packet
++{
++ private array $data = array();
++
++ public function __get(string $name)
++ {
++ foreach ($this->data as $item) {
++ if ($item->name === $name) {
++ return $item->value;
++ }
++ }
++ return null;
++ }
++
++ public function __set(string $name, string|my_mysqli_fake_packet_item $value)
++ {
++ if ($value instanceof my_mysqli_fake_packet_item) {
++ if ($value->name === null) {
++ $value->name = $name;
++ }
++ } else {
++ $value = new my_mysqli_fake_packet_item($name, $value, true);
++ }
++
++ for ($i = 0; $i < count($this->data); $i++) {
++ if ($this->data[$i]->name === $name) {
++ $this->data[$i] = $value;
++ return;
++ }
++ }
++
++ $this->data[] = $value;
++ }
++
++ public function to_bytes(): string
++ {
++ $bytes = '';
++ foreach ($this->data as $item) {
++ $bytes .= $item->is_hex ? hex2bin($item->value) : $item->value;
++ }
++ return $bytes;
++ }
++}
++
++class my_mysqli_fake_packet_generator
++{
++ public static function create_packet_item(int|string $value, bool $is_hex = false, string $format = 'v'): my_mysqli_fake_packet_item
++ {
++ if (is_string($value)) {
++ $packed_value = $value;
++ } else {
++ $packed_value = pack($format, $value);
++ }
++ return new my_mysqli_fake_packet_item(null, $packed_value, $is_hex);
++ }
++
++ public function server_ok(): my_mysqli_fake_packet
++ {
++ $packet = new my_mysqli_fake_packet();
++ $packet->packet_length = "070000";
++ $packet->packet_number = "02";
++ $packet->header = "00"; // OK
++ $packet->affected_rows = "00";
++ $packet->last_insert_id = "00";
++ $packet->server_status = "0200";
++ $packet->warning_count = "0000";
++ return $packet;
++ }
++
++ public function server_greetings(): my_mysqli_fake_packet
++ {
++ $packet = new my_mysqli_fake_packet();
++ $packet->packet_length = "580000";
++ $packet->packet_number = "00";
++ $packet->proto_version = "0a";
++ $packet->version = self::create_packet_item('5.5.5-10.5.18-MariaDB' . chr(0));
++ $packet->thread_id = "03000000";
++ $packet->salt = "473e3f6047257c67";
++ $packet->filler = "00";
++ $packet->server_capabilities = self::create_packet_item(0b1111011111111110);
++ $packet->server_character_set = "08";
++ $packet->server_status = self::create_packet_item(0b000000000000010);
++ $packet->extended_server_capabilities = self::create_packet_item(0b1000000111111111);
++ $packet->auth_plugin = "15";
++ $packet->unused = "000000000000";
++ $packet->mariadb_extended_server_capabilities = self::create_packet_item(0b1111, false, 'V');
++ $packet->mariadb_extended_server_capabilities_salt = "6c6b55463f49335f686c643100";
++ $packet->mariadb_extended_server_capabilities_auth_plugin = self::create_packet_item('mysql_native_password');
++
++ return $packet;
++ }
++
++ public function server_tabular_query_response(): array
++ {
++ $qr1 = new my_mysqli_fake_packet();
++ $qr1->packet_length = "010000";
++ $qr1->packet_number = "01";
++ $qr1->field_count = "01";
++
++ $qr2 = new my_mysqli_fake_packet();
++ $qr2->packet_length = "190000";
++ $qr2->packet_number = "02";
++ $qr2->catalog_length_plus_name = "0164";
++ $qr2->db_length_plus_name = "0164";
++ $qr2->table_length_plus_name = "0164";
++ $qr2->original_t = "0164";
++ $qr2->name_length_plus_name = "0164";
++ $qr2->original_n = "0164";
++ $qr2->canary = "0c";
++ $qr2->charset = "3f00";
++ $qr2->length = "0b000000";
++ $qr2->type = "03";
++ $qr2->flags = "0350";
++ $qr2->decimals = "000000";
++
++ $qr3 = new my_mysqli_fake_packet();
++ $qr3->full = "05000003fe00002200";
++
++ $qr4 = new my_mysqli_fake_packet();
++ $qr4->full = "0400000401350174";
++
++ $qr5 = new my_mysqli_fake_packet();
++ $qr5->full = "05000005fe00002200";
++
++ return [$qr1, $qr2, $qr3, $qr4, $qr5];
++ }
++
++ public function server_upsert_query_response(): array
++ {
++ $qr1 = new my_mysqli_fake_packet();
++ $qr1->packet_length = "010000";
++ $qr1->packet_number = "01";
++ $qr1->field_count = "00"; // UPSERT
++ $qr1->affected_rows = "00";
++ $qr1->affected_rows = "00";
++ $qr1->last_insert_id = "00";
++ $qr1->server_status = "0000";
++ $qr1->warning_count = "0000";
++ $qr1->len = "01";
++ $qr1->filename = "65";
++ $qr1->packet_length = sprintf("%02x0000", strlen($qr1->to_bytes())-4);
++
++ return [$qr1];
++ }
++
++ public function server_stmt_prepare_response_start($num_field): my_mysqli_fake_packet
++ {
++ $pr1 = new my_mysqli_fake_packet();
++ $pr1->packet_length = "0c0000";
++ $pr1->packet_number = "01";
++ $pr1->response_code = '00'; // OK
++ $pr1->statement_id = '01000000';
++ $pr1->num_fields = $num_field;
++ $pr1->num_params = '0000';
++ $pr1->filler = '00';
++ $pr1->warnings = '0000';
++
++ return $pr1;
++ }
++
++ public function server_stmt_prepare_response_end($packer_number): my_mysqli_fake_packet
++ {
++ $pr3 = new my_mysqli_fake_packet();
++ $pr3->packet_length = "050000";
++ $pr3->packet_number = $packer_number;
++ $pr3->packet_type = 'fe'; // EOF
++ $pr3->warnings = '0000';
++ $pr3->server_status = '0200';
++
++ return $pr3;
++ }
++
++ public function server_stmt_prepare_items_response(): array
++ {
++ $pr1 = $this->server_stmt_prepare_response_start('0100');
++
++ $pr2 = new my_mysqli_fake_packet();
++ $pr2->packet_length = "300000";
++ $pr2->packet_number = "02";
++ $pr2->catalogue_len = '03';
++ $pr2->catalogue = '646566'; // def
++ $pr2->db_len = '08';
++ $pr2->db = '7068705f74657374'; // php_test
++ $pr2->table_len = '05';
++ $pr2->table = '6974656d73'; // items
++ $pr2->orig_table_len = '05';
++ $pr2->orig_table = '6974656d73'; // items
++ $pr2->name_len = '04';
++ $pr2->name = '6974656d';
++ $pr2->orig_name_len = '04';
++ $pr2->orig_name = '6974656d';
++ $pr2->something = '0c';
++ $pr2->charset = 'e000';
++ $pr2->length = 'c8000000';
++ $pr2->field_type = 'fd'; // FIELD_TYPE_VAR_STRING
++ $pr2->flags = '0110';
++ $pr2->decimal = '00';
++ $pr2->padding = '0000';
++
++ $pr3 = $this->server_stmt_prepare_response_end('03');
++
++ return [$pr1, $pr2, $pr3];
++ }
++
++ public function server_stmt_prepare_data_response_field($packet_number, $field_name): my_mysqli_fake_packet
++ {
++ if (strlen($field_name) != 6) {
++ throw new Exception("Invalid field length - only 6 is allowed");
++ }
++
++ $field = my_mysqli_data_field($field_name);
++
++ $pr = new my_mysqli_fake_packet();
++ $pr->packet_length = "320000";
++ $pr->packet_number = $packet_number;
++ $pr->catalogue_len = '03';
++ $pr->catalogue = bin2hex('def');
++ $pr->db_len = '08';
++ $pr->db = bin2hex('php_test');
++ $pr->table_len = '04';
++ $pr->table = bin2hex('data');
++ $pr->orig_table_len = '04';
++ $pr->orig_table = bin2hex('data');
++ $pr->name_len = '06';
++ $pr->name = bin2hex($field_name);
++ $pr->orig_name_len = '06';
++ $pr->orig_name = bin2hex($field_name);
++ $pr->something = '0c';
++ $pr->charset = $field['charset'];
++ $pr->length = $field['length'];
++ $pr->field_type = $field['type'];
++ $pr->flags = $field['flags'];
++ $pr->decimal = $field['decimal'];
++ $pr->padding = '0000';
++
++ return $pr;
++ }
++
++ public function server_stmt_prepare_data_response(string $field_name): array
++ {
++ $pr1 = $this->server_stmt_prepare_response_start('0200');
++
++ $pr2 = $this->server_stmt_prepare_data_response_field('02', 'strval');
++ $pr3 = $this->server_stmt_prepare_data_response_field('03', $field_name);
++
++ $pr4 = $this->server_stmt_prepare_response_end('04');
++
++ return [$pr1, $pr2, $pr3, $pr4];
++ }
++
++ public function server_stmt_execute_items_response(): array
++ {
++ $pr1 = new my_mysqli_fake_packet();
++ $pr1->packet_length = "010000";
++ $pr1->packet_number = "01";
++ $pr1->num_fields = '01';
++
++ $pr2 = new my_mysqli_fake_packet();
++ $pr2->packet_length = "300000";
++ $pr2->packet_number = "02";
++ $pr2->catalogue_len = '03';
++ $pr2->catalogue = '646566'; // def
++ $pr2->db_len = '08';
++ $pr2->db = '7068705f74657374'; // php_test
++ $pr2->table_len = '05';
++ $pr2->table = '6974656d73'; // items
++ $pr2->orig_table_len = '05';
++ $pr2->orig_table = '6974656d73'; // items
++ $pr2->name_len = '04';
++ $pr2->name = '6974656d';
++ $pr2->orig_name_len = '04';
++ $pr2->orig_name = '6974656d';
++ $pr2->something = '0c';
++ $pr2->charset = 'e000';
++ $pr2->length = 'c8000000';
++ $pr2->field_type = 'fd'; // FIELD_TYPE_VAR_STRING
++ $pr2->flags = '0110';
++ $pr2->decimal = '00';
++ $pr2->padding = '0000';
++
++ $pr3 = new my_mysqli_fake_packet();
++ $pr3->packet_length = "050000";
++ $pr3->packet_number = "03";
++ $pr3->packet_type = 'fe'; // EOF
++ $pr3->warnings = '0000';
++ $pr3->server_status = '2200';
++
++ $pr4 = new my_mysqli_fake_packet();
++ $pr4->packet_length = "070000";
++ $pr4->packet_number = "04";
++ $pr4->packet_type = '00'; // OK
++ $pr4->affected_rows = '00';
++ $pr4->row_data_len = '04';
++ $pr4->row_data = '74657374'; // item
++
++ $pr5 = new my_mysqli_fake_packet();
++ $pr5->full = '05000005fe00002200';
++
++ return [$pr1, $pr2, $pr3, $pr4, $pr5];
++ }
++
++ private function server_execute_data_response_start(string $field_name): array
++ {
++ $pr1 = new my_mysqli_fake_packet();
++ $pr1->packet_length = "010000";
++ $pr1->packet_number = "01";
++ $pr1->num_fields = '02';
++
++ $pr2 = new my_mysqli_fake_packet();
++ $pr2->packet_length = "320000";
++ $pr2->packet_number = "02";
++ $pr2->catalogue_len = '03';
++ $pr2->catalogue = '646566'; // def
++ $pr2->db_len = '08';
++ $pr2->db = '7068705f74657374'; // php_test
++ $pr2->table_len = '04';
++ $pr2->table = bin2hex('data');
++ $pr2->orig_table_len = '04';
++ $pr2->orig_table = bin2hex('data');
++ $pr2->name_len = '06';
++ $pr2->name = bin2hex('strval');
++ $pr2->orig_name_len = '06';
++ $pr2->orig_name = bin2hex('strval');
++ $pr2->something = '0c';
++ $pr2->charset = 'e000';
++ $pr2->length = 'c8000000';
++ $pr2->field_type = 'fd'; // FIELD_TYPE_VAR_STRING
++ $pr2->flags = '0110';
++ $pr2->decimal = '00';
++ $pr2->padding = '0000';
++
++ $field = my_mysqli_data_field($field_name);
++
++ $pr3 = new my_mysqli_fake_packet();
++ $pr3->packet_length = "320000";
++ $pr3->packet_number = "03";
++ $pr3->catalogue_len = '03';
++ $pr3->catalogue = '646566'; // def
++ $pr3->db_len = '08';
++ $pr3->db = '7068705f74657374'; // php_test
++ $pr3->table_len = '04';
++ $pr3->table = bin2hex('data');
++ $pr3->orig_table_len = '04';
++ $pr3->orig_table = bin2hex('data');
++ $pr3->name_len = '06';
++ $pr3->name = bin2hex($field_name);
++ $pr3->orig_name_len = '06';
++ $pr3->orig_name = bin2hex($field_name);
++ $pr3->something = '0c';
++ $pr3->charset = $field['charset'];
++ $pr3->length = $field['length'];
++ $pr3->field_type = $field['type'];
++ $pr3->flags = $field['flags'];
++ $pr3->decimal = $field['decimal'];
++ $pr3->padding = '0000';
++
++ $pr4 = new my_mysqli_fake_packet();
++ $pr4->packet_length = "050000";
++ $pr4->packet_number = "04";
++ $pr4->packet_type = 'fe'; // EOF
++ $pr4->warnings = '0000';
++ $pr4->server_status = '2200';
++
++ return [$field, $pr1, $pr2, $pr3, $pr4];
++ }
++
++ private function server_execute_data_response_end(): my_mysqli_fake_packet
++ {
++ $pr6 = new my_mysqli_fake_packet();
++ $pr6->packet_length = '050000';
++ $pr6->packet_number = "06";
++ $pr6->packet_type = 'fe'; // EOF
++ $pr6->warnings = '0000';
++ $pr6->server_status = '2200';
++
++ return $pr6;
++ }
++
++ public function server_stmt_execute_data_response(string $field_name): array
++ {
++ [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name);
++
++ $pr5 = new my_mysqli_fake_packet();
++ $pr5->packet_length = $field['stmt_data_packet_length'];
++ $pr5->packet_number = "05";
++ $pr5->packet_type = '00'; // OK
++ $pr5->affected_rows = '00';
++ $pr5->row_field1_len = '04';
++ $pr5->row_field1_data = '74657374'; // test
++ $pr5->row_field2 = $field['stmt_data_value'];
++
++ return [$pr1, $pr2, $pr3, $pr4, $pr5, $this->server_execute_data_response_end()];
++ }
++
++ public function server_query_execute_data_response(string $field_name): array
++ {
++ [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name);
++
++ $pr5 = new my_mysqli_fake_packet();
++ $pr5->packet_length = $field['query_data_packet_length'];
++ $pr5->packet_number = "05";
++ $pr5->row_field1_len = '04';
++ $pr5->row_field1_data = '74657374'; // test
++ $pr5->row_field2 = $field['query_data_value'];
++
++ return [$pr1, $pr2, $pr3, $pr4, $pr5, $this->server_execute_data_response_end()];
++ }
++}
++
++class my_mysqli_fake_server_conn
++{
++ private $conn;
++ public $packet_generator;
++
++ public function __construct($socket)
++ {
++ $this->packet_generator = new my_mysqli_fake_packet_generator();
++ $this->conn = stream_socket_accept($socket);
++ if ($this->conn) {
++ fprintf(STDERR, "[*] Connection established\n");
++ } else {
++ fprintf(STDERR, "[*] Failed to establish connection\n");
++ }
++ }
++
++ public function packets_to_bytes(array $packets): string
++ {
++ return implode('', array_map(fn($s) => $s->to_bytes(), $packets));
++ }
++
++ public function send($payload, $message = null): void
++ {
++ if ($message) {
++ fprintf(STDERR, "[*] Sending - %s: %s\n", $message, bin2hex($payload));
++ }
++ fwrite($this->conn, $payload);
++ }
++
++ public function read($bytes_len = 1024)
++ {
++ // wait 10ms to fill the buffer
++ usleep(10000);
++ $data = fread($this->conn, $bytes_len);
++ if ($data) {
++ fprintf(STDERR, "[*] Received: %s\n", bin2hex($data));
++ }
++ }
++
++ public function close()
++ {
++ fclose($this->conn);
++ }
++
++ public function send_server_greetings()
++ {
++ $this->send($this->packet_generator->server_greetings()->to_bytes(), "Server Greeting");
++ }
++
++ public function send_server_ok()
++ {
++ $this->send($this->packet_generator->server_ok()->to_bytes(), "Server OK");
++ }
++
++ public function send_server_tabular_query_response(): void
++ {
++ $packets = $this->packet_generator->server_tabular_query_response();
++ $this->send($this->packets_to_bytes($packets), "Tabular response");
++ }
++
++ public function send_server_stmt_prepare_items_response(): void
++ {
++ $packets = $this->packet_generator->server_stmt_prepare_items_response();
++ $this->send($this->packets_to_bytes($packets), "Stmt prepare items");
++ }
++
++
++ public function send_server_stmt_prepare_data_response(string $field_name): void
++ {
++ $packets = $this->packet_generator->server_stmt_prepare_data_response($field_name);
++ $this->send($this->packets_to_bytes($packets), "Stmt prepare data $field_name");
++ }
++
++ public function send_server_stmt_execute_items_response(): void
++ {
++ $packets = $this->packet_generator->server_stmt_execute_items_response();
++ $this->send($this->packets_to_bytes($packets), "Stmt execute items");
++ }
++
++ public function send_server_stmt_execute_data_response(string $field_name): void
++ {
++ $packets = $this->packet_generator->server_stmt_execute_data_response($field_name);
++ $this->send($this->packets_to_bytes($packets), "Stmt execute data $field_name");
++ }
++
++ public function send_server_query_execute_data_response(string $field_name): void
++ {
++ $packets = $this->packet_generator->server_query_execute_data_response($field_name);
++ $this->send($this->packets_to_bytes($packets), "Query execute data $field_name");
++ }
++}
++
++class my_mysqli_fake_server_process
++{
++ public function __construct(private $process, private array $pipes) {}
++
++ public function terminate(bool $wait = false)
++ {
++ if ($wait) {
++ $this->wait();
++ }
++ proc_terminate($this->process);
++ }
++
++ public function wait()
++ {
++ echo fgets($this->pipes[1]);
++ }
++}
++
++function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_tabular_query_response();
++
++ // Length of the packet is modified to include the next added data
++ $rh[1]->packet_length = "1e0000";
++
++ // We add a length field encoded on 4 bytes which evaluates to 65536. If the process crashes because
++ // the heap has been overread, lower this value.
++ $rh[1]->extra_def_size = "fd000001"; # 65536
++
++ // Filler
++ $rh[1]->extra_def_data = "aa";
++
++ $trrh = $conn->packets_to_bytes($rh);
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send($trrh, "Malicious Tabular Response [Extract heap through buffer over-read]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_upsert_query_response();
++
++ // Set extra length to overread
++ $rh[0]->len = "fa";
++
++ $trrh = $conn->packets_to_bytes($rh);
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send($trrh, "Malicious Tabular Response [Extract heap through buffer over-read]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_conn $conn): void
++{
++ $p = $conn->packet_generator->server_ok();
++ $p->packet_length = "090000";
++ $p->message_len = "fcff";
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send($p->to_bytes(), "Malicious OK Auth Response [Extract heap through buffer over-read]");
++ $conn->read();
++}
++
++function my_mysqli_test_stmt_response_row_over_read_string(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_stmt_execute_items_response();
++
++ // Set extra length to overread
++ $rh[3]->row_data_len = "fa";
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send_server_stmt_prepare_items_response();
++ $conn->read();
++ $conn->send($conn->packets_to_bytes($rh), "Malicious Stmt Response for items [Extract heap through buffer over-read]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_stmt_response_row_over_read_two_fields(
++ my_mysqli_fake_server_conn $conn,
++ string $field_name,
++ string $row_field1_len = '06'
++): void {
++ $rh = $conn->packet_generator->server_stmt_execute_data_response($field_name);
++
++ // Set extra length to overread by two bytes
++ $rh[4]->row_field1_len = $row_field1_len;
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send_server_stmt_prepare_data_response($field_name);
++ $conn->read();
++ $conn->send(
++ $conn->packets_to_bytes($rh),
++ "Malicious Stmt Response for data $field_name [Extract heap through buffer over-read]"
++ );
++ $conn->read(65536);
++}
++
++function my_mysqli_test_stmt_response_row_over_read_int(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'intval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_float(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'fltval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_double(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'dblval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_date(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'datval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_time(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'timval', '0c');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_datetime(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'dtival');
++}
++
++function my_mysqli_test_stmt_response_row_no_space(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'strval', '09');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_bit(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'bitval');
++}
++
++function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void
++{
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $field_names = array_keys(my_mysqli_data_fields());
++ foreach ($field_names as $field_name) {
++ $conn->send_server_stmt_prepare_data_response($field_name);
++ $conn->read(65536);
++ $conn->send_server_stmt_execute_data_response($field_name);
++ $conn->read(65536);
++ }
++}
++
++function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_query_execute_data_response('strval');
++
++ // Set extra length to overread by two bytes
++ $rh[4]->row_field2 = 'fefefefefe';
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send($conn->packets_to_bytes($rh), "Malicious Query Response for data strval field [length overflow]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void
++{
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $field_names = array_keys(my_mysqli_data_fields());
++ foreach ($field_names as $field_name) {
++ $conn->send_server_query_execute_data_response($field_name);
++ $conn->read();
++ }
++}
++
++function run_fake_server(string $test_function, $port = 33305): void
++{
++ $address = '127.0.0.1';
++
++ $socket = @stream_socket_server("tcp://$address:$port", $errno, $errstr);
++ if (!$socket) {
++ die("Failed to create socket: $errstr ($errno)\n");
++ }
++ echo "[*] Server started\n";
++
++ try {
++ $conn = new my_mysqli_fake_server_conn($socket);
++ $test_function_name = 'my_mysqli_test_' . $test_function;
++ call_user_func($test_function_name, $conn);
++ $conn->close();
++ } catch (Exception $e) {
++ fprintf(STDERR, "[!] Exception: " . $e->getMessage() . "\n");
++ }
++
++ fclose($socket);
++
++ echo "[*] Server finished\n";
++}
++
++
++function run_fake_server_in_background($test_function, $port = 33305): my_mysqli_fake_server_process
++{
++ $command = [PHP_BINARY, '-n', __FILE__, 'mysqli_fake_server', $test_function, $port];
++
++ $descriptorspec = array(
++ 0 => array("pipe", "r"),
++ 1 => array("pipe", "w"),
++ 2 => STDERR,
++ );
++
++ $process = proc_open($command, $descriptorspec, $pipes);
++
++ if (is_resource($process)) {
++ return new my_mysqli_fake_server_process($process, $pipes);
++ } else {
++ throw new Exception("Failed to start server process");
++ }
++}
++
++if (isset($argv) && $argc > 2 && $argv[1] == 'mysqli_fake_server') {
++ run_fake_server($argv[2], $argv[3] ?? '33305');
++}
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+new file mode 100644
+index 00000000000..db54a6c0177
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+@@ -0,0 +1,38 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - auth message buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 50001;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('auth_response_message_over_read', $port);
++$process->wait();
++
++try {
++ $conn = new mysqli( $servername, $username, $password, "", $port );
++ $info = mysqli_info($conn);
++ var_dump($info);
++} catch (Exception $e) {
++ echo $e->getMessage() . PHP_EOL;
++}
++
++$process->terminate();
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff
++
++Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
++Unknown error while trying to connect via tcp://127.0.0.1:50001
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt
+new file mode 100644
+index 00000000000..77f2232eca6
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - tabular default)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('tabular_response_def_over_read', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Running query on the fake server...\n";
++
++$result = $conn->query("SELECT * from users");
++
++if ($result) {
++ $all_fields = $result->fetch_fields();
++ var_dump($result->fetch_all(MYSQLI_ASSOC));
++ var_dump(get_object_vars($all_fields[0])["def"]);
++}
++
++$conn->close();
++
++$process->terminate();
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Running query on the fake server...
++[*] Received: 140000000353454c454354202a2066726f6d207573657273
++[*] Sending - Malicious Tabular Response [Extract heap through buffer over-read]: 01000001011e0000020164016401640164016401640c3f000b000000030350000000fd000001aa05000003fe00002200040000040135017405000005fe00002200
++
++Warning: mysqli::query(): Protocol error. Server sent default for unsupported field list (mysqlnd_wireprotocol.c:%d) in %s on line %d
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt
+new file mode 100644
+index 00000000000..0b4db8ccece
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt
+@@ -0,0 +1,43 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - upsert filename buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('upsert_response_filename_over_read', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++echo "[*] Running query on the fake server...\n";
++
++$result = $conn->query("SELECT * from users");
++$info = mysqli_info($conn);
++
++var_dump($info);
++
++$process->terminate();
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Running query on the fake server...
++[*] Received: 140000000353454c454354202a2066726f6d207573657273
++[*] Sending - Malicious Tabular Response [Extract heap through buffer over-read]: 0900000100000000000000fa65
++
++Warning: mysqli::query(): RSET_HEADER packet additional data length is past 249 bytes the packet size in %s on line %d
++
++Warning: mysqli::query(): Error reading result set's header in %s on line %d
++NULL
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt
+new file mode 100644
+index 00000000000..f141a79bdaa
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row no space for the field)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('query_response_row_length_overflow', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Query the fake server...\n";
++$sql = "SELECT strval, strval FROM data";
++
++$result = $conn->query($sql);
++
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row['strval']);
++ }
++}
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Query the fake server...
++[*] Received: 200000000353454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Malicious Query Response for data strval field [length overflow]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000a0000050474657374fefefefefe05000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after end of packet in %s on line %d
++[*] Received: 0100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt
+new file mode 100644
+index 00000000000..e43518217eb
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row bit buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_bit', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT bitval, timval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["bitval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542062697476616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data bitval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data bitval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00002200100000050000067465737408080808080808080805000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt
+new file mode 100644
+index 00000000000..76158e940d0
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row date buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_date', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, datval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["datval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2064617476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data datval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data datval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe000022000c0000050000067465737404de070c0f05000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt
+new file mode 100644
+index 00000000000..f53d5b83bd4
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row datetime buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_datetime', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, dtival FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["dtival"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2064746976616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dtival: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data dtival [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe000022000f0000050000067465737407de070c100d000105000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt
+new file mode 100644
+index 00000000000..03c9b045d73
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row double buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_double', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, dblval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["dblval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2064626c76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dblval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data dblval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe000022000f00000500000674657374333333333333f33f05000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt
+new file mode 100644
+index 00000000000..b1ec9aa51ec
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row int buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_float', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, fltval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["fltval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c20666c7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data fltval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data fltval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe000022000b000005000006746573743333134005000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt
+new file mode 100644
+index 00000000000..426d9ea7b3f
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row int buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_int', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, intval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["intval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c20696e7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data intval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data intval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe000022000b000005000006746573740e00000005000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt
+new file mode 100644
+index 00000000000..6db6952d42a
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row no space for the field)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_no_space', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, strval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["strval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Stmt prepare data strval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data strval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000c00000500000974657374047465737405000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. No packet space left for the field in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt
+new file mode 100644
+index 00000000000..55bad4cc544
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row string buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_string', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT item FROM items");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["item"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 170000001653454c454354206974656d2046524f4d206974656d73
++[*] Sending - Stmt prepare items: 0c0000010001000000010000000000003000000203646566087068705f74657374056974656d73056974656d73046974656d046974656d0ce000c8000000fd011000000005000003fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for items [Extract heap through buffer over-read]: 01000001013000000203646566087068705f74657374056974656d73056974656d73046974656d046974656d0ce000c8000000fd011000000005000003fe00002200070000040000fa7465737405000005fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt
+new file mode 100644
+index 00000000000..06918c375f3
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row time buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_time', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, timval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["timval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data timval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data timval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe000022001000000500000c7465737408000000000015080105000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/protocol_query_row_fetch_data.phpt b/ext/mysqli/tests/protocol_query_row_fetch_data.phpt
+new file mode 100644
+index 00000000000..524fe5e587c
+--- /dev/null
++++ b/ext/mysqli/tests/protocol_query_row_fetch_data.phpt
+@@ -0,0 +1,74 @@
++--TEST--
++MySQL protocol - statement row data fetch)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('query_response_row_read_two_fields', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++function my_query($conn, $field)
++{
++ $sql = "SELECT strval, $field FROM data";
++
++ $result = $conn->query($sql);
++
++ if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row[$field]);
++ }
++ }
++}
++
++foreach (my_mysqli_data_fields() as $field_name => $field) {
++ my_query($conn, $field_name);
++}
++
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECT--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Received: 200000000353454c4543542073747276616c2c20696e7476616c2046524f4d2064617461
++[*] Sending - Query execute data intval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe0000220008000005047465737402313405000006fe00002200
++string(2) "14"
++[*] Received: 200000000353454c4543542073747276616c2c20666c7476616c2046524f4d2064617461
++[*] Sending - Query execute data fltval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe0000220009000005047465737403322e3305000006fe00002200
++string(3) "2.3"
++[*] Received: 200000000353454c4543542073747276616c2c2064626c76616c2046524f4d2064617461
++[*] Sending - Query execute data dblval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe0000220009000005047465737403312e3205000006fe00002200
++string(3) "1.2"
++[*] Received: 200000000353454c4543542073747276616c2c2064617476616c2046524f4d2064617461
++[*] Sending - Query execute data datval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe000022001000000504746573740a323031342d31322d313505000006fe00002200
++string(10) "2014-12-15"
++[*] Received: 200000000353454c4543542073747276616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Query execute data timval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe000022000e00000504746573740831333a30303a303205000006fe00002200
++string(8) "13:00:02"
++[*] Received: 200000000353454c4543542073747276616c2c2064746976616c2046524f4d2064617461
++[*] Sending - Query execute data dtival: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe0000220019000005047465737413323031342d31322d31362031333a30303a303105000006fe00002200
++string(19) "2014-12-16 13:00:01"
++[*] Received: 200000000353454c4543542073747276616c2c2062697476616c2046524f4d2064617461
++[*] Sending - Query execute data bitval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe000022000e000005047465737408080808080808080805000006fe00002200
++string(18) "578721382704613384"
++[*] Received: 200000000353454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Query execute data strval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000a0000050474657374047465737405000006fe00002200
++string(4) "test"
++[*] Received: 0100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt b/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt
+new file mode 100644
+index 00000000000..d461ec24b8c
+--- /dev/null
++++ b/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt
+@@ -0,0 +1,91 @@
++--TEST--
++MySQL protocol - statement row data fetch)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_read_two_fields', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++function my_query($conn, $field)
++{
++ $stmt = $conn->prepare("SELECT strval, $field FROM data");
++
++ $stmt->execute();
++ $result = $stmt->get_result();
++
++ if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row[$field]);
++ }
++ }
++}
++
++foreach (my_mysqli_data_fields() as $field_name => $field) {
++ my_query($conn, $field_name);
++}
++
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECT--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Received: 200000001653454c4543542073747276616c2c20696e7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data intval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data intval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe000022000b000005000004746573740e00000005000006fe00002200
++int(14)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c20666c7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data fltval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data fltval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe000022000b000005000004746573743333134005000006fe00002200
++float(2.3)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2064626c76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dblval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data dblval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe000022000f00000500000474657374333333333333f33f05000006fe00002200
++float(1.2)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2064617476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data datval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data datval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe000022000c0000050000047465737404de070c0f05000006fe00002200
++string(10) "2014-12-15"
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data timval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data timval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe00002200100000050000047465737408000000000015080105000006fe00002200
++string(8) "21:08:01"
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2064746976616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dtival: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data dtival: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe000022000f0000050000047465737407de070c100d000105000006fe00002200
++string(19) "2014-12-16 13:00:01"
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2062697476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data bitval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data bitval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00002200100000050000047465737408080808080808080805000006fe00002200
++int(578721382704613384)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Stmt prepare data strval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data strval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000c00000500000474657374047465737405000006fe00002200
++string(4) "test"
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c
+index e942f10faca..736d777b43a 100644
+--- a/ext/mysqlnd/mysqlnd_ps_codec.c
++++ b/ext/mysqlnd/mysqlnd_ps_codec.c
+@@ -50,6 +50,37 @@ struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
+ #define MYSQLND_PS_SKIP_RESULT_W_LEN -1
+ #define MYSQLND_PS_SKIP_RESULT_STR -2
+
++static inline void ps_fetch_over_read_error(const zend_uchar ** row)
++{
++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after the end of packet");
++ *row = NULL;
++}
++
++static inline bool ps_fetch_is_packet_over_read_with_variable_length(const unsigned int pack_len,
++ const zend_uchar ** row, const zend_uchar *p, unsigned int length)
++{
++ if (pack_len == 0) {
++ return false;
++ }
++ size_t length_len = *row - p;
++ if (length_len > pack_len || length > pack_len - length_len) {
++ ps_fetch_over_read_error(row);
++ return true;
++ }
++ return false;
++}
++
++static inline bool ps_fetch_is_packet_over_read_with_static_length(const unsigned int pack_len,
++ const zend_uchar ** row, unsigned int length)
++{
++ if (pack_len > 0 && length > pack_len) {
++ ps_fetch_over_read_error(row);
++ return true;
++ }
++ return false;
++}
++
++
+ /* {{{ ps_fetch_from_1_to_8_bytes */
+ void
+ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len,
+@@ -58,6 +89,11 @@ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, const u
+ char tmp[22];
+ size_t tmp_len = 0;
+ zend_bool is_bit = field->type == MYSQL_TYPE_BIT;
++
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, byte_count))) {
++ return;
++ }
++
+ DBG_ENTER("ps_fetch_from_1_to_8_bytes");
+ DBG_INF_FMT("zv=%p byte_count=%u", zv, byte_count);
+ if (field->flags & UNSIGNED_FLAG) {
+@@ -176,6 +212,11 @@ ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ float fval;
+ double dval;
+ DBG_ENTER("ps_fetch_float");
++
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 4))) {
++ return;
++ }
++
+ float4get(fval, *row);
+ (*row)+= 4;
+ DBG_INF_FMT("value=%f", fval);
+@@ -198,6 +239,11 @@ ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ {
+ double value;
+ DBG_ENTER("ps_fetch_double");
++
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 8))) {
++ return;
++ }
++
+ float8get(value, *row);
+ ZVAL_DOUBLE(zv, value);
+ (*row)+= 8;
+@@ -214,9 +260,14 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, const unsigned int p
+ struct st_mysqlnd_time t;
+ zend_ulong length; /* First byte encodes the length*/
+ char * value;
++ const zend_uchar *p = *row;
+ DBG_ENTER("ps_fetch_time");
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
++
+ const zend_uchar * to = *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_TIME;
+@@ -271,9 +322,14 @@ ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, const unsigned int p
+ struct st_mysqlnd_time t = {0};
+ zend_ulong length; /* First byte encodes the length*/
+ char * value;
++ const zend_uchar *p = *row;
+ DBG_ENTER("ps_fetch_date");
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
++
+ const zend_uchar * to = *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_DATE;
+@@ -308,9 +364,14 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, const unsigned i
+ struct st_mysqlnd_time t;
+ zend_ulong length; /* First byte encodes the length*/
+ char * value;
++ const zend_uchar *p = *row;
+ DBG_ENTER("ps_fetch_datetime");
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
++
+ const zend_uchar * to = *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_DATETIME;
+@@ -369,7 +430,11 @@ ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ For now just copy, before we make it possible
+ to write \0 to the row buffer
+ */
++ const zend_uchar *p = *row;
+ const zend_ulong length = php_mysqlnd_net_field_length(row);
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
+ DBG_ENTER("ps_fetch_string");
+ DBG_INF_FMT("len = %lu", length);
+ DBG_INF("copying from the row buffer");
+@@ -385,7 +450,11 @@ ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ static void
+ ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
+ {
++ const zend_uchar *p = *row;
+ const zend_ulong length = php_mysqlnd_net_field_length(row);
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length);
+ }
+ /* }}} */
+diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
+index 5b63e09f71e..011ba34cb5e 100644
+--- a/ext/mysqlnd/mysqlnd_result.c
++++ b/ext/mysqlnd/mysqlnd_result.c
+@@ -503,7 +503,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
+ if (FAIL == (ret = result->m.read_result_metadata(result, conn))) {
+ /* For PS, we leave them in Prepared state */
+ if (!stmt && conn->current_result) {
+- mnd_efree(conn->current_result);
++ conn->current_result->m.free_result(conn->current_result, TRUE);
+ conn->current_result = NULL;
+ }
+ DBG_ERR("Error occurred while reading metadata");
+diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
+index 664a993322d..929ea422924 100644
+--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
+@@ -721,7 +721,14 @@ php_mysqlnd_auth_response_read(MYSQLND_CONN_DATA * conn, void * _packet)
+
+ /* There is a message */
+ if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
+- packet->message_len = MIN(net_len, buf_len - (p - begin));
++ /* p can get past packet size when getting field length so it needs to be checked first
++ * and after that it can be checked that the net_len is not greater than the packet size */
++ if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < net_len) {
++ DBG_ERR_FMT("OK packet message length is past the packet size");
++ php_error_docref(NULL, E_WARNING, "OK packet message length is past the packet size");
++ DBG_RETURN(FAIL);
++ }
++ packet->message_len = net_len;
+ packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
+ } else {
+ packet->message = NULL;
+@@ -1110,6 +1117,17 @@ php_mysqlnd_rset_header_read(MYSQLND_CONN_DATA * conn, void * _packet)
+ BAIL_IF_NO_MORE_DATA;
+ /* Check for additional textual data */
+ if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
++ /* p can get past packet size when getting field length so it needs to be checked first
++ * and after that it can be checked that the len is not greater than the packet size */
++ if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < len) {
++ size_t local_file_name_over_read = ((p - buf) - packet->header.size) + len;
++ DBG_ERR_FMT("RSET_HEADER packet additional data length is past %zu bytes the packet size",
++ local_file_name_over_read);
++ php_error_docref(NULL, E_WARNING,
++ "RSET_HEADER packet additional data length is past %zu bytes the packet size",
++ local_file_name_over_read);
++ DBG_RETURN(FAIL);
++ }
+ packet->info_or_local_file.s = mnd_emalloc(len + 1);
+ if (packet->info_or_local_file.s) {
+ memcpy(packet->info_or_local_file.s, p, len);
+@@ -1268,23 +1286,16 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
+ meta->flags |= NUM_FLAG;
+ }
+
+-
+- /*
+- def could be empty, thus don't allocate on the root.
+- NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
+- Otherwise the string is length encoded.
+- */
++ /* COM_FIELD_LIST is no longer supported so def should not be present */
+ if (packet->header.size > (size_t) (p - buf) &&
+ (len = php_mysqlnd_net_field_length(&p)) &&
+ len != MYSQLND_NULL_LENGTH)
+ {
+- BAIL_IF_NO_MORE_DATA;
+- DBG_INF_FMT("Def found, length %lu", len);
+- meta->def = packet->memory_pool->get_chunk(packet->memory_pool, len + 1);
+- memcpy(meta->def, p, len);
+- meta->def[len] = '\0';
+- meta->def_length = len;
+- p += len;
++ DBG_ERR_FMT("Protocol error. Server sent default for unsupported field list");
++ php_error_docref(NULL, E_WARNING,
++ "Protocol error. Server sent default for unsupported field list (mysqlnd_wireprotocol.c:%u)",
++ __LINE__);
++ DBG_RETURN(FAIL);
+ }
+
+ root_ptr = meta->root = packet->memory_pool->get_chunk(packet->memory_pool, total_len);
+@@ -1451,8 +1462,10 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi
+ const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
+ const zend_bool as_int_or_float, MYSQLND_STATS * const stats)
+ {
+- unsigned int i;
+- const zend_uchar * p = row_buffer->ptr;
++ unsigned int i, j;
++ size_t rbs = row_buffer->size;
++ const zend_uchar * rbp = row_buffer->ptr;
++ const zend_uchar * p = rbp;
+ const zend_uchar * null_ptr;
+ zend_uchar bit;
+ zval *current_field, *end_field, *start_field;
+@@ -1485,7 +1498,21 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi
+ statistic = STAT_BINARY_TYPE_FETCHED_NULL;
+ } else {
+ enum_mysqlnd_field_types type = fields_metadata[i].type;
+- mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], 0, &p);
++ size_t row_position = p - rbp;
++ if (rbs <= row_position) {
++ for (j = 0, current_field = start_field; j < i; current_field++, j++) {
++ zval_ptr_dtor(current_field);
++ }
++ php_error_docref(NULL, E_WARNING, "Malformed server packet. No packet space left for the field");
++ DBG_RETURN(FAIL);
++ }
++ mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], rbs - row_position, &p);
++ if (p == NULL) {
++ for (j = 0, current_field = start_field; j < i; current_field++, j++) {
++ zval_ptr_dtor(current_field);
++ }
++ DBG_RETURN(FAIL);
++ }
+
+ if (MYSQLND_G(collect_statistics)) {
+ switch (fields_metadata[i].type) {
+@@ -1542,7 +1569,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
+ unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
+ zend_bool as_int_or_float, MYSQLND_STATS * stats)
+ {
+- unsigned int i;
++ unsigned int i, j;
+ zval *current_field, *end_field, *start_field;
+ zend_uchar * p = row_buffer->ptr;
+ const size_t data_size = row_buffer->size;
+@@ -1563,9 +1590,11 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
+ /* NULL or NOT NULL, this is the question! */
+ if (len == MYSQLND_NULL_LENGTH) {
+ ZVAL_NULL(current_field);
+- } else if ((p + len) > packet_end) {
+- php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing "MYSQLND_SZ_T_SPEC
+- " bytes after end of packet", (p + len) - packet_end - 1);
++ } else if (p > packet_end || len > packet_end - p) {
++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after end of packet");
++ for (j = 0, current_field = start_field; j < i; current_field++, j++) {
++ zval_ptr_dtor(current_field);
++ }
+ DBG_RETURN(FAIL);
+ } else {
+ #ifdef MYSQLND_STRING_TO_INT_CONVERSION
+--
+2.47.0
+
+From d5f9da0d6af72ae21b0a9f4c94c59dfdd409e3e2 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Mon, 18 Nov 2024 15:54:30 +0100
+Subject: [PATCH 2/6] Fix MySQLnd possible buffer over read in auth_protocol
+
+(cherry picked from commit 32f905f1d689aaa8eacd6331a18c0dd45972c3c1)
+---
+ ext/mysqlnd/mysqlnd_wireprotocol.c | 27 +++++++++++++++++++++++++--
+ 1 file changed, 25 insertions(+), 2 deletions(-)
+
+diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
+index 929ea422924..5499ebac967 100644
+--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
+@@ -447,8 +447,31 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA * conn, void * _packet)
+ if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
+ BAIL_IF_NO_MORE_DATA;
+ /* The server is 5.5.x and supports authentication plugins */
+- packet->auth_protocol = estrdup((char *)p);
+- p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
++ size_t remaining_size = packet->header.size - (size_t)(p - buf);
++ if (remaining_size == 0) {
++ /* Might be better to fail but this will fail anyway */
++ packet->auth_protocol = estrdup("");
++ } else {
++ /* Check if NUL present */
++ char *null_terminator = memchr(p, '\0', remaining_size);
++ size_t auth_protocol_len;
++ if (null_terminator) {
++ /* If present, do basically estrdup */
++ auth_protocol_len = null_terminator - (char *)p;
++ } else {
++ /* If not present, copy the rest of the buffer */
++ auth_protocol_len = remaining_size;
++ }
++ char *auth_protocol = emalloc(auth_protocol_len + 1);
++ memcpy(auth_protocol, p, auth_protocol_len);
++ auth_protocol[auth_protocol_len] = '\0';
++ packet->auth_protocol = auth_protocol;
++
++ p += auth_protocol_len;
++ if (null_terminator) {
++ p++;
++ }
++ }
+ }
+
+ DBG_INF_FMT("proto=%u server=%s thread_id=%u",
+--
+2.47.0
+
+From 7e6af9c78d84d15880cfbc7867501f25ab982f5f Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 24 Nov 2024 20:13:47 +0100
+Subject: [PATCH 3/6] Change port for mysqli fake server auth message test
+
+(cherry picked from commit 51f5539914ae62ef8568ea1ed302dceda897c439)
+---
+ ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+index db54a6c0177..279aec6a2cb 100644
+--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+@@ -6,7 +6,7 @@ mysqli
+ <?php
+ require_once 'fake_server.inc';
+
+-$port = 50001;
++$port = 33305;
+ $servername = "127.0.0.1";
+ $username = "root";
+ $password = "";
+@@ -34,5 +34,5 @@ print "done!";
+ [*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff
+
+ Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
+-Unknown error while trying to connect via tcp://127.0.0.1:50001
++Unknown error while trying to connect via tcp://127.0.0.1:33305
+ done!
+--
+2.47.0
+
+From cae38b1c749d27dc3a65f7d65fdf238439e2676c Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 24 Nov 2024 23:48:27 +0100
+Subject: [PATCH 4/6] Increase MySQLi fake server read timeout for ASAN job
+
+(cherry picked from commit eb951b3d11109aa16982a2132f8d1fd5129edc9e)
+---
+ ext/mysqli/tests/fake_server.inc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc
+index b02fabc584c..1127f6c00e3 100644
+--- a/ext/mysqli/tests/fake_server.inc
++++ b/ext/mysqli/tests/fake_server.inc
+@@ -552,8 +552,8 @@ class my_mysqli_fake_server_conn
+
+ public function read($bytes_len = 1024)
+ {
+- // wait 10ms to fill the buffer
+- usleep(10000);
++ // wait 20ms to fill the buffer
++ usleep(20000);
+ $data = fread($this->conn, $bytes_len);
+ if ($data) {
+ fprintf(STDERR, "[*] Received: %s\n", bin2hex($data));
+--
+2.47.0
+
+From 69853e12b73a989e2383452356cdc07172427ae3 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 27 Nov 2024 10:54:10 +0100
+Subject: [PATCH 5/6] Avoid using uninitialised struct
+
+ (cherry picked from commit 7e7817bc2f82570bbc510a2bf5e4e0ec09dbc774)
+---
+ ext/mysqlnd/mysqlnd_result.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
+index 011ba34cb5e..9dcbd046a43 100644
+--- a/ext/mysqlnd/mysqlnd_result.c
++++ b/ext/mysqlnd/mysqlnd_result.c
+@@ -547,8 +547,8 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
+ }
+ MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
+ }
++ PACKET_FREE(&fields_eof);
+ } while (0);
+- PACKET_FREE(&fields_eof);
+ break; /* switch break */
+ }
+ } while (0);
+--
+2.47.0
+
+From 4c5f0e9541f675033aff30be6d08f629c8da01d5 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 27 Nov 2024 11:17:48 +0100
+Subject: [PATCH 6/6] adapt test + NEWS
+
+---
+ NEWS | 4 ++++
+ ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt | 3 +--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 0f82a65a44b..e043901ee96 100644
+--- a/NEWS
++++ b/NEWS
+@@ -11,6 +11,10 @@ Backported from 8.1.31
+ . Fixed bug GHSA-g665-fm4p-vhff (OOB access in ldap_escape). (CVE-2024-8932)
+ (nielsdos)
+
++- MySQLnd:
++ . Fixed bug GHSA-h35g-vwh6-m678 (Leak partial content of the heap through
++ heap buffer over-read). (CVE-2024-8929) (Jakub Zelenka)
++
+ - PDO DBLIB:
+ . Fixed bug GHSA-5hqh-c84r-qjcv (Integer overflow in the dblib quoter causing
+ OOB writes). (CVE-2024-11236) (nielsdos)
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+index 279aec6a2cb..161c9a5b8e6 100644
+--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+@@ -34,5 +34,4 @@ print "done!";
+ [*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff
+
+ Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
+-Unknown error while trying to connect via tcp://127.0.0.1:33305
+-done!
++%A
+--
+2.47.0
+
diff --git a/php-cve-2024-8932.patch b/php-cve-2024-8932.patch
new file mode 100644
index 0000000..88e2e9f
--- /dev/null
+++ b/php-cve-2024-8932.patch
@@ -0,0 +1,130 @@
+From 9f367d847989b339c33369737daf573e30bab5f1 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/8] Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape
+
+(cherry picked from commit f9ecf90070a11dad09ca7671a712f81cc2a7d52f)
+---
+ ext/ldap/ldap.c | 20 ++++++++++++++--
+ ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt | 28 ++++++++++++++++++++++
+ ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt | 29 +++++++++++++++++++++++
+ 3 files changed, 75 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 c4dfe0c5b07..6661310d055 100644
+--- a/ext/ldap/ldap.c
++++ b/ext/ldap/ldap.c
+@@ -3760,13 +3760,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;
+ }
+
+@@ -3833,7 +3843,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_argument_value_error(1, "is too long");
++ RETURN_THROWS();
++ }
++
++ 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..8e2c4fb160d
+--- /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 (ValueError $e) {
++ echo $e->getMessage(), "\n";
++}
++
++try {
++ ldap_escape(str_repeat("#", 1431655758).' ', "", LDAP_ESCAPE_DN);
++} catch (ValueError $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..a69597084be
+--- /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 (ValueError $e) {
++ echo $e->getMessage(), "\n";
++}
++
++// would allocate a string of length 2
++try {
++ ldap_escape(str_repeat("*", 1431655766), "", LDAP_ESCAPE_FILTER);
++} catch (ValueError $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
+
diff --git a/php-ghsa-4w77-75f9-2c8w.patch b/php-ghsa-4w77-75f9-2c8w.patch
new file mode 100644
index 0000000..61e859f
--- /dev/null
+++ b/php-ghsa-4w77-75f9-2c8w.patch
@@ -0,0 +1,133 @@
+From 462092a48aa0dbad24d9fa8a4a9d418faa14d309 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/8] Fix GHSA-4w77-75f9-2c8w
+
+(cherry picked from commit 7dd336ae838bbf2c62dc47e3c900d657d3534c02)
+---
+ 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 295448f1211..5104318a634 100644
+--- a/sapi/cli/php_cli_server.c
++++ b/sapi/cli/php_cli_server.c
+@@ -1863,8 +1863,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;
+@@ -1872,9 +1870,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..2c8aeff12d5
+--- /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 . "/", context: $context);
++
++$options = [
++ "http" => [
++ "method" => "POST",
++ ],
++];
++$context = stream_context_create($options);
++
++echo file_get_contents("http://" . PHP_CLI_SERVER_ADDRESS . "/", context: $context);
++?>
++--EXPECT--
++string(5) "AAAAA"
++string(0) ""
+--
+2.47.0
+
+From 22bdb43da0ecd6e72d63b63aa6c1f3a25d1bca3a 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/8] NEWS for 8.1.31 backports
+
+---
+ NEWS | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index bad0a719aae..0f82a65a44b 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
+
diff --git a/php80.spec b/php80.spec
index cb3b4f9..0866f36 100644
--- a/php80.spec
+++ b/php80.spec
@@ -30,7 +30,7 @@
%global oraclelib 19.1
%global oracledir 19.24
%else
-%global oraclever 23.5
+%global oraclever 23.6
%global oraclemax 24
%global oraclelib 23.1
%global oracledir 23
@@ -75,7 +75,11 @@
%endif
# Build firebird extensions, you can disable using --without firebird
+%if 0%{?rhel} == 10
+%bcond_with firebird
+%else
%bcond_without firebird
+%endif
# Build ZTS extension or only NTS using --without zts
%ifarch x86_64
@@ -120,7 +124,7 @@
Summary: PHP scripting language for creating dynamic web sites
Name: php
Version: %{upver}%{?rcver:~%{rcver}}
-Release: 9%{?dist}
+Release: 11%{?dist}
# All files licensed under PHP version 3.01, except
# Zend is licensed under Zend
# TSRM is licensed under BSD
@@ -204,6 +208,12 @@ Patch203: php-cve-2024-8925.patch
Patch204: php-cve-2024-8926.patch
Patch205: php-cve-2024-8927.patch
Patch206: php-cve-2024-9026.patch
+Patch207: php-cve-2024-11236.patch
+Patch208: php-cve-2024-11234.patch
+Patch209: php-cve-2024-8932.patch
+Patch210: php-cve-2024-11233.patch
+Patch211: php-ghsa-4w77-75f9-2c8w.patch
+Patch212: php-cve-2024-8929.patch
# Fixes for tests (300+)
# Factory is droped from system tzdata
@@ -1233,6 +1243,12 @@ rm ext/openssl/tests/p12_with_extra_certs.p12
%patch -P204 -p1 -b .cve8926
%patch -P205 -p1 -b .cve8927
%patch -P206 -p1 -b .cve9026
+%patch -P207 -p1 -b .cve11236
+%patch -P208 -p1 -b .cve11234
+%patch -P209 -p1 -b .cve8932
+%patch -P210 -p1 -b .cve11233
+%patch -P211 -p1 -b .ghsa4w77
+%patch -P212 -p1 -b .cve8929
# Fixes for tests related to tzdata
%patch -P300 -p1 -b .datetests
@@ -2238,6 +2254,22 @@ EOF
%changelog
+* Wed Nov 27 2024 Remi Collet <remi@remirepo.net> - 8.0.30-11
+- Fix Leak partial content of the heap through heap buffer over-read
+ CVE-2024-8929
+
+* Fri Nov 22 2024 Remi Collet <remi@remirepo.net> - 8.0.30-10
+- Fix Heap-Use-After-Free in sapi_read_post_data Processing in CLI SAPI Interface
+ GHSA-4w77-75f9-2c8w
+- Fix OOB access in ldap_escape
+ CVE-2024-8932
+- Fix Integer overflow in the dblib/firebird quoter causing OOB writes
+ CVE-2024-11236
+- 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
+
* Thu Sep 26 2024 Remi Collet <remi@remirepo.net> - 8.0.30-9
- Fix Bypass of CVE-2012-1823, Argument Injection in PHP-CGI
CVE-2024-4577