summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-03-07 12:01:20 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2020-03-07 14:31:36 +0200
commit70f0dbe4d30eb7932637fd0d085a2a22744000d1 (patch)
tree36cfaf122b16ab397a22e83a2869a0fd2986d56a
parent522fbfcb5cf655851ce4ee4deaccfe430942f6ce (diff)
downloadmariadb-git-70f0dbe4d30eb7932637fd0d085a2a22744000d1.tar.gz
Cleanup: log upgrade and encryption
log_crypt_101_read_checkpoint(), log_crypt_101_read_block(): Declare as ATTRIBUTE_COLD. These are only used when checking that a MariaDB 10.1 encrypted redo log is clean. log_block_calc_checksum_format_0(): Define in the only compilation unit where it is needed. This is only used when reading the checkpoint information from redo logs before MariaDB 10.2.2. crypt_info_t: Declare the byte arrays directly with alignas(). log_crypt(): Use memcpy_aligned instead of reinterpret_cast on integers.
-rw-r--r--storage/innobase/include/log0crypt.h12
-rw-r--r--storage/innobase/include/log0log.h2
-rw-r--r--storage/innobase/include/log0log.ic31
-rw-r--r--storage/innobase/log/log0crypt.cc128
-rw-r--r--storage/innobase/log/log0recv.cc35
5 files changed, 84 insertions, 124 deletions
diff --git a/storage/innobase/include/log0crypt.h b/storage/innobase/include/log0crypt.h
index 2095649f131..980a79d8f9e 100644
--- a/storage/innobase/include/log0crypt.h
+++ b/storage/innobase/include/log0crypt.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
-Copyright (C) 2014, 2018, MariaDB Corporation.
+Copyright (C) 2014, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -55,22 +55,18 @@ log_crypt_write_checkpoint_buf(
/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
-UNIV_INTERN
-bool
-log_crypt_101_read_checkpoint(const byte* buf);
+ATTRIBUTE_COLD bool log_crypt_101_read_checkpoint(const byte* buf);
/** Decrypt a MariaDB 10.1 redo log block.
@param[in,out] buf log block
@param[in] start_lsn server start LSN
@return whether the decryption was successful */
-bool log_crypt_101_read_block(byte* buf, lsn_t start_lsn);
+ATTRIBUTE_COLD bool log_crypt_101_read_block(byte* buf, lsn_t start_lsn);
/** Read the checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
-UNIV_INTERN
-bool
-log_crypt_read_checkpoint_buf(const byte* buf);
+bool log_crypt_read_checkpoint_buf(const byte* buf);
/** log_crypt() operation code */
enum log_crypt_t {
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index 9b3d0f214b6..07918e478dc 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -624,7 +624,7 @@ public:
@param[in] lsn log sequence number
@return offset within the log */
inline lsn_t calc_lsn_offset(lsn_t lsn) const;
- lsn_t calc_lsn_offset_old(lsn_t lsn) const;
+ inline lsn_t calc_lsn_offset_old(lsn_t lsn) const;
/** Set the field values to correspond to a given lsn. */
void set_fields(lsn_t lsn)
diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic
index 624b6cad95c..46dfb0dd028 100644
--- a/storage/innobase/include/log0log.ic
+++ b/storage/innobase/include/log0log.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -187,35 +187,6 @@ log_block_convert_lsn_to_no(
0xFUL, 0x3FFFFFFFUL)) + 1);
}
-/** Calculate the checksum for a log block using the pre-5.7.9 algorithm.
-@param[in] block log block
-@return checksum */
-UNIV_INLINE
-ulint
-log_block_calc_checksum_format_0(
- const byte* block)
-{
- ulint sum;
- ulint sh;
- ulint i;
-
- sum = 1;
- sh = 0;
-
- for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_CHECKSUM; i++) {
- ulint b = (ulint) block[i];
- sum &= 0x7FFFFFFFUL;
- sum += b;
- sum += b << sh;
- sh++;
- if (sh > 24) {
- sh = 0;
- }
- }
-
- return(sum);
-}
-
/** Calculate the CRC-32C checksum of a log block.
@param[in] block log block
@return checksum */
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index ea621a1bf1a..7cad6571fd7 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
-Copyright (C) 2014, 2019, MariaDB Corporation.
+Copyright (C) 2014, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -37,22 +37,15 @@ my_bool srv_encrypt_log;
/** Redo log encryption key ID */
#define LOG_DEFAULT_ENCRYPTION_KEY 1
-struct aes_block_t {
- byte bytes[MY_AES_BLOCK_SIZE];
-};
-
struct crypt_info_t {
ulint checkpoint_no; /*!< checkpoint no; 32 bits */
uint key_version; /*!< mysqld key version */
/** random string for encrypting the key */
- aes_block_t crypt_msg;
+ alignas(8) byte crypt_msg[MY_AES_BLOCK_SIZE];
/** the secret key */
- aes_block_t crypt_key;
+ alignas(8) byte crypt_key[MY_AES_BLOCK_SIZE];
/** a random string for the per-block initialization vector */
- union {
- uint32_t word;
- byte bytes[4];
- } crypt_nonce;
+ alignas(4) byte crypt_nonce[4];
};
/** The crypt info */
@@ -91,7 +84,7 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
uint keylen = sizeof mysqld_key;
- compile_time_assert(16 == sizeof info->crypt_key.bytes);
+ compile_time_assert(16 == sizeof info->crypt_key);
compile_time_assert(16 == MY_AES_BLOCK_SIZE);
if (uint rc = encryption_key_get(LOG_DEFAULT_ENCRYPTION_KEY,
@@ -114,8 +107,8 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
uint dst_len;
int err= my_aes_crypt(MY_AES_ECB,
ENCRYPTION_FLAG_NOPAD | ENCRYPTION_FLAG_ENCRYPT,
- info->crypt_msg.bytes, MY_AES_BLOCK_SIZE,
- info->crypt_key.bytes, &dst_len,
+ info->crypt_msg, MY_AES_BLOCK_SIZE,
+ info->crypt_key, &dst_len,
mysqld_key, keylen, NULL, 0);
if (err != MY_AES_OK || dst_len != MY_AES_BLOCK_SIZE) {
@@ -139,32 +132,24 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op)
ut_ad(ulint(buf) % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(info.key_version);
- uint32_t aes_ctr_iv[MY_AES_BLOCK_SIZE / sizeof(uint32_t)];
- compile_time_assert(sizeof(uint32_t) == 4);
+ alignas(8) byte aes_ctr_iv[MY_AES_BLOCK_SIZE];
#define LOG_CRYPT_HDR_SIZE 4
lsn &= ~lsn_t(OS_FILE_LOG_BLOCK_SIZE - 1);
for (const byte* const end = buf + size; buf != end;
buf += OS_FILE_LOG_BLOCK_SIZE, lsn += OS_FILE_LOG_BLOCK_SIZE) {
- uint32_t dst[(OS_FILE_LOG_BLOCK_SIZE - LOG_CRYPT_HDR_SIZE
- - LOG_BLOCK_CHECKSUM)
- / sizeof(uint32_t)];
+ alignas(4) byte dst[OS_FILE_LOG_BLOCK_SIZE - LOG_CRYPT_HDR_SIZE
+ - LOG_BLOCK_CHECKSUM];
/* The log block number is not encrypted. */
- *aes_ctr_iv =
-#ifdef WORDS_BIGENDIAN
- ~LOG_BLOCK_FLUSH_BIT_MASK
-#else
- ~(LOG_BLOCK_FLUSH_BIT_MASK >> 24)
-#endif
- & (*dst = *reinterpret_cast<const uint32_t*>(
- buf + LOG_BLOCK_HDR_NO));
-#if LOG_BLOCK_HDR_NO + 4 != LOG_CRYPT_HDR_SIZE
-# error "LOG_BLOCK_HDR_NO has been moved; redo log format affected!"
-#endif
- aes_ctr_iv[1] = info.crypt_nonce.word;
- mach_write_to_8(reinterpret_cast<byte*>(aes_ctr_iv + 2), lsn);
+ memcpy_aligned<4>(dst, buf + LOG_BLOCK_HDR_NO, 4);
+ memcpy_aligned<4>(aes_ctr_iv, buf + LOG_BLOCK_HDR_NO, 4);
+ *aes_ctr_iv &= ~(LOG_BLOCK_FLUSH_BIT_MASK >> 24);
+ static_assert(LOG_BLOCK_HDR_NO + 4 == LOG_CRYPT_HDR_SIZE,
+ "compatibility");
+ memcpy_aligned<4>(aes_ctr_iv + 4, info.crypt_nonce, 4);
+ mach_write_to_8(my_assume_aligned<8>(aes_ctr_iv + 8), lsn);
ut_ad(log_block_get_start_lsn(lsn,
log_block_get_hdr_no(buf))
== lsn);
@@ -212,9 +197,9 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op)
int rc = encryption_crypt(
buf + LOG_CRYPT_HDR_SIZE, dst_size,
reinterpret_cast<byte*>(dst), &dst_len,
- const_cast<byte*>(info.crypt_key.bytes),
+ const_cast<byte*>(info.crypt_key),
MY_AES_BLOCK_SIZE,
- reinterpret_cast<byte*>(aes_ctr_iv), sizeof aes_ctr_iv,
+ aes_ctr_iv, sizeof aes_ctr_iv,
op == LOG_DECRYPT
? ENCRYPTION_FLAG_DECRYPT | ENCRYPTION_FLAG_NOPAD
: ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
@@ -234,37 +219,31 @@ The random parameters will be persisted in the log checkpoint pages.
@see log_crypt_write_checkpoint_buf()
@see log_crypt_read_checkpoint_buf()
@return whether the operation succeeded */
-UNIV_INTERN
-bool
-log_crypt_init()
+bool log_crypt_init()
{
- info.key_version = encryption_key_get_latest_version(
- LOG_DEFAULT_ENCRYPTION_KEY);
-
- if (info.key_version == ENCRYPTION_KEY_VERSION_INVALID) {
- ib::error() << "innodb_encrypt_log: cannot get key version";
- info.key_version = 0;
- return false;
- }
-
- if (my_random_bytes(tmp_iv, MY_AES_BLOCK_SIZE) != MY_AES_OK
- || my_random_bytes(info.crypt_msg.bytes, sizeof info.crypt_msg)
- != MY_AES_OK
- || my_random_bytes(info.crypt_nonce.bytes, sizeof info.crypt_nonce)
- != MY_AES_OK) {
- ib::error() << "innodb_encrypt_log: my_random_bytes() failed";
- return false;
- }
-
- return init_crypt_key(&info);
+ info.key_version=
+ encryption_key_get_latest_version(LOG_DEFAULT_ENCRYPTION_KEY);
+
+ if (info.key_version == ENCRYPTION_KEY_VERSION_INVALID)
+ ib::error() << "log_crypt_init(): cannot get key version";
+ else if (my_random_bytes(tmp_iv, MY_AES_BLOCK_SIZE) != MY_AES_OK ||
+ my_random_bytes(info.crypt_msg, sizeof info.crypt_msg) !=
+ MY_AES_OK ||
+ my_random_bytes(info.crypt_nonce, sizeof info.crypt_nonce) !=
+ MY_AES_OK)
+ ib::error() << "log_crypt_init(): my_random_bytes() failed";
+ else if (init_crypt_key(&info))
+ goto func_exit;
+
+ info.key_version= 0;
+func_exit:
+ return info.key_version != 0;
}
/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
-UNIV_INTERN
-bool
-log_crypt_101_read_checkpoint(const byte* buf)
+ATTRIBUTE_COLD bool log_crypt_101_read_checkpoint(const byte* buf)
{
buf += 20 + 32 * 9;
@@ -286,9 +265,8 @@ log_crypt_101_read_checkpoint(const byte* buf)
infos_used++;
info.checkpoint_no = checkpoint_no;
info.key_version = mach_read_from_4(buf + 4);
- memcpy(info.crypt_msg.bytes, buf + 8, MY_AES_BLOCK_SIZE);
- memcpy(info.crypt_nonce.bytes, buf + 24,
- sizeof info.crypt_nonce);
+ memcpy(info.crypt_msg, buf + 8, MY_AES_BLOCK_SIZE);
+ memcpy(info.crypt_nonce, buf + 24, sizeof info.crypt_nonce);
if (!init_crypt_key(&info, true)) {
return false;
@@ -304,10 +282,8 @@ next_slot:
@param[in,out] buf log block
@param[in] start_lsn server start LSN
@return whether the decryption was successful */
-bool log_crypt_101_read_block(byte* buf, lsn_t start_lsn)
+ATTRIBUTE_COLD bool log_crypt_101_read_block(byte* buf, lsn_t start_lsn)
{
- ut_ad(log_block_calc_checksum_format_0(buf)
- != log_block_get_checksum(buf));
const uint32_t checkpoint_no
= uint32_t(log_block_get_checkpoint_no(buf));
const crypt_info_t* info = infos;
@@ -337,7 +313,7 @@ found:
/* The log block header is not encrypted. */
memcpy(dst, buf, LOG_BLOCK_HDR_SIZE);
- memcpy(aes_ctr_iv, info->crypt_nonce.bytes, 3);
+ memcpy(aes_ctr_iv, info->crypt_nonce, 3);
mach_write_to_8(aes_ctr_iv + 3,
log_block_get_start_lsn(start_lsn, log_block_no));
memcpy(aes_ctr_iv + 11, buf, 4);
@@ -346,7 +322,7 @@ found:
int rc = encryption_crypt(buf + LOG_BLOCK_HDR_SIZE, src_len,
dst + LOG_BLOCK_HDR_SIZE, &dst_len,
- const_cast<byte*>(info->crypt_key.bytes),
+ const_cast<byte*>(info->crypt_key),
MY_AES_BLOCK_SIZE,
aes_ctr_iv, MY_AES_BLOCK_SIZE,
ENCRYPTION_FLAG_DECRYPT
@@ -369,15 +345,15 @@ void
log_crypt_write_checkpoint_buf(byte* buf)
{
ut_ad(info.key_version);
- compile_time_assert(16 == sizeof info.crypt_msg.bytes);
+ compile_time_assert(16 == sizeof info.crypt_msg);
compile_time_assert(16 == MY_AES_BLOCK_SIZE);
compile_time_assert(LOG_CHECKPOINT_CRYPT_MESSAGE
- LOG_CHECKPOINT_CRYPT_NONCE
== sizeof info.crypt_nonce);
- memcpy(buf + LOG_CHECKPOINT_CRYPT_MESSAGE, info.crypt_msg.bytes,
+ memcpy(buf + LOG_CHECKPOINT_CRYPT_MESSAGE, info.crypt_msg,
MY_AES_BLOCK_SIZE);
- memcpy(buf + LOG_CHECKPOINT_CRYPT_NONCE, info.crypt_nonce.bytes,
+ memcpy(buf + LOG_CHECKPOINT_CRYPT_NONCE, info.crypt_nonce,
sizeof info.crypt_nonce);
mach_write_to_4(buf + LOG_CHECKPOINT_CRYPT_KEY, info.key_version);
}
@@ -385,9 +361,7 @@ log_crypt_write_checkpoint_buf(byte* buf)
/** Read the checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
-UNIV_INTERN
-bool
-log_crypt_read_checkpoint_buf(const byte* buf)
+bool log_crypt_read_checkpoint_buf(const byte* buf)
{
info.checkpoint_no = mach_read_from_4(buf + (LOG_CHECKPOINT_NO + 4));
info.key_version = mach_read_from_4(buf + LOG_CHECKPOINT_CRYPT_KEY);
@@ -395,15 +369,15 @@ log_crypt_read_checkpoint_buf(const byte* buf)
#if MY_AES_BLOCK_SIZE != 16
# error "MY_AES_BLOCK_SIZE != 16; redo log checkpoint format affected"
#endif
- compile_time_assert(16 == sizeof info.crypt_msg.bytes);
+ compile_time_assert(16 == sizeof info.crypt_msg);
compile_time_assert(16 == MY_AES_BLOCK_SIZE);
compile_time_assert(LOG_CHECKPOINT_CRYPT_MESSAGE
- LOG_CHECKPOINT_CRYPT_NONCE
== sizeof info.crypt_nonce);
- memcpy(info.crypt_msg.bytes, buf + LOG_CHECKPOINT_CRYPT_MESSAGE,
+ memcpy(info.crypt_msg, buf + LOG_CHECKPOINT_CRYPT_MESSAGE,
MY_AES_BLOCK_SIZE);
- memcpy(info.crypt_nonce.bytes, buf + LOG_CHECKPOINT_CRYPT_NONCE,
+ memcpy(info.crypt_nonce, buf + LOG_CHECKPOINT_CRYPT_NONCE,
sizeof info.crypt_nonce);
return init_crypt_key(&info);
@@ -432,7 +406,7 @@ log_tmp_block_encrypt(
int rc = encryption_crypt(
src, uint(size), dst, &dst_len,
- const_cast<byte*>(info.crypt_key.bytes), MY_AES_BLOCK_SIZE,
+ const_cast<byte*>(info.crypt_key), MY_AES_BLOCK_SIZE,
reinterpret_cast<byte*>(iv), uint(sizeof iv),
encrypt
? ENCRYPTION_FLAG_ENCRYPT|ENCRYPTION_FLAG_NOPAD
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 75094e463e7..6dc6cf62412 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -1320,15 +1320,32 @@ static bool redo_file_sizes_are_correct()
return false;
}
+/** Calculate the checksum for a log block using the pre-10.2.2 algorithm. */
+inline uint32_t log_block_calc_checksum_format_0(const byte *b)
+{
+ uint32_t sum= 1;
+ const byte *const end= &b[512 - 4];
+
+ for (uint32_t sh= 0; b < end; )
+ {
+ sum&= 0x7FFFFFFFUL;
+ sum+= uint32_t{*b} << sh++;
+ sum+= *b++;
+ if (sh > 24)
+ sh= 0;
+ }
+
+ return sum;
+}
+
/** Determine if a redo log from before MariaDB 10.2.2 is clean.
@return error code
@retval DB_SUCCESS if the redo log is clean
@retval DB_CORRUPTION if the redo log is corrupted
@retval DB_ERROR if the redo log is not empty */
-static dberr_t recv_log_recover_pre_10_2()
+ATTRIBUTE_COLD static dberr_t recv_log_recover_pre_10_2()
{
uint64_t max_no= 0;
- uint64_t checkpoint_no;
byte *buf= log_sys.buf;
ut_ad(log_sys.log.format == 0);
@@ -1364,17 +1381,17 @@ static dberr_t recv_log_recover_pre_10_2()
continue;
}
- checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
-
if (!log_crypt_101_read_checkpoint(buf))
{
ib::error() << "Decrypting checkpoint failed";
continue;
}
+ const uint64_t checkpoint_no= mach_read_from_8(buf);
+
DBUG_PRINT("ib_log", ("checkpoint " UINT64PF " at " LSN_PF " found",
checkpoint_no,
- mach_read_from_8(buf + LOG_CHECKPOINT_LSN)));
+ mach_read_from_8(buf + CHECKPOINT_LSN)));
if (checkpoint_no >= max_no)
{
@@ -1435,10 +1452,12 @@ static dberr_t recv_log_recover_pre_10_2()
return DB_ERROR;
}
-/** Same as cals_lsn_offset() except that it supports multiple files */
-lsn_t log_t::file::calc_lsn_offset_old(lsn_t lsn) const
+/** Calculate the offset of a log sequence number
+in an old redo log file (during upgrade check).
+@param[in] lsn log sequence number
+@return byte offset within the log */
+inline lsn_t log_t::file::calc_lsn_offset_old(lsn_t lsn) const
{
- ut_ad(log_sys.mutex.is_owned() || log_write_lock_own());
const lsn_t size= capacity() * recv_sys.files_size();
lsn_t l= lsn - this->lsn;
if (longlong(l) < 0)