Commit 54672a4f authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-8043 innodb tablespace encryption

"use after free" bug, when a thread replaces space->crypt_data
and frees the old crypt_data object while it's being used
by another thread.
parent e5989d52
...@@ -216,25 +216,31 @@ fil_space_create_crypt_data( ...@@ -216,25 +216,31 @@ fil_space_create_crypt_data(
} }
/****************************************************************** /******************************************************************
Compare two crypt objects */ Merge fil_space_crypt_t object */
UNIV_INTERN UNIV_INTERN
int void
fil_space_crypt_compare( fil_space_merge_crypt_data(
/*====================*/ /*====================*/
const fil_space_crypt_t* crypt_data1,/*!< in: Crypt data */ fil_space_crypt_t* dst,/*!< out: Crypt data */
const fil_space_crypt_t* crypt_data2)/*!< in: Crypt data */ const fil_space_crypt_t* src)/*!< in: Crypt data */
{ {
ut_a(crypt_data1->type == CRYPT_SCHEME_UNENCRYPTED || mutex_enter(&dst->mutex);
crypt_data1->type == CRYPT_SCHEME_1);
ut_a(crypt_data2->type == CRYPT_SCHEME_UNENCRYPTED || /* validate that they are mergeable */
crypt_data2->type == CRYPT_SCHEME_1); ut_a(src->type == CRYPT_SCHEME_UNENCRYPTED ||
src->type == CRYPT_SCHEME_1);
ut_a(dst->type == CRYPT_SCHEME_UNENCRYPTED ||
dst->type == CRYPT_SCHEME_1);
/* no support for changing iv (yet?) */ /* no support for changing iv (yet?) */
ut_a(memcmp(crypt_data1->iv, crypt_data2->iv, ut_a(memcmp(src->iv, dst->iv, sizeof(src->iv)) == 0);
sizeof(crypt_data1->iv)) == 0);
dst->type = src->type;
dst->min_key_version = src->min_key_version;
dst->keyserver_requests += src->keyserver_requests;
return 0; mutex_exit(&dst->mutex);
} }
/****************************************************************** /******************************************************************
......
...@@ -6862,7 +6862,7 @@ fil_space_set_crypt_data( ...@@ -6862,7 +6862,7 @@ fil_space_set_crypt_data(
fil_space_crypt_t* crypt_data) /*!< in: crypt data */ fil_space_crypt_t* crypt_data) /*!< in: crypt data */
{ {
fil_space_t* space; fil_space_t* space;
fil_space_crypt_t* old_crypt_data = NULL; fil_space_crypt_t* free_crypt_data = NULL;
ut_ad(fil_system); ut_ad(fil_system);
...@@ -6872,24 +6872,24 @@ fil_space_set_crypt_data( ...@@ -6872,24 +6872,24 @@ fil_space_set_crypt_data(
if (space != NULL) { if (space != NULL) {
if (space->crypt_data != NULL) { if (space->crypt_data != NULL) {
ut_a(!fil_space_crypt_compare(crypt_data, fil_space_merge_crypt_data(space->crypt_data,
space->crypt_data)); crypt_data);
old_crypt_data = space->crypt_data; free_crypt_data = crypt_data;
} else {
space->crypt_data = crypt_data;
} }
space->crypt_data = crypt_data;
} else { } else {
/* there is a small risk that tablespace has been deleted */ /* there is a small risk that tablespace has been deleted */
old_crypt_data = crypt_data; free_crypt_data = crypt_data;
} }
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
if (old_crypt_data != NULL) { if (free_crypt_data != NULL) {
/* first assign space->crypt_data /* there was already crypt data present and the new crypt
* then destroy old_crypt_data when no new references to * data provided as argument to this function has been merged
* it can be created. * into that => free new crypt data
*/ */
fil_space_destroy_crypt_data(&old_crypt_data); fil_space_destroy_crypt_data(&free_crypt_data);
} }
} }
...@@ -141,13 +141,12 @@ fil_space_set_crypt_data( ...@@ -141,13 +141,12 @@ fil_space_set_crypt_data(
fil_space_crypt_t* crypt_data); /*!< in: crypt data to set */ fil_space_crypt_t* crypt_data); /*!< in: crypt data to set */
/********************************************************************* /*********************************************************************
Compare crypt data*/ Merge crypt data */
UNIV_INTERN void
int fil_space_merge_crypt_data(
fil_space_crypt_compare(
/*======================*/ /*======================*/
const fil_space_crypt_t* crypt_data1, /*!< in: crypt data */ fil_space_crypt_t* dst_crypt_data, /*!< in: crypt_data */
const fil_space_crypt_t* crypt_data2); /*!< in: crypt data */ const fil_space_crypt_t* src_crypt_data); /*!< in: crypt data */
/********************************************************************* /*********************************************************************
Read crypt data from buffer page */ Read crypt data from buffer page */
......
...@@ -216,25 +216,31 @@ fil_space_create_crypt_data( ...@@ -216,25 +216,31 @@ fil_space_create_crypt_data(
} }
/****************************************************************** /******************************************************************
Compare two crypt objects */ Merge fil_space_crypt_t object */
UNIV_INTERN UNIV_INTERN
int void
fil_space_crypt_compare( fil_space_merge_crypt_data(
/*====================*/ /*====================*/
const fil_space_crypt_t* crypt_data1,/*!< in: Crypt data */ fil_space_crypt_t* dst,/*!< out: Crypt data */
const fil_space_crypt_t* crypt_data2)/*!< in: Crypt data */ const fil_space_crypt_t* src)/*!< in: Crypt data */
{ {
ut_a(crypt_data1->type == CRYPT_SCHEME_UNENCRYPTED || mutex_enter(&dst->mutex);
crypt_data1->type == CRYPT_SCHEME_1);
ut_a(crypt_data2->type == CRYPT_SCHEME_UNENCRYPTED || /* validate that they are mergeable */
crypt_data2->type == CRYPT_SCHEME_1); ut_a(src->type == CRYPT_SCHEME_UNENCRYPTED ||
src->type == CRYPT_SCHEME_1);
ut_a(dst->type == CRYPT_SCHEME_UNENCRYPTED ||
dst->type == CRYPT_SCHEME_1);
/* no support for changing iv (yet?) */ /* no support for changing iv (yet?) */
ut_a(memcmp(crypt_data1->iv, crypt_data2->iv, ut_a(memcmp(src->iv, dst->iv, sizeof(src->iv)) == 0);
sizeof(crypt_data1->iv)) == 0);
dst->type = src->type;
dst->min_key_version = src->min_key_version;
dst->keyserver_requests += src->keyserver_requests;
return 0; mutex_exit(&dst->mutex);
} }
/****************************************************************** /******************************************************************
......
...@@ -6989,7 +6989,7 @@ fil_space_set_crypt_data( ...@@ -6989,7 +6989,7 @@ fil_space_set_crypt_data(
fil_space_crypt_t* crypt_data) /*!< in: crypt data */ fil_space_crypt_t* crypt_data) /*!< in: crypt data */
{ {
fil_space_t* space; fil_space_t* space;
fil_space_crypt_t* old_crypt_data = NULL; fil_space_crypt_t* free_crypt_data = NULL;
ut_ad(fil_system); ut_ad(fil_system);
...@@ -6999,24 +6999,24 @@ fil_space_set_crypt_data( ...@@ -6999,24 +6999,24 @@ fil_space_set_crypt_data(
if (space != NULL) { if (space != NULL) {
if (space->crypt_data != NULL) { if (space->crypt_data != NULL) {
ut_a(!fil_space_crypt_compare(crypt_data, fil_space_merge_crypt_data(space->crypt_data,
space->crypt_data)); crypt_data);
old_crypt_data = space->crypt_data; free_crypt_data = crypt_data;
} else {
space->crypt_data = crypt_data;
} }
space->crypt_data = crypt_data;
} else { } else {
/* there is a small risk that tablespace has been deleted */ /* there is a small risk that tablespace has been deleted */
old_crypt_data = crypt_data; free_crypt_data = crypt_data;
} }
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
if (old_crypt_data != NULL) { if (free_crypt_data != NULL) {
/* first assign space->crypt_data /* there was already crypt data present and the new crypt
* then destroy old_crypt_data when no new references to * data provided as argument to this function has been merged
* it can be created. * into that => free new crypt data
*/ */
fil_space_destroy_crypt_data(&old_crypt_data); fil_space_destroy_crypt_data(&free_crypt_data);
} }
} }
...@@ -141,13 +141,12 @@ fil_space_set_crypt_data( ...@@ -141,13 +141,12 @@ fil_space_set_crypt_data(
fil_space_crypt_t* crypt_data); /*!< in: crypt data to set */ fil_space_crypt_t* crypt_data); /*!< in: crypt data to set */
/********************************************************************* /*********************************************************************
Compare crypt data*/ Merge crypt data */
UNIV_INTERN void
int fil_space_merge_crypt_data(
fil_space_crypt_compare(
/*======================*/ /*======================*/
const fil_space_crypt_t* crypt_data1, /*!< in: crypt data */ fil_space_crypt_t* dst_crypt_data, /*!< in: crypt_data */
const fil_space_crypt_t* crypt_data2); /*!< in: crypt data */ const fil_space_crypt_t* src_crypt_data); /*!< in: crypt data */
/********************************************************************* /*********************************************************************
Read crypt data from buffer page */ Read crypt data from buffer page */
......
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