Commit b85a0016 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-8264 encryption for binlog

* Start_encryption_log_event
* --encrypt-binlog command line option

based on google patches.
parent 41d68cab
......@@ -2575,6 +2575,11 @@ void *sql_alloc(size_t size)
return alloc_root(&s_mem_root, size);
}
struct encryption_service_st encryption_handler=
{
0, 0, 0, 0, 0, 0, 0
};
/*
We must include this here as it's compiled with different options for
the server
......
......@@ -10,19 +10,19 @@
#
# Format_description_log_event length =
# 19 /* event common header */ +
# 57 /* misc stuff in the Format description header */ +
# 58 /* misc stuff in the Format description header */ +
# number of events +
# 1 /* Checksum algorithm */ +
# 4 /* CRC32 length */
#
# With current number of events = 163,
# With current number of events = 164,
#
# binlog_start_pos = 4 + 19 + 57 + 163 + 1 + 4 = 248.
# binlog_start_pos = 4 + 19 + 57 + 163 + 1 + 4 = 249.
#
##############################################################################
let $binlog_start_pos=248;
let $binlog_start_pos=249;
--disable_query_log
SET @binlog_start_pos=248;
SET @binlog_start_pos=249;
--enable_query_log
......@@ -4,7 +4,7 @@ if ($binlog_start)
}
if (!$binlog_start)
{
--let $_binlog_start=248
--let $_binlog_start=249
}
if ($binlog_file)
{
......
......@@ -176,6 +176,8 @@ The following options may be given as the first argument:
--div-precision-increment=#
Precision of the result of '/' operator will be increased
on that value
--encrypt-binlog Encrypt binary logs (including relay logs)
(Defaults to on; use --skip-encrypt-binlog to disable.)
--encrypt-tmp-disk-tables
Encrypt temporary on-disk tables (created as part of
query execution)
......@@ -1170,6 +1172,7 @@ delayed-insert-limit 100
delayed-insert-timeout 300
delayed-queue-size 1000
div-precision-increment 4
encrypt-binlog TRUE
encrypt-tmp-disk-tables FALSE
encrypt-tmp-files TRUE
enforce-storage-engine (No default value)
......
......@@ -71,7 +71,7 @@ insert into t1 values (1) /* will not be applied on slave due to simulation */;
set @@global.debug_dbug='d,simulate_slave_unaware_checksum';
start slave;
include/wait_for_slave_io_error.inc [errno=1236]
Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 367, the last event read from 'master-bin.000010' at 4, the last byte read from 'master-bin.000010' at 248.''
Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 368, the last event read from 'master-bin.000010' at 4, the last byte read from 'master-bin.000010' at 249.''
select count(*) as zero from t1;
zero
0
......
......@@ -695,6 +695,20 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME ENCRYPT_BINLOG
SESSION_VALUE NULL
GLOBAL_VALUE ON
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE ON
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Encrypt binary logs (including relay logs)
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME ENCRYPT_TMP_DISK_TABLES
SESSION_VALUE NULL
GLOBAL_VALUE OFF
......
......@@ -709,6 +709,20 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME ENCRYPT_BINLOG
SESSION_VALUE NULL
GLOBAL_VALUE ON
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE ON
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Encrypt binary logs (including relay logs)
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME ENCRYPT_TMP_DISK_TABLES
SESSION_VALUE NULL
GLOBAL_VALUE OFF
......
......@@ -3457,6 +3457,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
else
s.checksum_alg= (enum_binlog_checksum_alg)binlog_checksum_options;
crypto.scheme = 0;
DBUG_ASSERT(s.checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
if (!s.is_valid())
goto err;
......@@ -3465,6 +3466,26 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
goto err;
bytes_written+= s.data_written;
if (encrypt_binlog)
{
uint key_version= encryption_key_get_latest_version(ENCRYPTION_KEY_SYSTEM_DATA);
if (key_version != ENCRYPTION_KEY_VERSION_INVALID &&
key_version != ENCRYPTION_KEY_NOT_ENCRYPTED)
{
if (my_random_bytes(crypto.nonce, sizeof(crypto.nonce)))
goto err;
Start_encryption_log_event sele(1, key_version, crypto.nonce);
sele.checksum_alg= s.checksum_alg;
if (write_event(&sele))
goto err;
// Start_encryption_log_event is written, enable the encryption
if (crypto.init(sele.crypto_scheme, key_version))
goto err;
}
}
if (!is_relay_log)
{
char buf[FN_REFLEN];
......@@ -5107,7 +5128,10 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
bool MYSQL_BIN_LOG::write_event(Log_event *ev, IO_CACHE *file)
{
Log_event_writer writer(file);
Log_event_writer writer(file, &crypto);
if (crypto.scheme && file == &log_file)
writer.ctx= alloca(crypto.ctx_size);
return writer.write(ev);
}
......@@ -5145,32 +5169,62 @@ bool MYSQL_BIN_LOG::append_no_lock(Log_event* ev)
DBUG_RETURN(error);
}
bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
bool MYSQL_BIN_LOG::write_event_buffer(uchar* buf, uint len)
{
bool error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::appendv");
va_list(args);
va_start(args,len);
bool error= 1;
uchar *ebuf= 0;
DBUG_ENTER("MYSQL_BIN_LOG::write_event_buffer");
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
mysql_mutex_assert_owner(&LOCK_log);
do
if (crypto.scheme != 0)
{
if (my_b_append(&log_file,(uchar*) buf,len))
{
error= 1;
DBUG_ASSERT(crypto.scheme == 1);
uint elen;
uchar iv[BINLOG_IV_LENGTH];
ebuf= (uchar*)my_safe_alloca(len);
if (!ebuf)
goto err;
}
bytes_written += len;
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
crypto.set_iv(iv, my_b_append_tell(&log_file));
/*
we want to encrypt everything, excluding the event length:
massage the data before the encryption
*/
memcpy(buf + EVENT_LEN_OFFSET, buf, 4);
if (encryption_crypt(buf + 4, len - 4,
ebuf + 4, &elen,
crypto.key, crypto.key_length, iv, sizeof(iv),
ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
ENCRYPTION_KEY_SYSTEM_DATA, crypto.key_version))
goto err;
DBUG_ASSERT(elen == len - 4);
/* massage the data after the encryption */
memcpy(ebuf, ebuf + EVENT_LEN_OFFSET, 4);
int4store(ebuf + EVENT_LEN_OFFSET, len);
buf= ebuf;
}
if (my_b_append(&log_file, buf, len))
goto err;
bytes_written+= len;
error= 0;
DBUG_PRINT("info",("max_size: %lu",max_size));
if (flush_and_sync(0))
goto err;
if (my_b_append_tell(&log_file) > max_size)
error= new_file_without_locking();
err:
my_safe_afree(ebuf, len);
if (!error)
signal_update();
DBUG_RETURN(error);
......@@ -6533,8 +6587,9 @@ class CacheWriter: public Log_event_writer
public:
ulong remains;
CacheWriter(THD *thd_arg, IO_CACHE *file_arg, bool do_checksum)
: Log_event_writer(file_arg), remains(0), thd(thd_arg), first(true)
CacheWriter(THD *thd_arg, IO_CACHE *file_arg, bool do_checksum,
Binlog_crypt_data *cr)
: Log_event_writer(file_arg, cr), remains(0), thd(thd_arg), first(true)
{ checksum_len= do_checksum ? BINLOG_CHECKSUM_LEN : 0; }
~CacheWriter()
......@@ -6585,7 +6640,10 @@ int MYSQL_BIN_LOG::write_cache(THD *thd, IO_CACHE *cache)
long val;
ulong end_log_pos_inc= 0; // each event processed adds BINLOG_CHECKSUM_LEN 2 t
uchar header[LOG_EVENT_HEADER_LEN];
CacheWriter writer(thd, &log_file, binlog_checksum_options);
CacheWriter writer(thd, &log_file, binlog_checksum_options, &crypto);
if (crypto.scheme)
writer.ctx= alloca(crypto.ctx_size);
// while there is just one alg the following must hold:
DBUG_ASSERT(binlog_checksum_options == BINLOG_CHECKSUM_ALG_OFF ||
......@@ -9670,6 +9728,13 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
break;
#endif
case START_ENCRYPTION_EVENT:
{
if (fdle->start_decryption((Start_encryption_log_event*) ev))
goto err2;
}
break;
default:
/* Nothing. */
break;
......@@ -9746,6 +9811,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
sql_print_error("Error reading binlog files during recovery. Aborting.");
goto err2;
}
fdle->reset_crypto();
}
if (do_xa)
......
......@@ -527,6 +527,9 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
ulonglong group_commit_trigger_count, group_commit_trigger_timeout;
ulonglong group_commit_trigger_lock_wait;
/* binlog encryption data */
struct Binlog_crypt_data crypto;
/* pointer to the sync period variable, for binlog this will be
sync_binlog_period, for relay log this will be
sync_relay_log_period
......@@ -740,11 +743,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
bool write_event(Log_event *ev, IO_CACHE *file);
bool write_event(Log_event *ev) { return write_event(ev, &log_file); }
/*
v stands for vector
invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
*/
bool appendv(const char* buf,uint len,...);
bool write_event_buffer(uchar* buf,uint len);
bool append(Log_event* ev);
bool append_no_lock(Log_event* ev);
......
This diff is collapsed.
......@@ -81,6 +81,7 @@ class String;
#define LOG_READ_TRUNC -6
#define LOG_READ_TOO_LARGE -7
#define LOG_READ_CHECKSUM_FAILURE -8
#define LOG_READ_DECRYPT -9
#define LOG_EVENT_OFFSET 4
......@@ -211,6 +212,7 @@ class String;
#define BINLOG_CHECKPOINT_HEADER_LEN 4
#define GTID_HEADER_LEN 19
#define GTID_LIST_HEADER_LEN 4
#define START_ENCRYPTION_HEADER_LEN 0
/*
Max number of possible extra bytes in a replication event compared to a
......@@ -666,6 +668,8 @@ enum Log_event_type
*/
GTID_LIST_EVENT= 163,
START_ENCRYPTION_EVENT= 164,
/* Add new MariaDB events here - right above this comment! */
ENUM_END_EVENT /* end marker */
......@@ -790,12 +794,13 @@ typedef struct st_print_event_info
/**
This class encapsulates writing of Log_event objects to IO_CACHE.
Automatically calculates the checksum if necessary.
Automatically calculates the checksum and encrypts the data, if necessary.
*/
class Log_event_writer
{
public:
ulonglong bytes_written;
void *ctx; ///< Encryption context or 0 if no encryption is needed
uint checksum_len;
int write(Log_event *ev);
int write_header(uchar *pos, size_t len);
......@@ -803,7 +808,9 @@ class Log_event_writer
int write_footer();
my_off_t pos() { return my_b_safe_tell(file); }
Log_event_writer(IO_CACHE *file_arg) : bytes_written(0), file(file_arg) { }
Log_event_writer(IO_CACHE *file_arg, Binlog_crypt_data *cr= 0)
: bytes_written(0), ctx(0),
file(file_arg), crypto(cr) { }
private:
IO_CACHE *file;
......@@ -811,8 +818,17 @@ Log_event_writer(IO_CACHE *file_arg) : bytes_written(0), file(file_arg) { }
Placeholder for event checksum while writing to binlog.
*/
ha_checksum crc;
/**
Encryption data (key, nonce). Only used if ctx != 0.
*/
Binlog_crypt_data *crypto;
/**
Event length to be written into the next encrypted block
*/
uint event_len;
int write_internal(const uchar *pos, size_t len);
int encrypt_and_write(const uchar *pos, size_t len);
int maybe_write_event_len(uchar *pos, size_t len);
};
/**
......@@ -1163,6 +1179,7 @@ class Log_event
@retval LOG_READ_TOO_LARGE event too large
*/
static int read_log_event(IO_CACHE* file, String* packet,
const Format_description_log_event *fdle,
enum enum_binlog_checksum_alg checksum_alg_arg);
/*
The value is set by caller of FD constructor and
......@@ -1289,7 +1306,6 @@ class Log_event
const char* get_type_str();
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
public:
/**
Apply the event to the database.
......@@ -1381,6 +1397,7 @@ class Log_event
case HEARTBEAT_LOG_EVENT:
case BINLOG_CHECKPOINT_EVENT:
case GTID_LIST_EVENT:
case START_ENCRYPTION_EVENT:
return false;
default:
......@@ -2457,6 +2474,73 @@ class Start_log_event_v3: public Log_event
#endif
};
/**
@class Start_encryption_log_event
Start_encryption_log_event marks the beginning of encrypted data (all events
after this event are encrypted).
It contains the cryptographic scheme used for the encryption as well as any
data required to decrypt (except the actual key).
For binlog cryptoscheme 1: key version, and nonce for iv generation.
*/
class Start_encryption_log_event : public Log_event
{
public:
#ifdef MYSQL_SERVER
Start_encryption_log_event(uint crypto_scheme_arg, uint key_version_arg,
const uchar* nonce_arg)
: crypto_scheme(crypto_scheme_arg), key_version(key_version_arg)
{
cache_type = EVENT_NO_CACHE;
DBUG_ASSERT(crypto_scheme == 1);
memcpy(nonce, nonce_arg, BINLOG_NONCE_LENGTH);
}
bool write_data_body()
{
uchar scheme_buf= crypto_scheme;
uchar key_version_buf[BINLOG_KEY_VERSION_LENGTH];
int4store(key_version_buf, key_version);
return write_data(&scheme_buf, sizeof(scheme_buf)) ||
write_data(key_version_buf, sizeof(key_version_buf)) ||
write_data(nonce, BINLOG_NONCE_LENGTH);
}
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Start_encryption_log_event(
const char* buf, uint event_len,
const Format_description_log_event* description_event);
bool is_valid() const { return crypto_scheme == 1; }
Log_event_type get_type_code() { return START_ENCRYPTION_EVENT; }
int get_data_size()
{
return BINLOG_CRYPTO_SCHEME_LENGTH + BINLOG_KEY_VERSION_LENGTH +
BINLOG_NONCE_LENGTH;
}
uint crypto_scheme;
uint key_version;
uchar nonce[BINLOG_NONCE_LENGTH];
protected:
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(rpl_group_info* rgi);
virtual int do_update_pos(rpl_group_info *rgi);
virtual enum_skip_reason do_shall_skip(rpl_group_info* rgi)
{
return Log_event::EVENT_SKIP_NOT;
}
#endif
};
/**
@class Format_description_log_event
......@@ -2534,6 +2618,17 @@ class Format_description_log_event: public Start_log_event_v3
return FORMAT_DESCRIPTION_HEADER_LEN;
}
Binlog_crypt_data crypto_data;
bool start_decryption(Start_encryption_log_event* sele);
void copy_crypto_data(const Format_description_log_event* o)
{
crypto_data= o->crypto_data;
}
void reset_crypto()
{
crypto_data.scheme= 0;
}
void calc_server_version_split();
static bool is_version_before_checksum(const master_version_split *version_split);
protected:
......
......@@ -629,6 +629,7 @@ char server_version[SERVER_VERSION_LENGTH];
char *mysqld_unix_port, *opt_mysql_tmpdir;
ulong thread_handling;
my_bool encrypt_binlog;
my_bool encrypt_tmp_disk_tables, encrypt_tmp_files;
/** name of reference on left expression in rewritten IN subquery */
......
......@@ -255,6 +255,7 @@ extern ulong connection_errors_internal;
extern ulong connection_errors_max_connection;
extern ulong connection_errors_peer_addr;
extern ulong log_warnings;
extern my_bool encrypt_binlog;
extern my_bool encrypt_tmp_disk_tables, encrypt_tmp_files;
extern ulong encryption_algorithm;
extern const char *encryption_algorithm_names[];
......
......@@ -17,6 +17,9 @@
#ifndef RPL_CONSTANTS_H
#define RPL_CONSTANTS_H
#include <my_sys.h>
#include <my_crypt.h>
/**
Enumeration of the incidents that can occur for the server.
*/
......@@ -78,4 +81,32 @@ enum enum_binlog_checksum_alg {
// or events from checksum-unaware servers
};
#define BINLOG_CRYPTO_SCHEME_LENGTH 1
#define BINLOG_KEY_VERSION_LENGTH 4
#define BINLOG_IV_LENGTH MY_AES_BLOCK_SIZE
#define BINLOG_IV_OFFS_LENGTH 4
#define BINLOG_NONCE_LENGTH (BINLOG_IV_LENGTH - BINLOG_IV_OFFS_LENGTH)
struct Binlog_crypt_data {
uint scheme;
uint key_version, key_length, ctx_size;
uchar key[MY_AES_MAX_KEY_LENGTH];
uchar nonce[BINLOG_NONCE_LENGTH];
int init(uint sch, uint kv)
{
scheme= sch;
ctx_size= encryption_ctx_size(ENCRYPTION_KEY_SYSTEM_DATA, kv);
key_version= kv;
key_length= sizeof(key);
return encryption_key_get(ENCRYPTION_KEY_SYSTEM_DATA, kv, key, &key_length);
}
void set_iv(uchar* iv, uint32 offs) const
{
memcpy(iv, nonce, BINLOG_NONCE_LENGTH);
int4store(iv + BINLOG_NONCE_LENGTH, offs);
}
};
#endif /* RPL_CONSTANTS_H */
......@@ -570,16 +570,26 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt,
err= 1;
goto check_retry;
}
description_event->reset_crypto();
/* Loop to try again on the new log file. */
}
event_type= ev->get_type_code();
if (event_type == FORMAT_DESCRIPTION_EVENT)
{
Format_description_log_event *newde= (Format_description_log_event*)ev;
newde->copy_crypto_data(description_event);
delete description_event;
description_event= (Format_description_log_event *)ev;
description_event= newde;
continue;
} else if (!Log_event::is_group_event(event_type))
}
else if (event_type == START_ENCRYPTION_EVENT)
{
description_event->start_decryption((Start_encryption_log_event*)ev);
delete ev;
continue;
}
else if (!Log_event::is_group_event(event_type))
{
delete ev;
continue;
......
......@@ -547,9 +547,12 @@ read_relay_log_description_event(IO_CACHE *cur_log, ulonglong start_pos,
typ= ev->get_type_code();
if (typ == FORMAT_DESCRIPTION_EVENT)
{
Format_description_log_event *old= fdev;
DBUG_PRINT("info",("found Format_description_log_event"));
delete fdev;
fdev= (Format_description_log_event*) ev;
fdev->copy_crypto_data(old);
delete old;
/*
As ev was returned by read_log_event, it has passed is_valid(), so
my_malloc() in ctor worked, no need to check again.
......@@ -571,6 +574,17 @@ read_relay_log_description_event(IO_CACHE *cur_log, ulonglong start_pos,
or Format_desc.
*/
}
else if (typ == START_ENCRYPTION_EVENT)
{
if (fdev->start_decryption((Start_encryption_log_event*) ev))
{
*errmsg= "Unable to set up decryption of binlog.";
delete ev;
delete fdev;
return NULL;
}
delete ev;
}
else
{
DBUG_PRINT("info",("found event of another type=%d", typ));
......
......@@ -5607,6 +5607,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
goto err;
}
tmp->copy_crypto_data(mi->rli.relay_log.description_event_for_queue);
delete mi->rli.relay_log.description_event_for_queue;
mi->rli.relay_log.description_event_for_queue= tmp;
if (tmp->checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF)
......@@ -6028,7 +6029,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
}
else
{
if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
if (likely(!rli->relay_log.write_event_buffer((uchar*)buf, event_len)))
{
mi->master_log_pos+= inc_pos;
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
......@@ -6778,6 +6779,7 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
mysql_file_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
rli->last_inuse_relaylog->completed= true;
rli->relay_log.description_event_for_exec->reset_crypto();
if (relay_log_purge)
{
......
......@@ -644,6 +644,9 @@ void set_read_error(binlog_send_info *info, int error)
case LOG_READ_CHECKSUM_FAILURE:
info->errmsg= "event read from binlog did not pass crc check";
break;
case LOG_READ_DECRYPT:
info->errmsg= "event decryption failure";
break;
default:
info->errmsg= "unknown error reading log event on the master";
break;
......@@ -918,9 +921,14 @@ get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list)
typ= ev->get_type_code();
if (typ == GTID_LIST_EVENT)
break; /* Done, found it */
if (typ == START_ENCRYPTION_EVENT)
{
if (fdle->start_decryption((Start_encryption_log_event*) ev))
errormsg= "Could not set up decryption for binlog.";
}
delete ev;
if (typ == ROTATE_EVENT || typ == STOP_EVENT ||
typ == FORMAT_DESCRIPTION_EVENT)
typ == FORMAT_DESCRIPTION_EVENT || typ == START_ENCRYPTION_EVENT)
continue; /* Continue looking */
/* We did not find any Gtid_list_log_event, must be old binlog. */
......@@ -1437,7 +1445,7 @@ gtid_state_from_pos(const char *name, uint32 offset,
break;
packet.length(0);
err= Log_event::read_log_event(&cache, &packet,
err= Log_event::read_log_event(&cache, &packet, fdev,
opt_master_verify_checksum ? current_checksum_alg
: BINLOG_CHECKSUM_ALG_OFF);
if (err)
......@@ -1474,6 +1482,20 @@ gtid_state_from_pos(const char *name, uint32 offset,
delete fdev;
fdev= tmp;
}
else if (typ == START_ENCRYPTION_EVENT)
{
uint sele_len = packet.length();
if (current_checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
{
sele_len -= BINLOG_CHECKSUM_LEN;
}
Start_encryption_log_event sele(packet.ptr(), sele_len, fdev);
if (fdev->start_decryption(&sele))
{
errormsg= "Could not start decryption of binlog.";
goto end;
}
}
else if (typ != FORMAT_DESCRIPTION_EVENT && !found_format_description_event)
{
errormsg= "Did not find format description log event while searching "
......@@ -2216,9 +2238,10 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
the binlog
*/
info->last_pos= my_b_tell(log);
error= Log_event::read_log_event(log, packet,
error= Log_event::read_log_event(log, packet, info->fdev,
opt_master_verify_checksum
? info->current_checksum_alg : BINLOG_CHECKSUM_ALG_OFF);
? info->current_checksum_alg
: BINLOG_CHECKSUM_ALG_OFF);
linfo->pos= my_b_tell(log);
if (error)
......@@ -2268,10 +2291,13 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
return 1;
}
uint ev_len= packet->length() - ev_offset;
if (info->current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
ev_len-= BINLOG_CHECKSUM_LEN;
Format_description_log_event *tmp;
if (!(tmp= new Format_description_log_event(packet->ptr()+ev_offset,
packet->length()-ev_offset,
info->fdev)))
if (!(tmp= new Format_description_log_event(packet->ptr() + ev_offset,
ev_len, info->fdev)))
{
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
info->errmsg= "Corrupt Format_description event found "
......@@ -2338,6 +2364,57 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
return 1;
}
/*
Read the following Start_encryption_log_event but don't send it to slave.
Slave doesn't need to know whether master's binlog is encrypted,
and if it'll want to encrypt its logs, it should generate its own
random nonce, not use the one from the master.
*/
packet->length(0);
info->last_pos= linfo->pos;
error= Log_event::read_log_event(log, packet, info->fdev,
opt_master_verify_checksum
? info->current_checksum_alg
: BINLOG_CHECKSUM_ALG_OFF);
linfo->pos= my_b_tell(log);
if (error)
{
set_read_error(info, error);
return 1;
}
event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET]);
if (event_type == START_ENCRYPTION_EVENT)
{
Start_encryption_log_event *sele= (Start_encryption_log_event *)
Log_event::read_log_event(packet->ptr(), packet->length(), &info->errmsg,
info->fdev, BINLOG_CHECKSUM_ALG_OFF);
if (!sele)
{
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
return 1;
}
if (info->fdev->start_decryption(sele))
{
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
info->errmsg= "Could not decrypt binlog: encryption key error";
return 1;
}
delete sele;
}
else if (start_pos == BIN_LOG_HEADER_SIZE)
{
/*
not Start_encryption_log_event - seek back. But only if
send_one_binlog_file() isn't going to seek anyway
*/
my_b_seek(log, info->last_pos);
linfo->pos= info->last_pos;
}
/** all done */
return 0;
}
......@@ -2547,7 +2624,7 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo,
return 1;
info->last_pos= linfo->pos;
error= Log_event::read_log_event(log, packet,
error= Log_event::read_log_event(log, packet, info->fdev,
opt_master_verify_checksum ? info->current_checksum_alg
: BINLOG_CHECKSUM_ALG_OFF);
linfo->pos= my_b_tell(log);
......@@ -2598,8 +2675,9 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo,
});
#endif
if ((info->errmsg= send_event_to_slave(info, event_type, log,
ev_offset, &info->error_gtid)))
if (event_type != START_ENCRYPTION_EVENT &&
((info->errmsg= send_event_to_slave(info, event_type, log,
ev_offset, &info->error_gtid))))
return 1;
if (unlikely(info->send_fake_gtid_list) &&
......@@ -3876,38 +3954,52 @@ bool mysql_show_binlog_events(THD* thd)
Read the first event in case it's a Format_description_log_event, to
know the format. If there's no such event, we are 3.23 or 4.x. This
code, like before, can't read 3.23 binlogs.
Also read the second event, in case it's a Start_encryption_log_event.
This code will fail on a mixed relay log (one which has Format_desc then
Rotate then Format_desc).
*/
ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event,
opt_master_verify_checksum);
if (ev)
my_off_t scan_pos = BIN_LOG_HEADER_SIZE;
while (scan_pos < pos)
{
ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event,
opt_master_verify_checksum);
scan_pos = my_b_tell(&log);
if (ev == NULL || !ev->is_valid())
{
mysql_mutex_unlock(log_lock);
errmsg = "Wrong offset or I/O error";
goto err;
}
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
{
delete description_event;
description_event= (Format_description_log_event*) ev;
}
else
{
if (ev->get_type_code() == START_ENCRYPTION_EVENT)
{
if (description_event->start_decryption((Start_encryption_log_event*) ev))
{
delete ev;
mysql_mutex_unlock(log_lock);
errmsg = "Could not initialize decryption of binlog.";
goto err;
}
}
delete ev;
break;
}
}
my_b_seek(&log, pos);
if (!description_event->is_valid())
{
errmsg="Invalid Format_description event; could be out of memory";
goto err;
}
for (event_count = 0;
(ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0,
description_event,
opt_master_verify_checksum)); )
{
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
description_event->checksum_alg= ev->checksum_alg;
if (event_count >= limit_start &&
ev->net_send(thd, protocol, linfo.log_file_name, pos))
{
......@@ -3917,8 +4009,30 @@ bool mysql_show_binlog_events(THD* thd)
goto err;
}
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
{
Format_description_log_event* new_fdle=
(Format_description_log_event*) ev;
new_fdle->copy_crypto_data(description_event);
delete description_event;
description_event= new_fdle;
}
else
{
if (ev->get_type_code() == START_ENCRYPTION_EVENT)
{
if (description_event->start_decryption((Start_encryption_log_event*) ev))
{
errmsg = "Error starting decryption";
delete ev;
mysql_mutex_unlock(log_lock);
goto err;
}
}
delete ev;
}
pos = my_b_tell(&log);
delete ev;
if (++event_count >= limit_end)
break;
......
......@@ -467,6 +467,10 @@ class String
}
return false;
}
bool append_hex(const uchar *src, uint32 srclen)
{
return append_hex((const char*)src, srclen);
}
bool fill(uint32 max_length,char fill);
void strip_sp();
friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
......
......@@ -1132,7 +1132,6 @@ static Sys_var_mybool Sys_log_bin(
"log_bin", "Whether the binary log is enabled",
READ_ONLY GLOBAL_VAR(opt_bin_log), NO_CMD_LINE, DEFAULT(FALSE));
static Sys_var_mybool Sys_trust_function_creators(
"log_bin_trust_function_creators",
"If set to FALSE (the default), then when --log-bin is used, creation "
......@@ -5215,6 +5214,11 @@ static Sys_var_mybool Sys_encrypt_tmp_files(
READ_ONLY GLOBAL_VAR(encrypt_tmp_files),
CMD_LINE(OPT_ARG), DEFAULT(TRUE));
static Sys_var_mybool Sys_binlog_encryption(
"encrypt_binlog", "Encrypt binary logs (including relay logs)",
READ_ONLY GLOBAL_VAR(encrypt_binlog), CMD_LINE(OPT_ARG),
DEFAULT(TRUE));
static const char *binlog_row_image_names[]= {"MINIMAL", "NOBLOB", "FULL", NullS};
static Sys_var_enum Sys_binlog_row_image(
"binlog_row_image",
......
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