diff options
| -rw-r--r-- | failed.txt | 2 | ||||
| -rw-r--r-- | php-cve-2024-8929.patch | 2906 | ||||
| -rw-r--r-- | php.spec | 8 | 
3 files changed, 2914 insertions, 2 deletions
| @@ -1,4 +1,4 @@ -===== 7.3.33-17 (2024-11-22) +===== 7.3.33-18 (2024-11-28)  $ grep -ar 'Tests failed' /var/lib/mock/*/build.log diff --git a/php-cve-2024-8929.patch b/php-cve-2024-8929.patch new file mode 100644 index 0000000..a62be66 --- /dev/null +++ b/php-cve-2024-8929.patch @@ -0,0 +1,2906 @@ +From bb1dd9865d8163ee9f0449994cf086852ea1014e 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) +(cherry picked from commit 0d3ccf4cc54d3844bc9d1c8f6bdcd36180752a2c) + +adapt for 7.x + +(cherry picked from commit e8bc357123ea19c4e2390374f088c9d4941f19e6) +--- + 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 0000000000..b02fabc584 +--- /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 0000000000..db54a6c017 +--- /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 0000000000..77f2232eca +--- /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 0000000000..0b4db8ccec +--- /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 0000000000..f141a79bda +--- /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 0000000000..e43518217e +--- /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 0000000000..76158e940d +--- /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 0000000000..f53d5b83bd +--- /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 0000000000..03c9b045d7 +--- /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 0000000000..b1ec9aa51e +--- /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 0000000000..426d9ea7b3 +--- /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 0000000000..6db6952d42 +--- /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 0000000000..55bad4cc54 +--- /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 0000000000..06918c375f +--- /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 0000000000..524fe5e587 +--- /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 0000000000..d461ec24b8 +--- /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 acc73334be..289945ae36 100644 +--- a/ext/mysqlnd/mysqlnd_ps_codec.c ++++ b/ext/mysqlnd/mysqlnd_ps_codec.c +@@ -52,6 +52,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 zend_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 0; ++	} ++	size_t length_len = *row - p; ++	if (length_len > pack_len || length > pack_len - length_len) { ++		ps_fetch_over_read_error(row); ++		return 1; ++	} ++	return 0; ++} ++ ++static inline zend_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 1; ++	} ++	return 0; ++} ++ ++ + /* {{{ 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, +@@ -60,6 +91,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) { +@@ -178,6 +214,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); +@@ -200,6 +241,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; +@@ -216,9 +262,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; +@@ -273,9 +324,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; +@@ -310,9 +366,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; +@@ -371,7 +432,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"); +@@ -387,7 +452,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 10b4d09905..1ca3d535b4 100644 +--- a/ext/mysqlnd/mysqlnd_result.c ++++ b/ext/mysqlnd/mysqlnd_result.c +@@ -502,7 +502,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 1aee62c64e..53c4768ab5 100644 +--- a/ext/mysqlnd/mysqlnd_wireprotocol.c ++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c +@@ -712,7 +712,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; +@@ -1106,6 +1113,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); +@@ -1262,23 +1280,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); +@@ -1439,8 +1450,10 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi + 									  unsigned int field_count, const MYSQLND_FIELD * fields_metadata, + 									  zend_bool as_int_or_float, MYSQLND_STATS * 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; +@@ -1473,7 +1486,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) { +@@ -1530,7 +1557,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; + 	size_t data_size = row_buffer->size; +@@ -1551,9 +1578,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 { + #if defined(MYSQLND_STRING_TO_INT_CONVERSION) +--  +2.47.0 + +From 4b9c5559d30291cae7abbbb12ffa20d3b375177f 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) +(cherry picked from commit d5f9da0d6af72ae21b0a9f4c94c59dfdd409e3e2) +(cherry picked from commit aaeb9549a1bdfa787fc3d3a2d499b418d09a5387) +--- + 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 53c4768ab5..7036945540 100644 +--- a/ext/mysqlnd/mysqlnd_wireprotocol.c ++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c +@@ -442,8 +442,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 1f246c5587bd49e207400bde80845566603ce67c Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 27 Nov 2024 10:54:10 +0100 +Subject: [PATCH 3/6] Avoid using uninitialised struct + +    (cherry picked from commit 7e7817bc2f82570bbc510a2bf5e4e0ec09dbc774) + +(cherry picked from commit 69853e12b73a989e2383452356cdc07172427ae3) +(cherry picked from commit 83a0d005d51a44bbe77a178c387e2c9f042a335d) +--- + 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 1ca3d535b4..aea660fedf 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 9da49d38401c1b5a2dfbb8d1bf6f779fef74e44b Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 24 Nov 2024 20:13:47 +0100 +Subject: [PATCH 4/6] Change port for mysqli fake server auth message test + +(cherry picked from commit 51f5539914ae62ef8568ea1ed302dceda897c439) +(cherry picked from commit 7e6af9c78d84d15880cfbc7867501f25ab982f5f) +(cherry picked from commit 606322b7f3475fb5980f7785789adfb9c381abbc) +--- + 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 db54a6c017..279aec6a2c 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 3d73240774358a265f9f2e18048fbfc95d7fe271 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 24 Nov 2024 23:48:27 +0100 +Subject: [PATCH 5/6] Increase MySQLi fake server read timeout for ASAN job + +(cherry picked from commit eb951b3d11109aa16982a2132f8d1fd5129edc9e) +(cherry picked from commit cae38b1c749d27dc3a65f7d65fdf238439e2676c) +(cherry picked from commit c308c94eefdbddb041ed3cf502ef5dd6969e14f1) +--- + 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 b02fabc584..1127f6c00e 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 d42971176d7a29c5366b2eb67eae65c6faf9c802 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 + +(cherry picked from commit 016ffd6131a6174fe5ca5f4af3c66ad9f59ed879) +--- + NEWS                                          |   4 + + ext/mysqli/tests/fake_server.inc              | 107 ++++++++++-------- + .../ghsa-h35g-vwh6-m678-auth-message.phpt     |   3 +- + ...hsa-h35g-vwh6-m678-query-len-overflow.phpt |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-bit.phpt     |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-date.phpt    |   2 +- + ...ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-double.phpt  |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-float.phpt   |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-int.phpt     |   2 +- + ...ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-string.phpt  |   2 +- + .../ghsa-h35g-vwh6-m678-stmt-row-time.phpt    |   2 +- + ext/mysqli/tests/mysqli_change_user_new.phpt  |   5 +- + ext/mysqli/tests/mysqli_pconn_max_links.phpt  |   4 +- + ..._stmt_get_result_metadata_fetch_field.phpt |   2 +- + 16 files changed, 80 insertions(+), 65 deletions(-) + +diff --git a/NEWS b/NEWS +index c852608133..342c184c30 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/fake_server.inc b/ext/mysqli/tests/fake_server.inc +index 1127f6c00e..8a9a045eac 100644 +--- a/ext/mysqli/tests/fake_server.inc ++++ b/ext/mysqli/tests/fake_server.inc +@@ -1,6 +1,6 @@ + <?php +  +-function my_mysqli_data_fields(): array ++function my_mysqli_data_fields() + { +     return [ +         'intval' => [ +@@ -107,14 +107,17 @@ function my_mysqli_data_field(string $field): array +  + class my_mysqli_fake_packet_item + { +-    public function __construct(public string|null $name, public string $value, public bool $is_hex = true) ++    public function __construct($name, string $value, bool $is_hex = true) +     { ++        $this->name   = $name; ++        $this->value  = $value; ++        $this->is_hex = $is_hex; +     } + } +  + class my_mysqli_fake_packet + { +-    private array $data = array(); ++    private $data = array(); +  +     public function __get(string $name) +     { +@@ -126,7 +129,7 @@ class my_mysqli_fake_packet +         return null; +     } +  +-    public function __set(string $name, string|my_mysqli_fake_packet_item $value) ++    public function __set(string $name, $value) +     { +         if ($value instanceof my_mysqli_fake_packet_item) { +             if ($value->name === null) { +@@ -146,7 +149,7 @@ class my_mysqli_fake_packet +         $this->data[] = $value; +     } +  +-    public function to_bytes(): string ++    public function to_bytes() +     { +         $bytes = ''; +         foreach ($this->data as $item) { +@@ -158,7 +161,7 @@ class my_mysqli_fake_packet +  + 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 ++    public static function create_packet_item($value, bool $is_hex = false, string $format = 'v') +     { +         if (is_string($value)) { +             $packed_value = $value; +@@ -168,7 +171,7 @@ class my_mysqli_fake_packet_generator +         return new my_mysqli_fake_packet_item(null, $packed_value, $is_hex); +     } +  +-    public function server_ok(): my_mysqli_fake_packet ++    public function server_ok() +     { +         $packet = new my_mysqli_fake_packet(); +         $packet->packet_length = "070000"; +@@ -181,7 +184,7 @@ class my_mysqli_fake_packet_generator +         return $packet; +     } +  +-    public function server_greetings(): my_mysqli_fake_packet ++    public function server_greetings() +     { +         $packet = new my_mysqli_fake_packet(); +         $packet->packet_length = "580000"; +@@ -204,7 +207,7 @@ class my_mysqli_fake_packet_generator +         return $packet; +     } +  +-    public function server_tabular_query_response(): array ++    public function server_tabular_query_response() +     { +         $qr1 = new my_mysqli_fake_packet(); +         $qr1->packet_length = "010000"; +@@ -239,7 +242,7 @@ class my_mysqli_fake_packet_generator +         return [$qr1, $qr2, $qr3, $qr4, $qr5]; +     } +  +-    public function server_upsert_query_response(): array ++    public function server_upsert_query_response() +     { +         $qr1 = new my_mysqli_fake_packet(); +         $qr1->packet_length = "010000"; +@@ -257,7 +260,7 @@ class my_mysqli_fake_packet_generator +         return [$qr1]; +     } +  +-    public function server_stmt_prepare_response_start($num_field): my_mysqli_fake_packet ++    public function server_stmt_prepare_response_start($num_field) +     { +         $pr1 = new my_mysqli_fake_packet(); +         $pr1->packet_length = "0c0000"; +@@ -272,7 +275,7 @@ class my_mysqli_fake_packet_generator +         return $pr1; +     } +  +-    public function server_stmt_prepare_response_end($packer_number): my_mysqli_fake_packet ++    public function server_stmt_prepare_response_end($packer_number) +     { +         $pr3 = new my_mysqli_fake_packet(); +         $pr3->packet_length = "050000"; +@@ -284,7 +287,7 @@ class my_mysqli_fake_packet_generator +         return $pr3; +     } +  +-    public function server_stmt_prepare_items_response(): array ++    public function server_stmt_prepare_items_response() +     { +         $pr1 = $this->server_stmt_prepare_response_start('0100'); +  +@@ -316,7 +319,7 @@ class my_mysqli_fake_packet_generator +         return [$pr1, $pr2, $pr3]; +     } +  +-    public function server_stmt_prepare_data_response_field($packet_number, $field_name): my_mysqli_fake_packet ++    public function server_stmt_prepare_data_response_field($packet_number, $field_name) +     { +         if (strlen($field_name) != 6) { +             throw new Exception("Invalid field length - only 6 is allowed"); +@@ -350,7 +353,7 @@ class my_mysqli_fake_packet_generator +         return $pr; +     } +  +-    public function server_stmt_prepare_data_response(string $field_name): array ++    public function server_stmt_prepare_data_response(string $field_name) +     { +         $pr1 = $this->server_stmt_prepare_response_start('0200'); +  +@@ -362,7 +365,7 @@ class my_mysqli_fake_packet_generator +         return [$pr1, $pr2, $pr3, $pr4]; +     } +  +-    public function server_stmt_execute_items_response(): array ++    public function server_stmt_execute_items_response() +     { +         $pr1 = new my_mysqli_fake_packet(); +         $pr1->packet_length = "010000"; +@@ -413,7 +416,7 @@ class my_mysqli_fake_packet_generator +         return [$pr1, $pr2, $pr3, $pr4, $pr5]; +     } +  +-    private function server_execute_data_response_start(string $field_name): array ++    private function server_execute_data_response_start(string $field_name) +     { +         $pr1 = new my_mysqli_fake_packet(); +         $pr1->packet_length = "010000"; +@@ -478,7 +481,7 @@ class my_mysqli_fake_packet_generator +         return [$field, $pr1, $pr2, $pr3, $pr4]; +     } +  +-    private function server_execute_data_response_end(): my_mysqli_fake_packet ++    private function server_execute_data_response_end() +     { +         $pr6 = new my_mysqli_fake_packet(); +         $pr6->packet_length = '050000'; +@@ -490,7 +493,7 @@ class my_mysqli_fake_packet_generator +         return $pr6; +     } +  +-    public function server_stmt_execute_data_response(string $field_name): array ++    public function server_stmt_execute_data_response(string $field_name) +     { +         [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name); +  +@@ -506,7 +509,7 @@ class my_mysqli_fake_packet_generator +         return [$pr1, $pr2, $pr3, $pr4, $pr5, $this->server_execute_data_response_end()]; +     } +  +-    public function server_query_execute_data_response(string $field_name): array ++    public function server_query_execute_data_response(string $field_name) +     { +         [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name); +  +@@ -537,12 +540,15 @@ class my_mysqli_fake_server_conn +         } +     } +  +-    public function packets_to_bytes(array $packets): string ++    public function packets_to_bytes(array $packets) +     { +-        return implode('', array_map(fn($s) => $s->to_bytes(), $packets)); ++        $func = function($s) { ++	    return $s->to_bytes(); ++	}; ++        return implode('', array_map($func, $packets)); +     } +  +-    public function send($payload, $message = null): void ++    public function send($payload, $message = null) +     { +         if ($message) { +             fprintf(STDERR, "[*] Sending - %s: %s\n", $message, bin2hex($payload)); +@@ -575,38 +581,38 @@ class my_mysqli_fake_server_conn +         $this->send($this->packet_generator->server_ok()->to_bytes(), "Server OK"); +     } +  +-    public function send_server_tabular_query_response(): void ++    public function send_server_tabular_query_response() +     { +         $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 ++    public function send_server_stmt_prepare_items_response() +     { +         $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 ++    public function send_server_stmt_prepare_data_response(string $field_name) +     { +         $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 ++    public function send_server_stmt_execute_items_response() +     { +         $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 ++    public function send_server_stmt_execute_data_response(string $field_name) +     { +         $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 ++    public function send_server_query_execute_data_response(string $field_name) +     { +         $packets = $this->packet_generator->server_query_execute_data_response($field_name); +         $this->send($this->packets_to_bytes($packets), "Query execute data $field_name"); +@@ -615,7 +621,11 @@ class my_mysqli_fake_server_conn +  + class my_mysqli_fake_server_process + { +-    public function __construct(private $process, private array $pipes) {} ++    public function __construct($process, array $pipes) ++    { ++	    $this->process = $process; ++	    $this->pipes = $pipes; ++    } +  +     public function terminate(bool $wait = false) +     { +@@ -631,7 +641,7 @@ class my_mysqli_fake_server_process +     } + } +  +-function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_conn $conn) + { +     $rh = $conn->packet_generator->server_tabular_query_response(); +  +@@ -655,7 +665,7 @@ function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_con +     $conn->read(65536); + } +  +-function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server_conn $conn) + { +     $rh = $conn->packet_generator->server_upsert_query_response(); +  +@@ -672,7 +682,7 @@ function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server +     $conn->read(65536); + } +  +-function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_conn $conn) + { +     $p = $conn->packet_generator->server_ok(); +     $p->packet_length = "090000"; +@@ -684,7 +694,7 @@ function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_co +     $conn->read(); + } +  +-function my_mysqli_test_stmt_response_row_over_read_string(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_stmt_response_row_over_read_string(my_mysqli_fake_server_conn $conn) + { +     $rh = $conn->packet_generator->server_stmt_execute_items_response(); +  +@@ -705,7 +715,7 @@ 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 +@@ -724,47 +734,47 @@ function my_mysqli_test_stmt_response_row_over_read_two_fields( +     $conn->read(65536); + } +  +-function my_mysqli_test_stmt_response_row_over_read_int(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_stmt_response_row_over_read_int(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_over_read_float(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_over_read_double(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_over_read_date(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_over_read_time(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_over_read_datetime(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_no_space(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_over_read_bit(my_mysqli_fake_server_conn $conn) + { +     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 ++function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_conn $conn) + { +     $conn->send_server_greetings(); +     $conn->read(); +@@ -779,7 +789,7 @@ function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_ +     } + } +  +-function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server_conn $conn) + { +     $rh = $conn->packet_generator->server_query_execute_data_response('strval'); +  +@@ -794,7 +804,7 @@ function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server +     $conn->read(65536); + } +  +-function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void ++function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server_conn $conn) + { +     $conn->send_server_greetings(); +     $conn->read(); +@@ -807,7 +817,7 @@ function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server +     } + } +  +-function run_fake_server(string $test_function, $port = 33305): void ++function run_fake_server(string $test_function, $port = 33305) + { +     $address = '127.0.0.1'; +  +@@ -832,9 +842,10 @@ function run_fake_server(string $test_function, $port = 33305): void + } +  +  +-function run_fake_server_in_background($test_function, $port = 33305): my_mysqli_fake_server_process ++function run_fake_server_in_background($test_function, $port = 33305) + { +     $command = [PHP_BINARY, '-n', __FILE__, 'mysqli_fake_server', $test_function, $port]; ++    $command = implode(' ', $command); +  +     $descriptorspec = array( +         0 => array("pipe", "r"), +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 279aec6a2c..161c9a5b8e 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 +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 +index f141a79bda..6c443583b3 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt +@@ -42,7 +42,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after end of packet in %s on line %A + [*] 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 +index e43518217e..f5fdf6fb2b 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index 76158e940d..74f452d374 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index f53d5b83bd..6e8876508d 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index 03c9b045d7..f7a599af0e 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index b1ec9aa51e..4c28de66fa 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index 426d9ea7b3..4c7cb156a3 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index 6db6952d42..242669e3a1 100644 +--- 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 +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. No packet space left for the field in %s on line %A + [*] 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 +index 55bad4cc54..9433a811ba 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] 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 +index 06918c375f..82c2014c2d 100644 +--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt ++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt +@@ -47,7 +47,7 @@ print "done!"; + [*] 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 ++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %A + [*] Received: 0500000019010000000100000001 + [*] Server finished + done! +diff --git a/ext/mysqli/tests/mysqli_change_user_new.phpt b/ext/mysqli/tests/mysqli_change_user_new.phpt +index ec6b3e31c9..c56b5c03fa 100644 +--- a/ext/mysqli/tests/mysqli_change_user_new.phpt ++++ b/ext/mysqli/tests/mysqli_change_user_new.phpt +@@ -11,7 +11,10 @@ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) + 		$host, $user, $db, $port, $socket)); +  + if (mysqli_get_server_version($link) < 50600) +-	die("SKIP For MySQL >= 5.6.0"); ++    die("SKIP For MySQL >= 5.6.0"); ++ ++if (mysqli_get_server_version($link) >= 100000) ++    die("SKIP Not applicable for MariaDB"); + ?> + --FILE-- + <?php +diff --git a/ext/mysqli/tests/mysqli_pconn_max_links.phpt b/ext/mysqli/tests/mysqli_pconn_max_links.phpt +index 4b610c3a9a..37e5859e1a 100644 +--- a/ext/mysqli/tests/mysqli_pconn_max_links.phpt ++++ b/ext/mysqli/tests/mysqli_pconn_max_links.phpt +@@ -235,9 +235,7 @@ Before second pconnect:array(3) { +   int(0) + } +  +-Warning: main(): MySQL server has gone away in %s on line %d +- +-Warning: main(): Error reading result set's header in %s line %d ++Warning: %A + After second pconnect:array(3) { +   ["total"]=> +   int(1) +diff --git a/ext/mysqli/tests/mysqli_stmt_get_result_metadata_fetch_field.phpt b/ext/mysqli/tests/mysqli_stmt_get_result_metadata_fetch_field.phpt +index 5481db04f4..2ccac52aca 100644 +--- a/ext/mysqli/tests/mysqli_stmt_get_result_metadata_fetch_field.phpt ++++ b/ext/mysqli/tests/mysqli_stmt_get_result_metadata_fetch_field.phpt +@@ -176,6 +176,6 @@ object(stdClass)#%d (13) { +   ["type"]=> +   int(253) +   ["decimals"]=> +-  int(31) ++  int(3%d) + } + done! +--  +2.47.0 + @@ -135,7 +135,7 @@  Summary: PHP scripting language for creating dynamic web sites  Name:    %{?scl_prefix}php  Version: %{upver}%{?rcver:~%{rcver}} -Release: 17%{?dist} +Release: 18%{?dist}  # All files licensed under PHP version 3.01, except  # Zend is licensed under Zend  # TSRM is licensed under BSD @@ -230,6 +230,7 @@ Patch219: php-cve-2024-11234.patch  Patch220: php-cve-2024-8932.patch  Patch221: php-cve-2024-11233.patch  Patch222: php-ghsa-4w77-75f9-2c8w.patch +Patch223: php-cve-2024-8929.patch  # Fixes for tests (300+)  # Factory is droped from system tzdata @@ -1032,6 +1033,7 @@ sed -e 's/php-devel/%{?scl_prefix}php-devel/' -i scripts/phpize.in  %patch -P220 -p1 -b .cve8932  %patch -P221 -p1 -b .cve11233  %patch -P222 -p1 -b .ghsa4w77 +%patch -P223 -p1 -b .cve8929  # Fixes for tests  %patch -P300 -p1 -b .datetests @@ -1991,6 +1993,10 @@ EOF  %changelog +* Wed Nov 27 2024 Remi Collet <remi@remirepo.net> - 7.3.33-18 +- Fix Leak partial content of the heap through heap buffer over-read +  CVE-2024-8929 +  * Fri Nov 22 2024 Remi Collet <remi@remirepo.net> - 7.3.33-17  - Fix Heap-Use-After-Free in sapi_read_post_data Processing in CLI SAPI Interface    GHSA-4w77-75f9-2c8w | 
