BUG#38174 secure-file-priv breaks LOAD DATA INFILE replication in statement mode
If secure-file-priv was set on slave, it became unable to execute LOAD DATA INFILE statements sent from master using mixed or statement-based replication. This patch fixes the issue by ignoring this security restriction and checking if the files are created and read by the slave in the --slave-load-tmpdir while executing the SQL Thread.
This commit is contained in:
parent
9b36597ac1
commit
d822ab8957
10
mysql-test/suite/rpl/r/rpl_slave_load_in.result
Normal file
10
mysql-test/suite/rpl/r/rpl_slave_load_in.result
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
stop slave;
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
reset master;
|
||||||
|
reset slave;
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
start slave;
|
||||||
|
create table t1(a int not null auto_increment, b int, primary key(a));
|
||||||
|
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
|
||||||
|
Comparing tables master:test.t1 and slave:test.t1
|
||||||
|
drop table t1;
|
35
mysql-test/suite/rpl/t/rpl_slave_load_in.test
Normal file
35
mysql-test/suite/rpl/t/rpl_slave_load_in.test
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
##########################################################################
|
||||||
|
# This test verifies if a slave is able to process a "LOAD DATA INFILE"
|
||||||
|
# event while the "--secure-file-priv" option is set.
|
||||||
|
#
|
||||||
|
# The test is divided in two steps:
|
||||||
|
# 1 - Creates a table and populates it through "LOAD DATA INFILE".
|
||||||
|
# 2 - Compares the master and slave.
|
||||||
|
##########################################################################
|
||||||
|
source include/master-slave.inc;
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Loading data
|
||||||
|
##########################################################################
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
create table t1(a int not null auto_increment, b int, primary key(a));
|
||||||
|
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Checking Consistency
|
||||||
|
##########################################################################
|
||||||
|
sync_slave_with_master;
|
||||||
|
|
||||||
|
let $diff_table_1=master:test.t1;
|
||||||
|
let $diff_table_2=slave:test.t1;
|
||||||
|
source include/diff_tables.inc;
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Clean up
|
||||||
|
##########################################################################
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
sync_slave_with_master;
|
@ -354,7 +354,7 @@ static char *slave_load_file_stem(char *buf, uint file_id,
|
|||||||
int event_server_id, const char *ext)
|
int event_server_id, const char *ext)
|
||||||
{
|
{
|
||||||
char *res;
|
char *res;
|
||||||
fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME);
|
fn_format(buf,PREFIX_SQL_LOAD,slave_load_tmpdir, "", MY_UNPACK_FILENAME);
|
||||||
to_unix_path(buf);
|
to_unix_path(buf);
|
||||||
|
|
||||||
buf = strend(buf);
|
buf = strend(buf);
|
||||||
@ -393,7 +393,7 @@ static void cleanup_load_tmpdir()
|
|||||||
we cannot meet Start_log event in the middle of events from one
|
we cannot meet Start_log event in the middle of events from one
|
||||||
LOAD DATA.
|
LOAD DATA.
|
||||||
*/
|
*/
|
||||||
p= strmake(prefbuf, STRING_WITH_LEN("SQL_LOAD-"));
|
p= strmake(prefbuf, STRING_WITH_LEN(PREFIX_SQL_LOAD));
|
||||||
p= int10_to_str(::server_id, p, 10);
|
p= int10_to_str(::server_id, p, 10);
|
||||||
*(p++)= '-';
|
*(p++)= '-';
|
||||||
*p= 0;
|
*p= 0;
|
||||||
|
@ -47,6 +47,8 @@
|
|||||||
#include "rpl_reporting.h"
|
#include "rpl_reporting.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PREFIX_SQL_LOAD "SQL_LOAD-"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Either assert or return an error.
|
Either assert or return an error.
|
||||||
|
|
||||||
|
@ -104,6 +104,12 @@ int init_relay_log_info(Relay_log_info* rli,
|
|||||||
rli->tables_to_lock= 0;
|
rli->tables_to_lock= 0;
|
||||||
rli->tables_to_lock_count= 0;
|
rli->tables_to_lock_count= 0;
|
||||||
|
|
||||||
|
fn_format(rli->slave_patternload_file, PREFIX_SQL_LOAD, slave_load_tmpdir, "",
|
||||||
|
MY_PACK_FILENAME | MY_UNPACK_FILENAME |
|
||||||
|
MY_RETURN_REAL_PATH);
|
||||||
|
to_unix_path(rli->slave_patternload_file);
|
||||||
|
rli->slave_patternload_file_size= strlen(rli->slave_patternload_file);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
|
The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
|
||||||
Note that the I/O thread flushes it to disk after writing every
|
Note that the I/O thread flushes it to disk after writing every
|
||||||
|
@ -260,6 +260,13 @@ public:
|
|||||||
char ign_master_log_name_end[FN_REFLEN];
|
char ign_master_log_name_end[FN_REFLEN];
|
||||||
ulonglong ign_master_log_pos_end;
|
ulonglong ign_master_log_pos_end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Indentifies where the SQL Thread should create temporary files for the
|
||||||
|
LOAD DATA INFILE. This is used for security reasons.
|
||||||
|
*/
|
||||||
|
char slave_patternload_file[FN_REFLEN];
|
||||||
|
size_t slave_patternload_file_size;
|
||||||
|
|
||||||
Relay_log_info();
|
Relay_log_info();
|
||||||
~Relay_log_info();
|
~Relay_log_info();
|
||||||
|
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Copy data from a textfile to table */
|
/* Copy data from a textfile to table */
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include "sql_repl.h"
|
#include "sql_repl.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
#include "sql_trigger.h"
|
#include "sql_trigger.h"
|
||||||
@ -310,8 +310,31 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
is_fifo = 1;
|
is_fifo = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (opt_secure_file_priv &&
|
if (thd->slave_thread)
|
||||||
strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
|
{
|
||||||
|
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
||||||
|
if (strncmp(active_mi->rli.slave_patternload_file, name,
|
||||||
|
active_mi->rli.slave_patternload_file_size))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
LOAD DATA INFILE in the slave SQL Thread can only read from
|
||||||
|
--slave-load-tmpdir". This should never happen. Please, report a bug.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sql_print_error("LOAD DATA INFILE in the slave SQL Thread can only read from --slave-load-tmpdir. " \
|
||||||
|
"Please, report a bug.");
|
||||||
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--slave-load-tmpdir");
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
This is impossible and should never happen.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(FALSE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (opt_secure_file_priv &&
|
||||||
|
strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
|
||||||
{
|
{
|
||||||
/* Read only allowed from within dir specified by 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");
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user