Projects
home:rottame:vhosts-ng:php74
php7
php7-CVE-2024-8929.patch
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File php7-CVE-2024-8929.patch of Package php7
Index: php-7.4.33/ext/mysqlnd/mysqlnd_ps_codec.c =================================================================== --- php-7.4.33.orig/ext/mysqlnd/mysqlnd_ps_codec.c +++ php-7.4.33/ext/mysqlnd/mysqlnd_ps_codec.c @@ -52,11 +52,45 @@ struct st_mysqlnd_perm_bind mysqlnd_ps_f #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 int 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 int 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, const zend_uchar ** row, unsigned int byte_count) { + if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, byte_count))) { + return; + } + char tmp[22]; size_t tmp_len = 0; zend_bool is_bit = field->type == MYSQL_TYPE_BIT; @@ -178,6 +212,11 @@ ps_fetch_float(zval * zv, const MYSQLND_ 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 +239,11 @@ ps_fetch_double(zval * zv, const MYSQLND { 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 +260,14 @@ ps_fetch_time(zval * zv, const MYSQLND_F 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 +322,14 @@ ps_fetch_date(zval * zv, const MYSQLND_F 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 +364,14 @@ ps_fetch_datetime(zval * zv, const MYSQL 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 +430,11 @@ ps_fetch_string(zval * zv, const MYSQLND 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 +450,11 @@ ps_fetch_string(zval * zv, const MYSQLND 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); } /* }}} */ Index: php-7.4.33/ext/mysqlnd/mysqlnd_result.c =================================================================== --- php-7.4.33.orig/ext/mysqlnd/mysqlnd_result.c +++ php-7.4.33/ext/mysqlnd/mysqlnd_result.c @@ -505,7 +505,7 @@ mysqlnd_query_read_result_set_header(MYS 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"); Index: php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.c =================================================================== --- php-7.4.33.orig/ext/mysqlnd/mysqlnd_wireprotocol.c +++ php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -715,7 +715,14 @@ php_mysqlnd_auth_response_read(MYSQLND_C /* 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; @@ -1113,6 +1120,17 @@ php_mysqlnd_rset_header_read(MYSQLND_CON 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); @@ -1272,22 +1290,16 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN } - /* - 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); @@ -1462,8 +1474,10 @@ php_mysqlnd_rowp_read_binary_protocol(MY const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata, const zend_bool as_int_or_float, MYSQLND_STATS * const stats) { - unsigned int i; - const zend_uchar * p = row_buffer->ptr; + unsigned int i, j; + size_t rbs = row_buffer->size; + const zend_uchar * rbp = row_buffer->ptr; + const zend_uchar * p = rbp; const zend_uchar * null_ptr; zend_uchar bit; zval *current_field, *end_field, *start_field; @@ -1496,7 +1510,21 @@ php_mysqlnd_rowp_read_binary_protocol(MY 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) { @@ -1553,7 +1581,7 @@ php_mysqlnd_rowp_read_text_protocol_aux( unsigned int field_count, const MYSQLND_FIELD * fields_metadata, zend_bool as_int_or_float, MYSQLND_STATS * stats) { - unsigned int i; + unsigned int i, j; zval *current_field, *end_field, *start_field; zend_uchar * p = row_buffer->ptr; const size_t data_size = row_buffer->size; @@ -1574,9 +1602,11 @@ php_mysqlnd_rowp_read_text_protocol_aux( /* 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)
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.