2015-04-01 11:50:21 +03:00
|
|
|
/*****************************************************************************
|
2015-06-05 08:41:10 +03:00
|
|
|
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
|
MDEV-11638 Encryption causes race conditions in InnoDB shutdown
InnoDB shutdown failed to properly take fil_crypt_thread() into account.
The encryption threads were signalled to shut down together with other
non-critical tasks. This could be much too early in case of slow shutdown,
which could need minutes to complete the purge. Furthermore, InnoDB
failed to wait for the fil_crypt_thread() to actually exit before
proceeding to the final steps of shutdown, causing the race conditions.
Furthermore, the log_scrub_thread() was shut down way too early.
Also it should remain until the SRV_SHUTDOWN_FLUSH_PHASE.
fil_crypt_threads_end(): Remove. This would cause the threads to
be terminated way too early.
srv_buf_dump_thread_active, srv_dict_stats_thread_active,
lock_sys->timeout_thread_active, log_scrub_thread_active,
srv_monitor_active, srv_error_monitor_active: Remove a race condition
between startup and shutdown, by setting these in the startup thread
that creates threads, not in each created thread. In this way, once the
flag is cleared, it will remain cleared during shutdown.
srv_n_fil_crypt_threads_started, fil_crypt_threads_event: Declare in
global rather than static scope.
log_scrub_event, srv_log_scrub_thread_active, log_scrub_thread():
Declare in static rather than global scope. Let these be created by
log_init() and freed by log_shutdown().
rotate_thread_t::should_shutdown(): Do not shut down before the
SRV_SHUTDOWN_FLUSH_PHASE.
srv_any_background_threads_are_active(): Remove. These checks now
exist in logs_empty_and_mark_files_at_shutdown().
logs_empty_and_mark_files_at_shutdown(): Shut down the threads in
the proper order. Keep fil_crypt_thread() and log_scrub_thread() alive
until SRV_SHUTDOWN_FLUSH_PHASE, and check that they actually terminate.
2017-01-04 18:43:32 +02:00
|
|
|
Copyright (c) 2015, 2017, MariaDB Corporation.
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/**************************************************//**
|
|
|
|
@file include/fil0crypt.h
|
|
|
|
The low-level file system encryption support functions
|
|
|
|
|
|
|
|
Created 04/01/2015 Jan Lindström
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#ifndef fil0crypt_h
|
|
|
|
#define fil0crypt_h
|
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
#ifndef UNIV_INNOCHECKSUM
|
|
|
|
|
2017-01-05 10:48:03 +02:00
|
|
|
#include "os0event.h"
|
2017-02-10 12:11:42 +02:00
|
|
|
#include "my_crypt.h"
|
MDEV-11638 Encryption causes race conditions in InnoDB shutdown
InnoDB shutdown failed to properly take fil_crypt_thread() into account.
The encryption threads were signalled to shut down together with other
non-critical tasks. This could be much too early in case of slow shutdown,
which could need minutes to complete the purge. Furthermore, InnoDB
failed to wait for the fil_crypt_thread() to actually exit before
proceeding to the final steps of shutdown, causing the race conditions.
Furthermore, the log_scrub_thread() was shut down way too early.
Also it should remain until the SRV_SHUTDOWN_FLUSH_PHASE.
fil_crypt_threads_end(): Remove. This would cause the threads to
be terminated way too early.
srv_buf_dump_thread_active, srv_dict_stats_thread_active,
lock_sys->timeout_thread_active, log_scrub_thread_active,
srv_monitor_active, srv_error_monitor_active: Remove a race condition
between startup and shutdown, by setting these in the startup thread
that creates threads, not in each created thread. In this way, once the
flag is cleared, it will remain cleared during shutdown.
srv_n_fil_crypt_threads_started, fil_crypt_threads_event: Declare in
global rather than static scope.
log_scrub_event, srv_log_scrub_thread_active, log_scrub_thread():
Declare in static rather than global scope. Let these be created by
log_init() and freed by log_shutdown().
rotate_thread_t::should_shutdown(): Do not shut down before the
SRV_SHUTDOWN_FLUSH_PHASE.
srv_any_background_threads_are_active(): Remove. These checks now
exist in logs_empty_and_mark_files_at_shutdown().
logs_empty_and_mark_files_at_shutdown(): Shut down the threads in
the proper order. Keep fil_crypt_thread() and log_scrub_thread() alive
until SRV_SHUTDOWN_FLUSH_PHASE, and check that they actually terminate.
2017-01-04 18:43:32 +02:00
|
|
|
|
2015-09-19 11:30:18 +03:00
|
|
|
/**
|
|
|
|
* Magic pattern in start of crypt data on page 0
|
|
|
|
*/
|
|
|
|
#define MAGIC_SZ 6
|
|
|
|
|
|
|
|
static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = {
|
|
|
|
's', 0xE, 0xC, 'R', 'E', 't' };
|
|
|
|
|
2015-04-01 11:50:21 +03:00
|
|
|
/* This key will be used if nothing else is given */
|
2015-05-27 12:08:13 +02:00
|
|
|
#define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA
|
2015-04-01 11:50:21 +03:00
|
|
|
|
MDEV-11638 Encryption causes race conditions in InnoDB shutdown
InnoDB shutdown failed to properly take fil_crypt_thread() into account.
The encryption threads were signalled to shut down together with other
non-critical tasks. This could be much too early in case of slow shutdown,
which could need minutes to complete the purge. Furthermore, InnoDB
failed to wait for the fil_crypt_thread() to actually exit before
proceeding to the final steps of shutdown, causing the race conditions.
Furthermore, the log_scrub_thread() was shut down way too early.
Also it should remain until the SRV_SHUTDOWN_FLUSH_PHASE.
fil_crypt_threads_end(): Remove. This would cause the threads to
be terminated way too early.
srv_buf_dump_thread_active, srv_dict_stats_thread_active,
lock_sys->timeout_thread_active, log_scrub_thread_active,
srv_monitor_active, srv_error_monitor_active: Remove a race condition
between startup and shutdown, by setting these in the startup thread
that creates threads, not in each created thread. In this way, once the
flag is cleared, it will remain cleared during shutdown.
srv_n_fil_crypt_threads_started, fil_crypt_threads_event: Declare in
global rather than static scope.
log_scrub_event, srv_log_scrub_thread_active, log_scrub_thread():
Declare in static rather than global scope. Let these be created by
log_init() and freed by log_shutdown().
rotate_thread_t::should_shutdown(): Do not shut down before the
SRV_SHUTDOWN_FLUSH_PHASE.
srv_any_background_threads_are_active(): Remove. These checks now
exist in logs_empty_and_mark_files_at_shutdown().
logs_empty_and_mark_files_at_shutdown(): Shut down the threads in
the proper order. Keep fil_crypt_thread() and log_scrub_thread() alive
until SRV_SHUTDOWN_FLUSH_PHASE, and check that they actually terminate.
2017-01-04 18:43:32 +02:00
|
|
|
extern os_event_t fil_crypt_threads_event;
|
|
|
|
|
2015-04-01 11:50:21 +03:00
|
|
|
/**
|
|
|
|
* CRYPT_SCHEME_UNENCRYPTED
|
|
|
|
*
|
|
|
|
* Used as intermediate state when convering a space from unencrypted
|
|
|
|
* to encrypted
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* CRYPT_SCHEME_1
|
|
|
|
*
|
2015-04-09 19:27:40 +02:00
|
|
|
* xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths)
|
2015-04-01 11:50:21 +03:00
|
|
|
* L = AES_ECB(KEY, IV)
|
2015-04-09 19:27:40 +02:00
|
|
|
* CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE)
|
2015-04-01 11:50:21 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define CRYPT_SCHEME_1 1
|
|
|
|
#define CRYPT_SCHEME_1_IV_LEN 16
|
|
|
|
#define CRYPT_SCHEME_UNENCRYPTED 0
|
|
|
|
|
|
|
|
/* Cached L or key for given key_version */
|
|
|
|
struct key_struct
|
|
|
|
{
|
2015-04-09 00:37:47 +02:00
|
|
|
uint key_version; /*!< Version of the key */
|
2015-04-01 11:50:21 +03:00
|
|
|
uint key_length; /*!< Key length */
|
2015-04-09 19:27:40 +02:00
|
|
|
unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key
|
|
|
|
(that is L in CRYPT_SCHEME_1) */
|
2015-04-01 11:50:21 +03:00
|
|
|
};
|
|
|
|
|
2016-12-13 11:51:33 +02:00
|
|
|
/** is encryption enabled */
|
|
|
|
extern ulong srv_encrypt_tables;
|
|
|
|
|
|
|
|
/** Mutex helper for crypt_data->scheme
|
|
|
|
@param[in, out] schme encryption scheme
|
|
|
|
@param[in] exit should we exit or enter mutex ? */
|
|
|
|
void
|
|
|
|
crypt_data_scheme_locker(
|
|
|
|
st_encryption_scheme* scheme,
|
|
|
|
int exit);
|
|
|
|
|
2015-04-01 11:50:21 +03:00
|
|
|
struct fil_space_rotate_state_t
|
|
|
|
{
|
2015-08-14 11:09:06 +03:00
|
|
|
time_t start_time; /*!< time when rotation started */
|
|
|
|
ulint active_threads; /*!< active threads in space */
|
|
|
|
ulint next_offset; /*!< next "free" offset */
|
|
|
|
ulint max_offset; /*!< max offset needing to be rotated */
|
|
|
|
uint min_key_version_found; /*!< min key version found but not
|
|
|
|
rotated */
|
|
|
|
lsn_t end_lsn; /*!< max lsn created when rotating this
|
|
|
|
space */
|
|
|
|
bool starting; /*!< initial write of IV */
|
|
|
|
bool flushing; /*!< space is being flushed at end of rotate */
|
2015-04-01 11:50:21 +03:00
|
|
|
struct {
|
2015-08-14 11:09:06 +03:00
|
|
|
bool is_active; /*!< is scrubbing active in this space */
|
|
|
|
time_t last_scrub_completed; /*!< when was last scrub
|
|
|
|
completed */
|
2015-04-01 11:50:21 +03:00
|
|
|
} scrubbing;
|
|
|
|
};
|
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
struct fil_space_crypt_t : st_encryption_scheme
|
2015-04-01 11:50:21 +03:00
|
|
|
{
|
2016-12-13 11:51:33 +02:00
|
|
|
public:
|
|
|
|
/** Constructor. Does not initialize the members!
|
|
|
|
The object is expected to be placed in a buffer that
|
|
|
|
has been zero-initialized. */
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_crypt_t(
|
2017-03-01 08:27:39 +02:00
|
|
|
uint new_type,
|
2016-12-13 11:51:33 +02:00
|
|
|
uint new_min_key_version,
|
|
|
|
uint new_key_id,
|
|
|
|
fil_encryption_t new_encryption)
|
|
|
|
: st_encryption_scheme(),
|
|
|
|
min_key_version(new_min_key_version),
|
2017-03-14 12:56:01 +02:00
|
|
|
page0_offset(0),
|
2016-12-13 11:51:33 +02:00
|
|
|
encryption(new_encryption),
|
|
|
|
key_found(),
|
|
|
|
rotate_state()
|
|
|
|
{
|
|
|
|
key_found = new_min_key_version;
|
|
|
|
key_id = new_key_id;
|
|
|
|
my_random_bytes(iv, sizeof(iv));
|
2016-12-29 13:23:18 +01:00
|
|
|
mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex);
|
2016-12-13 11:51:33 +02:00
|
|
|
locker = crypt_data_scheme_locker;
|
|
|
|
type = new_type;
|
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
if (new_encryption == FIL_ENCRYPTION_OFF ||
|
2016-12-13 11:51:33 +02:00
|
|
|
(!srv_encrypt_tables &&
|
2017-03-14 12:56:01 +02:00
|
|
|
new_encryption == FIL_ENCRYPTION_DEFAULT)) {
|
2016-12-13 11:51:33 +02:00
|
|
|
type = CRYPT_SCHEME_UNENCRYPTED;
|
|
|
|
} else {
|
|
|
|
type = CRYPT_SCHEME_1;
|
|
|
|
min_key_version = key_get_latest_version();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Destructor */
|
2017-03-14 12:56:01 +02:00
|
|
|
~fil_space_crypt_t()
|
2016-12-13 11:51:33 +02:00
|
|
|
{
|
|
|
|
mutex_free(&mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Get latest key version from encryption plugin
|
|
|
|
@retval key_version or
|
|
|
|
@retval ENCRYPTION_KEY_VERSION_INVALID if used key_id
|
|
|
|
is not found from encryption plugin. */
|
|
|
|
uint key_get_latest_version(void);
|
|
|
|
|
|
|
|
/** Returns true if key was found from encryption plugin
|
|
|
|
and false if not. */
|
|
|
|
bool is_key_found() const {
|
|
|
|
return key_found != ENCRYPTION_KEY_VERSION_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns true if tablespace should be encrypted */
|
|
|
|
bool should_encrypt() const {
|
2017-03-14 12:56:01 +02:00
|
|
|
return ((encryption == FIL_ENCRYPTION_ON) ||
|
2016-12-13 11:51:33 +02:00
|
|
|
(srv_encrypt_tables &&
|
2017-03-14 12:56:01 +02:00
|
|
|
encryption == FIL_ENCRYPTION_DEFAULT));
|
2016-12-13 11:51:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return true if tablespace is encrypted. */
|
|
|
|
bool is_encrypted() const {
|
2017-03-14 12:56:01 +02:00
|
|
|
return (encryption != FIL_ENCRYPTION_OFF);
|
2016-12-13 11:51:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return true if default tablespace encryption is used, */
|
|
|
|
bool is_default_encryption() const {
|
2017-03-14 12:56:01 +02:00
|
|
|
return (encryption == FIL_ENCRYPTION_DEFAULT);
|
2016-12-13 11:51:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return true if tablespace is not encrypted. */
|
|
|
|
bool not_encrypted() const {
|
2017-03-14 12:56:01 +02:00
|
|
|
return (encryption == FIL_ENCRYPTION_OFF);
|
2016-12-13 11:51:33 +02:00
|
|
|
}
|
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
/** Write crypt data to a page (0)
|
2017-03-30 12:48:42 +02:00
|
|
|
@param[in] space tablespace
|
|
|
|
@param[in,out] page0 first page of the tablespace
|
|
|
|
@param[in,out] mtr mini-transaction */
|
|
|
|
void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr);
|
2016-12-13 11:51:33 +02:00
|
|
|
|
2015-04-01 11:50:21 +03:00
|
|
|
uint min_key_version; // min key version for this space
|
|
|
|
ulint page0_offset; // byte offset on page 0 for crypt data
|
2015-04-01 19:37:00 +03:00
|
|
|
fil_encryption_t encryption; // Encryption setup
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
ib_mutex_t mutex; // mutex protecting following variables
|
2016-12-13 11:51:33 +02:00
|
|
|
|
|
|
|
/** Return code from encryption_key_get_latest_version.
|
|
|
|
If ENCRYPTION_KEY_VERSION_INVALID encryption plugin
|
|
|
|
could not find the key and there is no need to call
|
|
|
|
get_latest_key_version again as keys are read only
|
|
|
|
at startup. */
|
|
|
|
uint key_found;
|
|
|
|
|
2015-04-01 11:50:21 +03:00
|
|
|
fil_space_rotate_state_t rotate_state;
|
|
|
|
};
|
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
/** Status info about encryption */
|
|
|
|
struct fil_space_crypt_status_t {
|
|
|
|
ulint space; /*!< tablespace id */
|
|
|
|
ulint scheme; /*!< encryption scheme */
|
|
|
|
uint min_key_version; /*!< min key version */
|
|
|
|
uint current_key_version;/*!< current key version */
|
|
|
|
uint keyserver_requests;/*!< no of key requests to key server */
|
|
|
|
ulint key_id; /*!< current key_id */
|
|
|
|
bool rotating; /*!< is key rotation ongoing */
|
|
|
|
bool flushing; /*!< is flush at end of rotation ongoing */
|
|
|
|
ulint rotate_next_page_number; /*!< next page if key rotating */
|
|
|
|
ulint rotate_max_page_number; /*!< max page if key rotating */
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Statistics about encryption key rotation */
|
|
|
|
struct fil_crypt_stat_t {
|
|
|
|
ulint pages_read_from_cache;
|
|
|
|
ulint pages_read_from_disk;
|
|
|
|
ulint pages_modified;
|
|
|
|
ulint pages_flushed;
|
|
|
|
ulint estimated_iops;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Status info about scrubbing */
|
|
|
|
struct fil_space_scrub_status_t {
|
|
|
|
ulint space; /*!< tablespace id */
|
|
|
|
bool compressed; /*!< is space compressed */
|
|
|
|
time_t last_scrub_completed; /*!< when was last scrub completed */
|
|
|
|
bool scrubbing; /*!< is scrubbing ongoing */
|
|
|
|
time_t current_scrub_started; /*!< when started current scrubbing */
|
|
|
|
ulint current_scrub_active_threads; /*!< current scrub active threads */
|
|
|
|
ulint current_scrub_page_number; /*!< current scrub page no */
|
|
|
|
ulint current_scrub_max_page_number; /*!< current scrub max page no */
|
|
|
|
};
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Init space crypt */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
fil_space_crypt_init();
|
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Cleanup space crypt */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
fil_space_crypt_cleanup();
|
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/**
|
2017-03-14 12:56:01 +02:00
|
|
|
Create a fil_space_crypt_t object
|
|
|
|
@param[in] encrypt_mode FIL_ENCRYPTION_DEFAULT or
|
|
|
|
FIL_ENCRYPTION_ON or
|
|
|
|
FIL_ENCRYPTION_OFF
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in] key_id Encryption key id
|
|
|
|
@return crypt object */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
2015-05-20 13:35:51 +03:00
|
|
|
fil_space_crypt_t*
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_create_crypt_data(
|
|
|
|
fil_encryption_t encrypt_mode,
|
|
|
|
uint key_id)
|
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
/******************************************************************
|
|
|
|
Merge fil_space_crypt_t object
|
|
|
|
@param[in,out] dst Destination cryp data
|
|
|
|
@param[in] src Source crypt data */
|
2015-05-17 14:14:16 +03:00
|
|
|
UNIV_INTERN
|
2015-05-15 09:54:41 +02:00
|
|
|
void
|
|
|
|
fil_space_merge_crypt_data(
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_crypt_t* dst,
|
|
|
|
const fil_space_crypt_t* src);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/** Initialize encryption parameters from a tablespace header page.
|
|
|
|
@param[in] page_size page size of the tablespace
|
|
|
|
@param[in] page first page of the tablespace
|
|
|
|
@return crypt data from page 0
|
|
|
|
@retval NULL if not present or not valid */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_crypt_t*
|
2017-03-30 12:48:42 +02:00
|
|
|
fil_space_read_crypt_data(const page_size_t& page_size, const byte* page)
|
|
|
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/**
|
2017-03-14 12:56:01 +02:00
|
|
|
Free a crypt data object
|
|
|
|
@param[in,out] crypt_data crypt data to be freed */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_destroy_crypt_data(
|
|
|
|
fil_space_crypt_t **crypt_data);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
/******************************************************************
|
|
|
|
Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
|
|
|
|
@param[in] ptr Log entry start
|
|
|
|
@param[in] end_ptr Log entry end
|
|
|
|
@param[in] block buffer block
|
|
|
|
@return position on log buffer */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
2017-03-14 12:56:01 +02:00
|
|
|
const byte*
|
|
|
|
fil_parse_write_crypt_data(
|
|
|
|
const byte* ptr,
|
|
|
|
const byte* end_ptr,
|
|
|
|
const buf_block_t* block)
|
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/** Encrypt a buffer.
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in,out] crypt_data Crypt data
|
|
|
|
@param[in] space space_id
|
|
|
|
@param[in] offset Page offset
|
|
|
|
@param[in] lsn Log sequence number
|
|
|
|
@param[in] src_frame Page to encrypt
|
2017-03-30 12:48:42 +02:00
|
|
|
@param[in] page_size Page size
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in,out] dst_frame Output buffer
|
|
|
|
@return encrypted buffer or NULL */
|
2015-04-01 11:50:21 +03:00
|
|
|
byte*
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_encrypt_buf(
|
2017-03-30 12:48:42 +02:00
|
|
|
fil_space_crypt_t* crypt_data,
|
|
|
|
ulint space,
|
|
|
|
ulint offset,
|
|
|
|
lsn_t lsn,
|
|
|
|
const byte* src_frame,
|
|
|
|
const page_size_t& page_size,
|
|
|
|
byte* dst_frame)
|
2017-03-14 12:56:01 +02:00
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/**
|
|
|
|
Encrypt a page.
|
2017-03-14 12:56:01 +02:00
|
|
|
|
|
|
|
@param[in] space Tablespace
|
|
|
|
@param[in] offset Page offset
|
|
|
|
@param[in] lsn Log sequence number
|
|
|
|
@param[in] src_frame Page to encrypt
|
|
|
|
@param[in,out] dst_frame Output buffer
|
|
|
|
@return encrypted buffer or NULL */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
byte*
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_encrypt(
|
|
|
|
const fil_space_t* space,
|
|
|
|
ulint offset,
|
|
|
|
lsn_t lsn,
|
|
|
|
byte* src_frame,
|
|
|
|
byte* dst_frame)
|
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/**
|
|
|
|
Decrypt a page.
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in,out] crypt_data crypt_data
|
|
|
|
@param[in] tmp_frame Temporary buffer
|
|
|
|
@param[in] page_size Page size
|
|
|
|
@param[in,out] src_frame Page to decrypt
|
|
|
|
@param[out] err DB_SUCCESS or error
|
MDEV-11759: Encryption code in MariaDB 10.1/10.2 causes
compatibility problems
Pages that are encrypted contain post encryption checksum on
different location that normal checksum fields. Therefore,
we should before decryption check this checksum to avoid
unencrypting corrupted pages. After decryption we can use
traditional checksum check to detect if page is corrupted
or unencryption was done using incorrect key.
Pages that are page compressed do not contain any checksum,
here we need to fist unencrypt, decompress and finally
use tradional checksum check to detect page corruption
or that we used incorrect key in unencryption.
buf0buf.cc: buf_page_is_corrupted() mofified so that
compressed pages are skipped.
buf0buf.h, buf_block_init(), buf_page_init_low():
removed unnecessary page_encrypted, page_compressed,
stored_checksum, valculated_checksum fields from
buf_page_t
buf_page_get_gen(): use new buf_page_check_corrupt() function
to detect corrupted pages.
buf_page_check_corrupt(): If page was not yet decrypted
check if post encryption checksum still matches.
If page is not anymore encrypted, use buf_page_is_corrupted()
traditional checksum method.
If page is detected as corrupted and it is not encrypted
we print corruption message to error log.
If page is still encrypted or it was encrypted and now
corrupted, we will print message that page is
encrypted to error log.
buf_page_io_complete(): use new buf_page_check_corrupt()
function to detect corrupted pages.
buf_page_decrypt_after_read(): Verify post encryption
checksum before tring to decrypt.
fil0crypt.cc: fil_encrypt_buf() verify post encryption
checksum and ind fil_space_decrypt() return true
if we really decrypted the page.
fil_space_verify_crypt_checksum(): rewrite to use
the method used when calculating post encryption
checksum. We also check if post encryption checksum
matches that traditional checksum check does not
match.
fil0fil.ic: Add missed page type encrypted and page
compressed to fil_get_page_type_name()
Note that this change does not yet fix innochecksum tool,
that will be done in separate MDEV.
Fix test failures caused by buf page corruption injection.
2017-02-06 10:47:55 +02:00
|
|
|
@return true if page decrypted, false if not.*/
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
bool
|
2015-06-05 08:41:10 +03:00
|
|
|
fil_space_decrypt(
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_crypt_t* crypt_data,
|
|
|
|
byte* tmp_frame,
|
2017-03-30 12:48:42 +02:00
|
|
|
const page_size_t& page_size,
|
2017-03-14 12:56:01 +02:00
|
|
|
byte* src_frame,
|
|
|
|
dberr_t* err);
|
2016-02-17 12:32:07 +02:00
|
|
|
|
2015-06-05 08:41:10 +03:00
|
|
|
/******************************************************************
|
|
|
|
Decrypt a page
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in] space Tablespace
|
MDEV-11759: Encryption code in MariaDB 10.1/10.2 causes
compatibility problems
Pages that are encrypted contain post encryption checksum on
different location that normal checksum fields. Therefore,
we should before decryption check this checksum to avoid
unencrypting corrupted pages. After decryption we can use
traditional checksum check to detect if page is corrupted
or unencryption was done using incorrect key.
Pages that are page compressed do not contain any checksum,
here we need to fist unencrypt, decompress and finally
use tradional checksum check to detect page corruption
or that we used incorrect key in unencryption.
buf0buf.cc: buf_page_is_corrupted() mofified so that
compressed pages are skipped.
buf0buf.h, buf_block_init(), buf_page_init_low():
removed unnecessary page_encrypted, page_compressed,
stored_checksum, valculated_checksum fields from
buf_page_t
buf_page_get_gen(): use new buf_page_check_corrupt() function
to detect corrupted pages.
buf_page_check_corrupt(): If page was not yet decrypted
check if post encryption checksum still matches.
If page is not anymore encrypted, use buf_page_is_corrupted()
traditional checksum method.
If page is detected as corrupted and it is not encrypted
we print corruption message to error log.
If page is still encrypted or it was encrypted and now
corrupted, we will print message that page is
encrypted to error log.
buf_page_io_complete(): use new buf_page_check_corrupt()
function to detect corrupted pages.
buf_page_decrypt_after_read(): Verify post encryption
checksum before tring to decrypt.
fil0crypt.cc: fil_encrypt_buf() verify post encryption
checksum and ind fil_space_decrypt() return true
if we really decrypted the page.
fil_space_verify_crypt_checksum(): rewrite to use
the method used when calculating post encryption
checksum. We also check if post encryption checksum
matches that traditional checksum check does not
match.
fil0fil.ic: Add missed page type encrypted and page
compressed to fil_get_page_type_name()
Note that this change does not yet fix innochecksum tool,
that will be done in separate MDEV.
Fix test failures caused by buf page corruption injection.
2017-02-06 10:47:55 +02:00
|
|
|
@param[in] tmp_frame Temporary buffer used for decrypting
|
|
|
|
@param[in,out] src_frame Page to decrypt
|
|
|
|
@param[out] decrypted true if page was decrypted
|
|
|
|
@return decrypted page, or original not encrypted page if decryption is
|
2015-06-05 08:41:10 +03:00
|
|
|
not needed.*/
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
2015-06-05 08:41:10 +03:00
|
|
|
byte*
|
2015-04-01 11:50:21 +03:00
|
|
|
fil_space_decrypt(
|
2017-03-14 12:56:01 +02:00
|
|
|
const fil_space_t* space,
|
|
|
|
byte* tmp_frame,
|
|
|
|
byte* src_frame,
|
|
|
|
bool* decrypted)
|
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
/******************************************************************
|
|
|
|
Calculate post encryption checksum
|
2017-03-30 12:48:42 +02:00
|
|
|
@param[in] page_size page size
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in] dst_frame Block where checksum is calculated
|
|
|
|
@return page checksum or BUF_NO_CHECKSUM_MAGIC
|
|
|
|
not needed. */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
2017-03-14 12:56:01 +02:00
|
|
|
ulint
|
|
|
|
fil_crypt_calculate_checksum(
|
2017-03-30 12:48:42 +02:00
|
|
|
const page_size_t& page_size,
|
|
|
|
const byte* dst_frame)
|
2017-03-14 12:56:01 +02:00
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Adjust thread count for key rotation
|
|
|
|
@param[in] enw_cnt Number of threads to be used */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_set_thread_cnt(
|
|
|
|
uint new_cnt);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Adjust max key age
|
|
|
|
@param[in] val New max key age */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_set_rotate_key_age(
|
|
|
|
uint val);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Adjust rotation iops
|
|
|
|
@param[in] val New max roation iops */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_set_rotation_iops(
|
|
|
|
uint val);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Adjust encrypt tables
|
|
|
|
@param[in] val New setting for innodb-encrypt-tables */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_set_encrypt_tables(
|
|
|
|
uint val);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Init threads for key rotation */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_threads_init();
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Clean up key rotation threads resources */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_threads_cleanup();
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Wait for crypt threads to stop accessing space
|
|
|
|
@param[in] space Tablespace */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
fil_space_crypt_close_tablespace(
|
2017-03-14 12:56:01 +02:00
|
|
|
const fil_space_t* space);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Get crypt status for a space (used by information_schema)
|
|
|
|
@param[in] space Tablespace
|
|
|
|
@param[out] status Crypt status
|
|
|
|
return 0 if crypt data present */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
2017-03-14 12:56:01 +02:00
|
|
|
void
|
2015-04-01 11:50:21 +03:00
|
|
|
fil_space_crypt_get_status(
|
2017-03-14 12:56:01 +02:00
|
|
|
const fil_space_t* space,
|
|
|
|
struct fil_space_crypt_status_t* status);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
/*********************************************************************
|
2017-03-14 12:56:01 +02:00
|
|
|
Return crypt statistics
|
|
|
|
@param[out] stat Crypt statistics */
|
2015-04-01 11:50:21 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
fil_crypt_total_stat(
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_crypt_stat_t *stat);
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/**
|
2017-03-14 12:56:01 +02:00
|
|
|
Get scrub status for a space (used by information_schema)
|
2015-04-01 11:50:21 +03:00
|
|
|
|
2017-03-14 12:56:01 +02:00
|
|
|
@param[in] space Tablespace
|
|
|
|
@param[out] status Scrub status
|
|
|
|
return 0 if data found */
|
2015-05-17 14:14:16 +03:00
|
|
|
UNIV_INTERN
|
|
|
|
void
|
2017-03-14 12:56:01 +02:00
|
|
|
fil_space_get_scrub_status(
|
2017-03-30 12:48:42 +02:00
|
|
|
const fil_space_t* space,
|
|
|
|
fil_space_scrub_status_t* status);
|
2015-05-17 14:14:16 +03:00
|
|
|
|
2015-04-01 11:50:21 +03:00
|
|
|
#include "fil0crypt.ic"
|
2017-03-30 12:48:42 +02:00
|
|
|
#endif /* !UNIV_INNOCHECKSUM */
|
2015-05-17 14:14:16 +03:00
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
/**
|
|
|
|
Verify that post encryption checksum match calculated checksum.
|
|
|
|
This function should be called only if tablespace contains crypt_data
|
|
|
|
metadata (this is strong indication that tablespace is encrypted).
|
|
|
|
Function also verifies that traditional checksum does not match
|
|
|
|
calculated checksum as if it does page could be valid unencrypted,
|
|
|
|
encrypted, or corrupted.
|
|
|
|
|
|
|
|
@param[in,out] page page frame (checksum is temporarily modified)
|
|
|
|
@param[in] page_size page size
|
|
|
|
@param[in] space tablespace identifier
|
|
|
|
@param[in] offset page number
|
|
|
|
@return true if page is encrypted AND OK, false otherwise */
|
2015-08-31 19:47:14 +03:00
|
|
|
UNIV_INTERN
|
2017-03-30 12:48:42 +02:00
|
|
|
bool
|
|
|
|
fil_space_verify_crypt_checksum(
|
|
|
|
byte* page,
|
|
|
|
const page_size_t& page_size,
|
|
|
|
#ifdef UNIV_INNOCHECKSUM
|
|
|
|
bool strict_check, /*!< --strict-check */
|
|
|
|
FILE* log_file, /*!< --log */
|
|
|
|
#endif /* UNIV_INNOCHECKSUM */
|
|
|
|
ulint space,
|
|
|
|
ulint offset)
|
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2015-04-01 11:50:21 +03:00
|
|
|
|
|
|
|
#endif /* fil0crypt_h */
|