Headline
CVE-2020-13249: sanity checks for client-supplied OK packet content · mariadb-corporation/mariadb-connector-c@2759b87
libmariadb/mariadb_lib.c in MariaDB Connector/C before 3.1.8 does not properly validate the content of an OK packet received from a server. NOTE: although mariadb_lib.c was originally based on code shipped for MySQL, this issue does not affect any MySQL components supported by Oracle.
@@ -81,6 +81,8 @@ #define ASYNC_CONTEXT_DEFAULT_STACK_SIZE (4096*15) #define MA_RPL_VERSION_HACK "5.5.5-"
#define CHARSET_NAME_LEN 64
#undef max_allowed_packet #undef net_buffer_length extern ulong max_allowed_packet; /* net.c */ @@ -2139,17 +2141,22 @@ mysql_send_query(MYSQL* mysql, const char* query, unsigned long length)
int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) { uchar *end= mysql->net.read_pos+length; size_t item_len; mysql->affected_rows= net_field_length_ll(&pos); mysql->insert_id= net_field_length_ll(&pos); mysql->server_status=uint2korr(pos); pos+=2; mysql->warning_count=uint2korr(pos); pos+=2; if (pos < mysql->net.read_pos+length) if (pos > end) goto corrupted; if (pos < end) { if ((item_len= net_field_length(&pos))) mysql->info=(char*) pos; if (pos + item_len > end) goto corrupted;
/* check if server supports session tracking */ if (mysql->server_capabilities & CLIENT_SESSION_TRACKING) @@ -2160,23 +2167,26 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) { int i; if (pos < mysql->net.read_pos + length) if (pos < end) { LIST *session_item; MYSQL_LEX_STRING *str= NULL; enum enum_session_state_type si_type; uchar *old_pos= pos; size_t item_len= net_field_length(&pos); /* length for all items */
item_len= net_field_length(&pos); /* length for all items */ if (pos + item_len > end) goto corrupted; end= pos + item_len;
/* length was already set, so make sure that info will be zero terminated */ if (mysql->info) *old_pos= 0;
while (item_len > 0) while (pos < end) { size_t plen; char *data; old_pos= pos; si_type= (enum enum_session_state_type)net_field_length(&pos); switch(si_type) { case SESSION_TRACK_SCHEMA: @@ -2186,16 +2196,14 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) if (si_type != SESSION_TRACK_STATE_CHANGE) net_field_length(&pos); /* ignore total length, item length will follow next */ plen= net_field_length(&pos); if (pos + plen > end) goto corrupted; if (!(session_item= ma_multi_malloc(0, &session_item, sizeof(LIST), &str, sizeof(MYSQL_LEX_STRING), &data, plen, NULL))) { ma_clear_session_state(mysql); SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return -1; } goto oom; str->length= plen; str->str= data; memcpy(str->str, (char *)pos, plen); @@ -2218,41 +2226,40 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) if (!strncmp(str->str, "character_set_client", str->length)) set_charset= 1; plen= net_field_length(&pos); if (pos + plen > end) goto corrupted; if (!(session_item= ma_multi_malloc(0, &session_item, sizeof(LIST), &str, sizeof(MYSQL_LEX_STRING), &data, plen, NULL))) { ma_clear_session_state(mysql); SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return -1; } goto oom; str->length= plen; str->str= data; memcpy(str->str, (char *)pos, plen); pos+= plen; session_item->data= str; mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); if (set_charset && if (set_charset && str->length < CHARSET_NAME_LEN && strncmp(mysql->charset->csname, str->str, str->length) != 0) { char cs_name[64]; MARIADB_CHARSET_INFO *cs_info; char cs_name[CHARSET_NAME_LEN]; const MARIADB_CHARSET_INFO *cs_info; memcpy(cs_name, str->str, str->length); cs_name[str->length]= 0; if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name))) if ((cs_info = mysql_find_charset_name(cs_name))) mysql->charset= cs_info; } } break; default: /* not supported yet */ plen= net_field_length(&pos); if (pos + plen > end) goto corrupted; pos+= plen; break; } item_len-= (pos - old_pos); } } for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++) @@ -2267,6 +2274,16 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) else if (mysql->server_capabilities & CLIENT_SESSION_TRACKING) ma_clear_session_state(mysql); return(0);
oom: ma_clear_session_state(mysql); SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return -1;
corrupted: ma_clear_session_state(mysql); SET_CLIENT_ERROR(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0); return -1; }
int mthd_my_read_query_result(MYSQL *mysql)
Related news
MariaDB CONNECT Storage Engine Heap-based Buffer Overflow Privilege Escalation Vulnerability. This vulnerability allows local attackers to escalate privileges on affected installations of MariaDB. Authentication is required to exploit this vulnerability. The specific flaw exists within the processing of SQL queries. The issue results from the lack of proper validation of the length of user-supplied data prior to copying it to a fixed-length heap-based buffer. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code in the context of the service account. Was ZDI-CAN-16190.