mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge dl145h.mysql.com:/data0/mkindahl/mysql-5.0-rpl-merge
into dl145h.mysql.com:/data0/mkindahl/mysql-5.1-rpl-merge
This commit is contained in:
@ -326,6 +326,7 @@ flush logs;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
1
|
1
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
flush logs;
|
flush logs;
|
||||||
BUG#31611: Security risk with BINLOG statement
|
BUG#31611: Security risk with BINLOG statement
|
||||||
|
BIN
mysql-test/std_data/corrupt-relay-bin.000624
Normal file
BIN
mysql-test/std_data/corrupt-relay-bin.000624
Normal file
Binary file not shown.
@ -240,6 +240,10 @@ let $c= `select $a=$b`;
|
|||||||
--echo $c
|
--echo $c
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
echo shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql;
|
||||||
|
error 1;
|
||||||
|
exec $MYSQL_BINLOG $MYSQL_TEST_DIR/std_data/corrupt-relay-bin.000624 > $MYSQLTEST_VARDIR/tmp/bug31793.sql;
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--echo End of 5.0 tests
|
||||||
|
|
||||||
#
|
#
|
||||||
|
124
sql/log_event.cc
124
sql/log_event.cc
@ -1661,18 +1661,48 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
|
|||||||
|
|
||||||
/* 2 utility functions for the next method */
|
/* 2 utility functions for the next method */
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Get the pointer for a string (src) that contains the length in
|
Read a string with length from memory.
|
||||||
the first byte. Set the output string (dst) to the string value
|
|
||||||
and place the length of the string in the byte after the string.
|
This function reads the string-with-length stored at
|
||||||
|
<code>src</code> and extract the length into <code>*len</code> and
|
||||||
|
a pointer to the start of the string into <code>*dst</code>. The
|
||||||
|
string can then be copied using <code>memcpy()</code> with the
|
||||||
|
number of bytes given in <code>*len</code>.
|
||||||
|
|
||||||
|
@param src Pointer to variable holding a pointer to the memory to
|
||||||
|
read the string from.
|
||||||
|
@param dst Pointer to variable holding a pointer where the actual
|
||||||
|
string starts. Starting from this position, the string
|
||||||
|
can be copied using @c memcpy().
|
||||||
|
@param len Pointer to variable where the length will be stored.
|
||||||
|
@param end One-past-the-end of the memory where the string is
|
||||||
|
stored.
|
||||||
|
|
||||||
|
@return Zero if the entire string can be copied successfully,
|
||||||
|
@c UINT_MAX if the length could not be read from memory
|
||||||
|
(that is, if <code>*src >= end</code>), otherwise the
|
||||||
|
number of bytes that are missing to read the full
|
||||||
|
string, which happends <code>*dst + *len >= end</code>.
|
||||||
*/
|
*/
|
||||||
static void get_str_len_and_pointer(const Log_event::Byte **src,
|
static int
|
||||||
|
get_str_len_and_pointer(const Log_event::Byte **src,
|
||||||
const char **dst,
|
const char **dst,
|
||||||
uint *len)
|
uint *len,
|
||||||
|
const Log_event::Byte *end)
|
||||||
{
|
{
|
||||||
if ((*len= **src))
|
if (*src >= end)
|
||||||
|
return -1; // Will be UINT_MAX in two-complement arithmetics
|
||||||
|
uint length= **src;
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
if (*src + length >= end)
|
||||||
|
return *src + length - end + 1; // Number of bytes missing
|
||||||
*dst= (char *)*src + 1; // Will be copied later
|
*dst= (char *)*src + 1; // Will be copied later
|
||||||
(*src)+= *len + 1;
|
}
|
||||||
|
*len= length;
|
||||||
|
*src+= length + 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_str_and_move(const char **src,
|
static void copy_str_and_move(const char **src,
|
||||||
@ -1685,6 +1715,46 @@ static void copy_str_and_move(const char **src,
|
|||||||
*(*dst)++= 0;
|
*(*dst)++= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
static char const *
|
||||||
|
code_name(int code)
|
||||||
|
{
|
||||||
|
static char buf[255];
|
||||||
|
switch (code) {
|
||||||
|
case Q_FLAGS2_CODE: return "Q_FLAGS2_CODE";
|
||||||
|
case Q_SQL_MODE_CODE: return "Q_SQL_MODE_CODE";
|
||||||
|
case Q_CATALOG_CODE: return "Q_CATALOG_CODE";
|
||||||
|
case Q_AUTO_INCREMENT: return "Q_AUTO_INCREMENT";
|
||||||
|
case Q_CHARSET_CODE: return "Q_CHARSET_CODE";
|
||||||
|
case Q_TIME_ZONE_CODE: return "Q_TIME_ZONE_CODE";
|
||||||
|
case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE";
|
||||||
|
case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE";
|
||||||
|
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
|
||||||
|
}
|
||||||
|
sprintf(buf, "CODE#%d", code);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Macro to check that there is enough space to read from memory.
|
||||||
|
|
||||||
|
@param PTR Pointer to memory
|
||||||
|
@param END End of memory
|
||||||
|
@param CNT Number of bytes that should be read.
|
||||||
|
*/
|
||||||
|
#define CHECK_SPACE(PTR,END,CNT) \
|
||||||
|
do { \
|
||||||
|
DBUG_PRINT("info", ("Read %s", code_name(pos[-1]))); \
|
||||||
|
DBUG_ASSERT((PTR) + (CNT) <= (END)); \
|
||||||
|
if ((PTR) + (CNT) > (END)) { \
|
||||||
|
DBUG_PRINT("info", ("query= 0")); \
|
||||||
|
query= 0; \
|
||||||
|
DBUG_VOID_RETURN; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Query_log_event::Query_log_event()
|
Query_log_event::Query_log_event()
|
||||||
This is used by the SQL slave thread to prepare the event before execution.
|
This is used by the SQL slave thread to prepare the event before execution.
|
||||||
@ -1737,6 +1807,19 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
if (tmp)
|
if (tmp)
|
||||||
{
|
{
|
||||||
status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET);
|
status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET);
|
||||||
|
/*
|
||||||
|
Check if status variable length is corrupt and will lead to very
|
||||||
|
wrong data. We could be even more strict and require data_len to
|
||||||
|
be even bigger, but this will suffice to catch most corruption
|
||||||
|
errors that can lead to a crash.
|
||||||
|
*/
|
||||||
|
if (status_vars_len > min(data_len, MAX_SIZE_LOG_EVENT_STATUS))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("status_vars_len (%u) > data_len (%lu); query= 0",
|
||||||
|
status_vars_len, data_len));
|
||||||
|
query= 0;
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
data_len-= status_vars_len;
|
data_len-= status_vars_len;
|
||||||
DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u",
|
DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u",
|
||||||
(uint) status_vars_len));
|
(uint) status_vars_len));
|
||||||
@ -1756,6 +1839,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
{
|
{
|
||||||
switch (*pos++) {
|
switch (*pos++) {
|
||||||
case Q_FLAGS2_CODE:
|
case Q_FLAGS2_CODE:
|
||||||
|
CHECK_SPACE(pos, end, 4);
|
||||||
flags2_inited= 1;
|
flags2_inited= 1;
|
||||||
flags2= uint4korr(pos);
|
flags2= uint4korr(pos);
|
||||||
DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2));
|
DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2));
|
||||||
@ -1766,6 +1850,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
char buff[22];
|
char buff[22];
|
||||||
#endif
|
#endif
|
||||||
|
CHECK_SPACE(pos, end, 8);
|
||||||
sql_mode_inited= 1;
|
sql_mode_inited= 1;
|
||||||
sql_mode= (ulong) uint8korr(pos); // QQ: Fix when sql_mode is ulonglong
|
sql_mode= (ulong) uint8korr(pos); // QQ: Fix when sql_mode is ulonglong
|
||||||
DBUG_PRINT("info",("In Query_log_event, read sql_mode: %s",
|
DBUG_PRINT("info",("In Query_log_event, read sql_mode: %s",
|
||||||
@ -1774,15 +1859,24 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Q_CATALOG_NZ_CODE:
|
case Q_CATALOG_NZ_CODE:
|
||||||
get_str_len_and_pointer(&pos, &catalog, &catalog_len);
|
DBUG_PRINT("info", ("case Q_CATALOG_NZ_CODE; pos: 0x%lx; end: 0x%lx",
|
||||||
|
(ulong) pos, (ulong) end));
|
||||||
|
if (get_str_len_and_pointer(&pos, &catalog, &catalog_len, end))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("query= 0"));
|
||||||
|
query= 0;
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Q_AUTO_INCREMENT:
|
case Q_AUTO_INCREMENT:
|
||||||
|
CHECK_SPACE(pos, end, 4);
|
||||||
auto_increment_increment= uint2korr(pos);
|
auto_increment_increment= uint2korr(pos);
|
||||||
auto_increment_offset= uint2korr(pos+2);
|
auto_increment_offset= uint2korr(pos+2);
|
||||||
pos+= 4;
|
pos+= 4;
|
||||||
break;
|
break;
|
||||||
case Q_CHARSET_CODE:
|
case Q_CHARSET_CODE:
|
||||||
{
|
{
|
||||||
|
CHECK_SPACE(pos, end, 6);
|
||||||
charset_inited= 1;
|
charset_inited= 1;
|
||||||
memcpy(charset, pos, 6);
|
memcpy(charset, pos, 6);
|
||||||
pos+= 6;
|
pos+= 6;
|
||||||
@ -1790,20 +1884,29 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
}
|
}
|
||||||
case Q_TIME_ZONE_CODE:
|
case Q_TIME_ZONE_CODE:
|
||||||
{
|
{
|
||||||
get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len);
|
if (get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len, end))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("Q_TIME_ZONE_CODE: query= 0"));
|
||||||
|
query= 0;
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
|
case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
|
||||||
|
CHECK_SPACE(pos, end, 1);
|
||||||
if ((catalog_len= *pos))
|
if ((catalog_len= *pos))
|
||||||
catalog= (char*) pos+1; // Will be copied later
|
catalog= (char*) pos+1; // Will be copied later
|
||||||
|
CHECK_SPACE(pos, end, catalog_len + 2);
|
||||||
pos+= catalog_len+2; // leap over end 0
|
pos+= catalog_len+2; // leap over end 0
|
||||||
catalog_nz= 0; // catalog has end 0 in event
|
catalog_nz= 0; // catalog has end 0 in event
|
||||||
break;
|
break;
|
||||||
case Q_LC_TIME_NAMES_CODE:
|
case Q_LC_TIME_NAMES_CODE:
|
||||||
|
CHECK_SPACE(pos, end, 2);
|
||||||
lc_time_names_number= uint2korr(pos);
|
lc_time_names_number= uint2korr(pos);
|
||||||
pos+= 2;
|
pos+= 2;
|
||||||
break;
|
break;
|
||||||
case Q_CHARSET_DATABASE_CODE:
|
case Q_CHARSET_DATABASE_CODE:
|
||||||
|
CHECK_SPACE(pos, end, 2);
|
||||||
charset_database_number= uint2korr(pos);
|
charset_database_number= uint2korr(pos);
|
||||||
pos+= 2;
|
pos+= 2;
|
||||||
break;
|
break;
|
||||||
@ -2317,6 +2420,7 @@ end:
|
|||||||
*/
|
*/
|
||||||
thd->catalog= 0;
|
thd->catalog= 0;
|
||||||
thd->set_db(NULL, 0); /* will free the current database */
|
thd->set_db(NULL, 0); /* will free the current database */
|
||||||
|
DBUG_PRINT("info", ("end: query= 0"));
|
||||||
thd->query= 0; // just to be sure
|
thd->query= 0; // just to be sure
|
||||||
thd->query_length= 0;
|
thd->query_length= 0;
|
||||||
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
||||||
|
Reference in New Issue
Block a user