Commit 5db5359d authored by Nuno Carvalho's avatar Nuno Carvalho

BUG#14629727: USER_VAR_EVENT IS MISSING RANGE CHECKS

Merge bundle on mysql-5.5.
parents ec64d88f ff08e648
...@@ -1299,7 +1299,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, ...@@ -1299,7 +1299,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
ev = new Rand_log_event(buf, description_event); ev = new Rand_log_event(buf, description_event);
break; break;
case USER_VAR_EVENT: case USER_VAR_EVENT:
ev = new User_var_log_event(buf, description_event); ev = new User_var_log_event(buf, event_len, description_event);
break; break;
case FORMAT_DESCRIPTION_EVENT: case FORMAT_DESCRIPTION_EVENT:
ev = new Format_description_log_event(buf, event_len, description_event); ev = new Format_description_log_event(buf, event_len, description_event);
...@@ -5812,19 +5812,35 @@ void User_var_log_event::pack_info(Protocol* protocol) ...@@ -5812,19 +5812,35 @@ void User_var_log_event::pack_info(Protocol* protocol)
User_var_log_event:: User_var_log_event::
User_var_log_event(const char* buf, User_var_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event) const Format_description_log_event* description_event)
:Log_event(buf, description_event) :Log_event(buf, description_event)
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
, deferred(false) , deferred(false)
#endif #endif
{ {
bool error= false;
const char* buf_start= buf;
/* The Post-Header is empty. The Variable Data part begins immediately. */ /* The Post-Header is empty. The Variable Data part begins immediately. */
const char *start= buf; const char *start= buf;
buf+= description_event->common_header_len + buf+= description_event->common_header_len +
description_event->post_header_len[USER_VAR_EVENT-1]; description_event->post_header_len[USER_VAR_EVENT-1];
name_len= uint4korr(buf); name_len= uint4korr(buf);
name= (char *) buf + UV_NAME_LEN_SIZE; name= (char *) buf + UV_NAME_LEN_SIZE;
/*
We don't know yet is_null value, so we must assume that name_len
may have the bigger value possible, is_null= True and there is no
payload for val.
*/
if (0 == name_len ||
!valid_buffer_range<uint>(name_len, buf_start, name,
event_len - UV_VAL_IS_NULL))
{
error= true;
goto err;
}
buf+= UV_NAME_LEN_SIZE + name_len; buf+= UV_NAME_LEN_SIZE + name_len;
is_null= (bool) *buf; is_null= (bool) *buf;
flags= User_var_log_event::UNDEF_F; // defaults to UNDEF_F flags= User_var_log_event::UNDEF_F; // defaults to UNDEF_F
...@@ -5837,6 +5853,14 @@ User_var_log_event(const char* buf, ...@@ -5837,6 +5853,14 @@ User_var_log_event(const char* buf,
} }
else else
{ {
if (!valid_buffer_range<uint>(UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE,
buf_start, buf, event_len))
{
error= true;
goto err;
}
type= (Item_result) buf[UV_VAL_IS_NULL]; type= (Item_result) buf[UV_VAL_IS_NULL];
charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE); charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
...@@ -5844,6 +5868,12 @@ User_var_log_event(const char* buf, ...@@ -5844,6 +5868,12 @@ User_var_log_event(const char* buf,
val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE); UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
if (!valid_buffer_range<uint>(val_len, buf_start, val, event_len))
{
error= true;
goto err;
}
/** /**
We need to check if this is from an old server We need to check if this is from an old server
that did not pack information for flags. that did not pack information for flags.
...@@ -5865,6 +5895,10 @@ User_var_log_event(const char* buf, ...@@ -5865,6 +5895,10 @@ User_var_log_event(const char* buf,
val_len); val_len);
} }
} }
err:
if (error)
name= 0;
} }
...@@ -6014,8 +6048,9 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -6014,8 +6048,9 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
char *hex_str; char *hex_str;
CHARSET_INFO *cs; CHARSET_INFO *cs;
if (!(hex_str= (char *)my_alloca(2*val_len+1+2))) // 2 hex digits / byte hex_str= (char *)my_malloc(2*val_len+1+2,MYF(MY_WME)); // 2 hex digits / byte
break; // no error, as we are 'void' if (!hex_str)
return;
str_to_hex(hex_str, val, val_len); str_to_hex(hex_str, val, val_len);
/* /*
For proper behaviour when mysqlbinlog|mysql, we need to explicitely For proper behaviour when mysqlbinlog|mysql, we need to explicitely
...@@ -6033,7 +6068,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -6033,7 +6068,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n", my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
cs->csname, hex_str, cs->name, cs->csname, hex_str, cs->name,
print_event_info->delimiter); print_event_info->delimiter);
my_afree(hex_str); my_free(hex_str);
} }
break; break;
case ROW_RESULT: case ROW_RESULT:
......
...@@ -2577,7 +2577,7 @@ class User_var_log_event: public Log_event ...@@ -2577,7 +2577,7 @@ class User_var_log_event: public Log_event
void print(FILE* file, PRINT_EVENT_INFO* print_event_info); void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif #endif
User_var_log_event(const char* buf, User_var_log_event(const char* buf, uint event_len,
const Format_description_log_event *description_event); const Format_description_log_event *description_event);
~User_var_log_event() {} ~User_var_log_event() {}
Log_event_type get_type_code() { return USER_VAR_EVENT;} Log_event_type get_type_code() { return USER_VAR_EVENT;}
...@@ -2591,7 +2591,7 @@ class User_var_log_event: public Log_event ...@@ -2591,7 +2591,7 @@ class User_var_log_event: public Log_event
bool is_deferred() { return deferred; } bool is_deferred() { return deferred; }
void set_deferred() { deferred= true; } void set_deferred() { deferred= true; }
#endif #endif
bool is_valid() const { return 1; } bool is_valid() const { return name != 0; }
private: private:
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
......
...@@ -151,6 +151,50 @@ ...@@ -151,6 +151,50 @@
*/ */
#define OPTION_ALLOW_BATCH (ULL(1) << 36) // THD, intern (slave) #define OPTION_ALLOW_BATCH (ULL(1) << 36) // THD, intern (slave)
/*
Check how many bytes are available on buffer.
@param buf_start Pointer to buffer start.
@param buf_current Pointer to the current position on buffer.
@param buf_len Buffer length.
@return Number of bytes available on event buffer.
*/
template <class T> T available_buffer(const char* buf_start,
const char* buf_current,
T buf_len)
{
return buf_len - (buf_current - buf_start);
}
/* Explicit instantion to unsigned int. */
template unsigned int available_buffer<unsigned int>(const char*,
const char*,
unsigned int);
/*
Check if jump value is within buffer limits.
@param jump Number of positions we want to advance.
@param buf_start Pointer to buffer start
@param buf_current Pointer to the current position on buffer.
@param buf_len Buffer length.
@return True If jump value is within buffer limits.
False Otherwise.
*/
template <class T> bool valid_buffer_range(T jump,
const char* buf_start,
const char* buf_current,
T buf_len)
{
return (jump <= available_buffer(buf_start, buf_current, buf_len));
}
/* Explicit instantion to unsigned int. */
template bool valid_buffer_range<unsigned int>(unsigned int,
const char*,
const char*,
unsigned int);
/* The rest of the file is included in the server only */ /* The rest of the file is included in the server only */
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment