summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-03-02 11:51:22 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2021-03-02 11:51:22 +0200
commit01b44c054d608c7a7c3ee751a14782558d06275f (patch)
tree14f0329b91676412118f4ff7df79cef66b2cda3c
parent1f1f61a9de0c85ed5fbe186b3c025a4ace002a8b (diff)
downloadmariadb-git-01b44c054d608c7a7c3ee751a14782558d06275f.tar.gz
MDEV-25026 Various code paths are accessing freed pagesbb-10.5-MDEV-25026
The test case encryption.innodb_encrypt_freed was failing in MemorySanitizer builds. recv_recover_page(): Mark non-recovered pages as freed. fil_crypt_rotate_page(): Before comparing the block->frame contents, check if the block was marked as freed. Other places: Whenever using BUF_GET_POSSIBLY_FREED, check the block->page.status before accessing the page frame. (Both uses of BUF_GET_IF_IN_POOL should be correct now.)
-rw-r--r--storage/innobase/btr/btr0cur.cc8
-rw-r--r--storage/innobase/fil/fil0crypt.cc21
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc4
-rw-r--r--storage/innobase/lock/lock0lock.cc2
-rw-r--r--storage/innobase/log/log0recv.cc1
5 files changed, 26 insertions, 10 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index cacd16841e1..e34677cfcb3 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -807,11 +807,13 @@ btr_cur_optimistic_latch_leaves(
mode, nullptr, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, mtr, &err);
- if (err == DB_DECRYPTION_FAILED) {
+ if (!cursor->left_block) {
cursor->index->table->file_unreadable = true;
}
- if (btr_page_get_next(cursor->left_block->frame)
+ if (cursor->left_block->page.status
+ == buf_page_t::FREED
+ || btr_page_get_next(cursor->left_block->frame)
!= curr_page_no) {
/* release the left block */
btr_leaf_page_release(
@@ -6072,7 +6074,7 @@ btr_estimate_n_rows_in_range_on_level(
ut_ad((block != NULL) == (err == DB_SUCCESS));
- if (err != DB_SUCCESS) {
+ if (!block) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index be0e45f276c..ca66544ffa6 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -996,6 +996,9 @@ fil_crypt_read_crypt_data(fil_space_t* space)
nullptr,
BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr)) {
+ if (block->page.status == buf_page_t::FREED) {
+ goto func_exit;
+ }
mutex_enter(&fil_system.mutex);
if (!space->crypt_data && !space->is_stopping()) {
space->crypt_data = fil_space_read_crypt_data(
@@ -1003,6 +1006,7 @@ fil_crypt_read_crypt_data(fil_space_t* space)
}
mutex_exit(&fil_system.mutex);
}
+func_exit:
mtr.commit();
}
@@ -1055,6 +1059,9 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space)
page_id_t(space->id, 0), space->zip_size(),
RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err)) {
+ if (block->page.status == buf_page_t::FREED) {
+ goto abort;
+ }
crypt_data->type = CRYPT_SCHEME_1;
crypt_data->min_key_version = 0; // all pages are unencrypted
@@ -1853,7 +1860,10 @@ fil_crypt_rotate_page(
const lsn_t block_lsn = mach_read_from_8(FIL_PAGE_LSN + frame);
uint kv = buf_page_get_key_version(frame, space->flags);
- if (space->is_stopping()) {
+ if (block->page.status == buf_page_t::FREED) {
+ /* Do not modify freed pages to avoid an assertion
+ failure on recovery.*/
+ } else if (space->is_stopping()) {
/* The tablespace is closing (in DROP TABLE or
TRUNCATE TABLE or similar): avoid further access */
} else if (!kv && !*reinterpret_cast<uint16_t*>
@@ -1882,9 +1892,6 @@ fil_crypt_rotate_page(
some dummy pages will be allocated, with 0 in
the FIL_PAGE_TYPE. Those pages should be
skipped from key rotation forever. */
- } else if (block->page.status == buf_page_t::FREED) {
- /* Do not modify freed pages to avoid an assertion
- failure on recovery.*/
} else if (fil_crypt_needs_rotation(
crypt_data,
kv,
@@ -2035,8 +2042,10 @@ fil_crypt_flush_space(
page_id_t(space->id, 0), space->zip_size(),
RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr)) {
- mtr.set_named_space(space);
- crypt_data->write_page0(block, &mtr);
+ if (block->page.status != buf_page_t::FREED) {
+ mtr.set_named_space(space);
+ crypt_data->write_page0(block, &mtr);
+ }
}
mtr.commit();
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 34464e38b21..ceaab79b1c4 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -417,6 +417,10 @@ xdes_get_descriptor_const(
__FILE__, __LINE__, mtr)) {
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+ if (block->page.status == buf_page_t::FREED) {
+ return nullptr;
+ }
+
ut_ad(page != 0 || space->free_limit == mach_read_from_4(
FSP_FREE_LIMIT + FSP_HEADER_OFFSET
+ block->frame));
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index cec1eb22d28..56f6d971271 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -4995,7 +4995,7 @@ static void lock_rec_block_validate(const page_id_t page_id)
<< page_id << " err " << err;
}
- if (block) {
+ if (block && block->page.status != buf_page_t::FREED) {
buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
ut_ad(lock_rec_validate_page(block));
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 67f8a2b5277..7c9d8af0859 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -2421,6 +2421,7 @@ set_start_lsn:
any buffered changes. */
init->created = false;
ut_ad(!mtr.has_modifications());
+ block->page.status = buf_page_t::FREED;
}
/* Make sure that committing mtr does not change the modification