diff options
-rw-r--r-- | include/mysql_com.h | 10 | ||||
-rw-r--r-- | mysql-test/r/explain.result | 12 | ||||
-rw-r--r-- | mysql-test/r/loaddata.result | 6 | ||||
-rw-r--r-- | mysql-test/r/ps.result | 12 | ||||
-rw-r--r-- | mysql-test/r/trigger.result | 23 | ||||
-rw-r--r-- | mysql-test/t/explain.test | 13 | ||||
-rw-r--r-- | mysql-test/t/loaddata.test | 14 | ||||
-rw-r--r-- | mysql-test/t/trigger.test | 31 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 3 | ||||
-rw-r--r-- | sql/mysqld.cc | 46 | ||||
-rw-r--r-- | sql/mysqld.h | 1 | ||||
-rw-r--r-- | sql/net_serv.cc | 4 | ||||
-rw-r--r-- | sql/sp_head.cc | 34 | ||||
-rw-r--r-- | sql/sp_head.h | 4 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_connect.cc | 7 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_load.cc | 11 | ||||
-rw-r--r-- | sql/sql_select.cc | 3 |
19 files changed, 180 insertions, 58 deletions
diff --git a/include/mysql_com.h b/include/mysql_com.h index e4e34141d43..e2baa06b160 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -300,6 +300,16 @@ typedef struct st_net { /** Client library sqlstate buffer. Set along with the error message. */ char sqlstate[SQLSTATE_LENGTH+1]; void *extension; +#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) + /* + Controls whether a big packet should be skipped. + + Initially set to FALSE by default. Unauthenticated sessions must have + this set to FALSE so that the server can't be tricked to read packets + indefinitely. + */ + my_bool skip_big_packet; +#endif } NET; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 9740303c00e..7042a2c6f6c 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -246,4 +246,16 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select '1' AS `f1`,`test`.`t2`.`f2` AS `f2` from `test`.`t2` where (`test`.`t2`.`f2` = 1) drop table t1,t2; +# +# Bug #48419: another explain crash.. +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b BLOB, KEY b(b(100))); +INSERT INTO t2 VALUES ('1'), ('2'), ('3'); +FLUSH TABLES; +EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT 1 FROM t1 t JOIN t2 WHERE b <= 1 AND t.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1, t2; End of 5.1 tests. diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 9969147a93e..7a79603adb3 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -202,12 +202,6 @@ select * from t1; a b c 10 NULL Ten 15 NULL Fifteen -show variables like "secure_file_pri%"; -Variable_name Value -secure_file_priv MYSQLTEST_VARDIR -select @@secure_file_priv; -@@secure_file_priv -MYSQLTEST_VARDIR set @@secure_file_priv= 0; ERROR HY000: Variable 'secure_file_priv' is a read only variable truncate table t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 5ac8ec78f2d..16f6657ceeb 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -155,24 +155,24 @@ execute stmt1 ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 6 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table -5 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found -4 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +5 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +4 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables execute stmt1 ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 6 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table -5 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found -4 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +5 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +4 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 6 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table -5 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found -4 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +5 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +4 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables deallocate prepare stmt1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 1cc9e57772b..e303c16fdd2 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -2128,6 +2128,29 @@ Warning 1048 Column 'id' cannot be null Warning 1048 Column 'id' cannot be null DROP TRIGGER t1_bu; DROP TABLE t1,t2; +# +# Bug#50755: Crash if stored routine def contains version comments +# +DROP DATABASE IF EXISTS db1; +DROP TRIGGER IF EXISTS trg1; +DROP TABLE IF EXISTS t1, t2; +CREATE DATABASE db1; +USE db1; +CREATE TABLE t1 (b INT); +CREATE TABLE t2 (a INT); +CREATE TRIGGER trg1 BEFORE INSERT ON t2 FOR EACH ROW INSERT/*!INTO*/t1 VALUES (1); +# Used to crash +SHOW TRIGGERS IN db1; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +Warnings: +Warning 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1 +INSERT INTO t2 VALUES (1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1 +SELECT * FROM t1; +b +# Work around Bug#45235 +DROP DATABASE db1; +USE test; End of 5.1 tests. # # Bug#34453 Can't change size of file (Errcode: 1224) diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 30366f6f67e..72406110de1 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -210,4 +210,17 @@ explain extended select * from t1 where f1=1; explain extended select * from t1 join t2 on f1=f2 where f1=1; drop table t1,t2; +--echo # +--echo # Bug #48419: another explain crash.. +--echo # +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b BLOB, KEY b(b(100))); +INSERT INTO t2 VALUES ('1'), ('2'), ('3'); + +FLUSH TABLES; + +EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT 1 FROM t1 t JOIN t2 WHERE b <= 1 AND t.a); + +DROP TABLE t1, t2; + --echo End of 5.1 tests. diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index e5f0a1d7eba..126bd5c8838 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -153,10 +153,16 @@ select * from t1; # # It should not be possible to load from a file outside of vardir ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -show variables like "secure_file_pri%"; ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -select @@secure_file_priv; +## The following lines were disabled because of patch for +## bug 50373. MYSQLTEST_VARDIR doesn't rewrite symlinks +## to real paths, but this is done for secure_file_priv. +## Because of this the result can't be replaced if the +## test suite runs with the --mem option which creates +## symlinks to the ramdisk. +#--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +#show variables like "secure_file_pri%"; +#--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +#select @@secure_file_priv; --error 1238 set @@secure_file_priv= 0; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index e929b4b39cc..2eb086cace5 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2439,6 +2439,37 @@ UPDATE t1 SET id=NULL; DROP TRIGGER t1_bu; DROP TABLE t1,t2; +--echo # +--echo # Bug#50755: Crash if stored routine def contains version comments +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +DROP TRIGGER IF EXISTS trg1; +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE DATABASE db1; +USE db1; + +CREATE TABLE t1 (b INT); +CREATE TABLE t2 (a INT); + +CREATE TRIGGER trg1 BEFORE INSERT ON t2 FOR EACH ROW INSERT/*!INTO*/t1 VALUES (1); +--echo # Used to crash +SHOW TRIGGERS IN db1; +--error ER_PARSE_ERROR +INSERT INTO t2 VALUES (1); +SELECT * FROM t1; + +--echo # Work around Bug#45235 +let $MYSQLD_DATADIR = `select @@datadir`; +--remove_file $MYSQLD_DATADIR/db1/t2.TRG +--remove_file $MYSQLD_DATADIR/db1/trg1.TRN + +DROP DATABASE db1; +USE test; + --echo End of 5.1 tests. diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 15ac6e24b16..61febb01e93 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3192,8 +3192,7 @@ String *Item_load_file::val_str(String *str) MY_RELATIVE_PATH | MY_UNPACK_FILENAME); /* Read only allowed from within dir specified by secure_file_priv */ - if (opt_secure_file_priv && - strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv))) + if (!is_secure_file_path(path)) goto err; if (!mysql_file_stat(key_file_loadfile, path, &stat_info, MYF(0))) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2c90aa8fbf5..950ba55a5bd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7711,6 +7711,45 @@ fn_format_relative_to_data_home(char * to, const char *name, } +/** + Test a file path to determine if the path is compatible with the secure file + path restriction. + + @param path null terminated character string + + @return + @retval TRUE The path is secure + @retval FALSE The path isn't secure +*/ + +bool is_secure_file_path(char *path) +{ + char buff1[FN_REFLEN], buff2[FN_REFLEN]; + /* + All paths are secure if opt_secure_file_path is 0 + */ + if (!opt_secure_file_priv) + return TRUE; + + if (my_realpath(buff1, path, 0)) + { + /* + The supplied file path might have been a file and not a directory. + */ + int length= (int)dirname_length(path); + if (length >= FN_REFLEN) + return FALSE; + memcpy(buff2, path, length); + buff2[length]= '\0'; + if (length == 0 || my_realpath(buff1, buff2, 0)) + return FALSE; + } + convert_dirname(buff2, buff1, NullS); + if (strncmp(opt_secure_file_priv, buff2, strlen(opt_secure_file_priv))) + return FALSE; + return TRUE; +} + static int fix_paths(void) { char buff[FN_REFLEN],*pos; @@ -7777,14 +7816,13 @@ static int fix_paths(void) } else { - convert_dirname(buff, opt_secure_file_priv, NullS); - char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); - if (secure_file_real_path == 0 || - my_realpath(secure_file_real_path, buff, 0)) + if (my_realpath(buff, opt_secure_file_priv, 0)) { sql_print_warning("Failed to normalize the argument for --secure-file-priv."); return 1; } + char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); + convert_dirname(secure_file_real_path, buff, NullS); my_free(opt_secure_file_priv, MYF(0)); opt_secure_file_priv= secure_file_real_path; } diff --git a/sql/mysqld.h b/sql/mysqld.h index 8770e273445..9a6e43e4321 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -71,6 +71,7 @@ void unlink_thd(THD *thd); bool one_thread_per_connection_end(THD *thd, bool put_in_cache); void flush_thread_cache(); void refresh_status(THD *thd); +bool is_secure_file_path(char *path); extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index fc8655ea2e7..28ed4cbdbaf 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -133,6 +133,9 @@ my_bool my_net_init(NET *net, Vio* vio) net->where_b = net->remain_in_buf=0; net->last_errno=0; net->unused= 0; +#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) + net->skip_big_packet= FALSE; +#endif if (vio != 0) /* If real connection */ { @@ -967,6 +970,7 @@ my_real_read(NET *net, size_t *complen) { #if defined(MYSQL_SERVER) && !defined(NO_ALARM) if (!net->compress && + net->skip_big_packet && !my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff)) net->error= 3; /* Successfully skiped packet */ #endif diff --git a/sql/sp_head.cc b/sql/sp_head.cc index dee01ee0b62..e833a540032 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -747,21 +747,12 @@ create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src) sp_head::~sp_head() { + LEX *lex; + sp_instr *i; DBUG_ENTER("sp_head::~sp_head"); - destroy(); - delete m_next_cached_sp; - if (m_thd) - restore_thd_mem_root(m_thd); - DBUG_VOID_RETURN; -} -void -sp_head::destroy() -{ - sp_instr *i; - LEX *lex; - DBUG_ENTER("sp_head::destroy"); - DBUG_PRINT("info", ("name: %s", m_name.str)); + /* sp_head::restore_thd_mem_root() must already have been called. */ + DBUG_ASSERT(m_thd == NULL); for (uint ip = 0 ; (i = get_instr(ip)) ; ip++) delete i; @@ -772,21 +763,22 @@ sp_head::destroy() /* If we have non-empty LEX stack then we just came out of parser with error. Now we should delete all auxilary LEXes and restore original - THD::lex (In this case sp_head::restore_thd_mem_root() was not called - too, so m_thd points to the current thread context). - It is safe to not update LEX::ptr because further query string parsing - and execution will be stopped anyway. + THD::lex. It is safe to not update LEX::ptr because further query + string parsing and execution will be stopped anyway. */ - DBUG_ASSERT(m_lex.is_empty() || m_thd); while ((lex= (LEX *)m_lex.pop())) { - lex_end(m_thd->lex); - delete m_thd->lex; - m_thd->lex= lex; + THD *thd= lex->thd; + lex_end(thd->lex); + delete thd->lex; + thd->lex= lex; } my_hash_free(&m_sptabs); my_hash_free(&m_sroutines); + + delete m_next_cached_sp; + DBUG_VOID_RETURN; } diff --git a/sql/sp_head.h b/sql/sp_head.h index 165f88321a9..539a2da5f8c 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -305,10 +305,6 @@ public: virtual ~sp_head(); - /// Free memory - void - destroy(); - bool execute_trigger(THD *thd, const LEX_STRING *db_name, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f59ffd4d42f..914ef5c919a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1917,8 +1917,7 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange, else (void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option); - if (opt_secure_file_priv && - strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv))) + if (!is_secure_file_path(path)) { /* Write only allowed to dir or subdir specified by secure_file_priv */ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index e2d0977def7..c0081c13366 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -496,6 +496,13 @@ check_user(THD *thd, enum enum_server_command command, } my_ok(thd); thd->password= test(passwd_len); // remember for error messages + /* + Allow the network layer to skip big packets. Although a malicious + authenticated session might use this to trick the server to read + big packets indefinitely, this is a previously established behavior + that needs to be preserved as to not break backwards compatibility. + */ + thd->net.skip_big_packet= TRUE; /* Ready to handle queries */ DBUG_RETURN(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 13f85b24299..f44edfdf6fb 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2194,6 +2194,7 @@ void LEX::cleanup_lex_after_parse_error(THD *thd) */ if (thd->lex->sphead) { + thd->lex->sphead->restore_thd_mem_root(thd); delete thd->lex->sphead; thd->lex->sphead= NULL; } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 77068f3d83b..59d30b020e8 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -394,14 +394,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_ASSERT(FALSE); #endif } - else if (opt_secure_file_priv) + else if (!is_secure_file_path(name)) { - if (strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv))) - { - /* Read only allowed from within dir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); - DBUG_RETURN(TRUE); - } + /* Read only allowed from within dir specified by secure_file_priv */ + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + DBUG_RETURN(TRUE); } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e8809564bce..21178f828c1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1127,8 +1127,7 @@ JOIN::optimize() } if (conds && const_table_map != found_const_table_map && - (select_options & SELECT_DESCRIBE) && - select_lex->master_unit() == &thd->lex->unit) // upper level SELECT + (select_options & SELECT_DESCRIBE)) { conds=new Item_int((longlong) 0,1); // Always false } |