1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00

sanity checks for client-supplied OK packet content

reported by Matthias Kaiser, Apple Information Security
This commit is contained in:
Sergei Golubchik
2020-05-07 14:57:00 +02:00
parent f8213af001
commit 2759b87d72

View File

@@ -81,6 +81,8 @@
#define ASYNC_CONTEXT_DEFAULT_STACK_SIZE (4096*15) #define ASYNC_CONTEXT_DEFAULT_STACK_SIZE (4096*15)
#define MA_RPL_VERSION_HACK "5.5.5-" #define MA_RPL_VERSION_HACK "5.5.5-"
#define CHARSET_NAME_LEN 64
#undef max_allowed_packet #undef max_allowed_packet
#undef net_buffer_length #undef net_buffer_length
extern ulong max_allowed_packet; /* net.c */ extern ulong max_allowed_packet; /* net.c */
@@ -2139,6 +2141,7 @@ mysql_send_query(MYSQL* mysql, const char* query, unsigned long length)
int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
{ {
uchar *end= mysql->net.read_pos+length;
size_t item_len; size_t item_len;
mysql->affected_rows= net_field_length_ll(&pos); mysql->affected_rows= net_field_length_ll(&pos);
mysql->insert_id= net_field_length_ll(&pos); mysql->insert_id= net_field_length_ll(&pos);
@@ -2146,10 +2149,14 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
pos+=2; pos+=2;
mysql->warning_count=uint2korr(pos); mysql->warning_count=uint2korr(pos);
pos+=2; pos+=2;
if (pos < mysql->net.read_pos+length) if (pos > end)
goto corrupted;
if (pos < end)
{ {
if ((item_len= net_field_length(&pos))) if ((item_len= net_field_length(&pos)))
mysql->info=(char*) pos; mysql->info=(char*) pos;
if (pos + item_len > end)
goto corrupted;
/* check if server supports session tracking */ /* check if server supports session tracking */
if (mysql->server_capabilities & CLIENT_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) if (mysql->server_status & SERVER_SESSION_STATE_CHANGED)
{ {
int i; int i;
if (pos < mysql->net.read_pos + length) if (pos < end)
{ {
LIST *session_item; LIST *session_item;
MYSQL_LEX_STRING *str= NULL; MYSQL_LEX_STRING *str= NULL;
enum enum_session_state_type si_type; enum enum_session_state_type si_type;
uchar *old_pos= pos; 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 */ /* length was already set, so make sure that info will be zero terminated */
if (mysql->info) if (mysql->info)
*old_pos= 0; *old_pos= 0;
while (item_len > 0) while (pos < end)
{ {
size_t plen; size_t plen;
char *data; char *data;
old_pos= pos;
si_type= (enum enum_session_state_type)net_field_length(&pos); si_type= (enum enum_session_state_type)net_field_length(&pos);
switch(si_type) { switch(si_type) {
case SESSION_TRACK_SCHEMA: 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) if (si_type != SESSION_TRACK_STATE_CHANGE)
net_field_length(&pos); /* ignore total length, item length will follow next */ net_field_length(&pos); /* ignore total length, item length will follow next */
plen= net_field_length(&pos); plen= net_field_length(&pos);
if (pos + plen > end)
goto corrupted;
if (!(session_item= ma_multi_malloc(0, if (!(session_item= ma_multi_malloc(0,
&session_item, sizeof(LIST), &session_item, sizeof(LIST),
&str, sizeof(MYSQL_LEX_STRING), &str, sizeof(MYSQL_LEX_STRING),
&data, plen, &data, plen,
NULL))) NULL)))
{ goto oom;
ma_clear_session_state(mysql);
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return -1;
}
str->length= plen; str->length= plen;
str->str= data; str->str= data;
memcpy(str->str, (char *)pos, plen); memcpy(str->str, (char *)pos, plen);
@@ -2218,30 +2226,28 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
if (!strncmp(str->str, "character_set_client", str->length)) if (!strncmp(str->str, "character_set_client", str->length))
set_charset= 1; set_charset= 1;
plen= net_field_length(&pos); plen= net_field_length(&pos);
if (pos + plen > end)
goto corrupted;
if (!(session_item= ma_multi_malloc(0, if (!(session_item= ma_multi_malloc(0,
&session_item, sizeof(LIST), &session_item, sizeof(LIST),
&str, sizeof(MYSQL_LEX_STRING), &str, sizeof(MYSQL_LEX_STRING),
&data, plen, &data, plen,
NULL))) NULL)))
{ goto oom;
ma_clear_session_state(mysql);
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return -1;
}
str->length= plen; str->length= plen;
str->str= data; str->str= data;
memcpy(str->str, (char *)pos, plen); memcpy(str->str, (char *)pos, plen);
pos+= plen; pos+= plen;
session_item->data= str; session_item->data= str;
mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); 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) strncmp(mysql->charset->csname, str->str, str->length) != 0)
{ {
char cs_name[64]; char cs_name[CHARSET_NAME_LEN];
MARIADB_CHARSET_INFO *cs_info; const MARIADB_CHARSET_INFO *cs_info;
memcpy(cs_name, str->str, str->length); memcpy(cs_name, str->str, str->length);
cs_name[str->length]= 0; 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; mysql->charset= cs_info;
} }
} }
@@ -2249,10 +2255,11 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
default: default:
/* not supported yet */ /* not supported yet */
plen= net_field_length(&pos); plen= net_field_length(&pos);
if (pos + plen > end)
goto corrupted;
pos+= plen; pos+= plen;
break; break;
} }
item_len-= (pos - old_pos);
} }
} }
for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++) 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) else if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
ma_clear_session_state(mysql); ma_clear_session_state(mysql);
return(0); 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) int mthd_my_read_query_result(MYSQL *mysql)