diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2018-12-28 19:18:56 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2018-12-28 19:18:56 +0530 |
commit | ce9dda37a5cc3be765208e091f83450b19a0921d (patch) | |
tree | 3dad07e656310d7f32ba6819e8a176f77ac7f09d | |
parent | dc90234bda3e2074179a3e54c09a7c9694e69965 (diff) | |
download | mariadb-git-bb-10.4-mdev-12026.tar.gz |
MDEV-12026 Support encrypted SPATIAL INDEXbb-10.4-mdev-12026
- For encrypted spatial index, store ssn in space id location of
PAGE_BTR_SEG_TOP while encrypting the page.
- While decrypting, insert the space id of PAGE_BTR_SEG_TOP for encrypted
spatial index.
-rw-r--r-- | mysql-test/suite/encryption/r/innodb-spatial-index.result | 20 | ||||
-rw-r--r-- | mysql-test/suite/encryption/t/innodb-spatial-index.test | 19 | ||||
-rw-r--r-- | storage/innobase/fil/fil0crypt.cc | 150 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 2 | ||||
-rw-r--r-- | storage/innobase/include/fil0crypt.h | 5 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 2 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.ic | 3 |
7 files changed, 155 insertions, 46 deletions
diff --git a/mysql-test/suite/encryption/r/innodb-spatial-index.result b/mysql-test/suite/encryption/r/innodb-spatial-index.result index 7cc6d86e48d..cafc20448ed 100644 --- a/mysql-test/suite/encryption/r/innodb-spatial-index.result +++ b/mysql-test/suite/encryption/r/innodb-spatial-index.result @@ -1,22 +1,25 @@ CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256), coordinate POINT NOT NULL, SPATIAL index(coordinate)) ENGINE=INNODB ENCRYPTED=YES; -ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options") +INSERT INTO t1(c, coordinate) values('mysql', ST_GeomFromText('POINT(903994614 180726515)')); +INSERT INTO t1(c, coordinate) values('mariadb', ST_GeomFromText('POINT(903994614 180726515)')); +DROP TABLE t1; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256), coordinate POINT NOT NULL, SPATIAL index(coordinate)) ENGINE=INNODB; ALTER TABLE t1 ENCRYPTED=YES; -ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'ENCRYPTED' DROP TABLE t1; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256), coordinate POINT NOT NULL) ENCRYPTED=YES ENGINE=INNODB; ALTER TABLE t1 ADD SPATIAL INDEX b(coordinate), ALGORITHM=COPY; -ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 140 "Wrong create options") -ALTER TABLE t1 ADD SPATIAL INDEX b(coordinate), FORCE, ALGORITHM=INPLACE; -ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'ENCRYPTED' +ALTER TABLE t1 ADD SPATIAL INDEX b1(coordinate), FORCE, ALGORITHM=INPLACE; +Warnings: +Note 1831 Duplicate index `b1`. This is deprecated and will be disallowed in a future release ALTER TABLE t1 ADD SPATIAL INDEX(coordinate); -ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'ENCRYPTED' -CREATE SPATIAL INDEX b on t1(coordinate); -ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'ENCRYPTED' +Warnings: +Note 1831 Duplicate index `coordinate`. This is deprecated and will be disallowed in a future release +CREATE SPATIAL INDEX b2 on t1(coordinate); +Warnings: +Note 1831 Duplicate index `b2`. This is deprecated and will be disallowed in a future release DROP TABLE t1; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256), coordinate POINT NOT NULL) ENCRYPTED=DEFAULT ENGINE=INNODB; @@ -44,4 +47,5 @@ test/t1 test/t2 SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; NAME +INSERT INTO t1 values(2, 'secret1', ST_GeomFromText('POINT(903994614 180726515)')); DROP TABLE t1, t2; diff --git a/mysql-test/suite/encryption/t/innodb-spatial-index.test b/mysql-test/suite/encryption/t/innodb-spatial-index.test index 28b35379a6b..44d547519c6 100644 --- a/mysql-test/suite/encryption/t/innodb-spatial-index.test +++ b/mysql-test/suite/encryption/t/innodb-spatial-index.test @@ -5,22 +5,20 @@ # MDEV-11974: MariaDB 10.2 encryption does not support spatial indexes # -# -# (1) Do not allow creating table with ENCRYPTED=YES -# -# --replace_regex /#sql-[0-9a-f_]*`/#sql-temporary`/ ---error ER_CANT_CREATE_TABLE CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256), coordinate POINT NOT NULL, SPATIAL index(coordinate)) ENGINE=INNODB ENCRYPTED=YES; +INSERT INTO t1(c, coordinate) values('mysql', ST_GeomFromText('POINT(903994614 180726515)')); +--source include/restart_mysqld.inc +INSERT INTO t1(c, coordinate) values('mariadb', ST_GeomFromText('POINT(903994614 180726515)')); +DROP TABLE t1; # # (2) Alter table # CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256), coordinate POINT NOT NULL, SPATIAL index(coordinate)) ENGINE=INNODB; ---error ER_ILLEGAL_HA_CREATE_OPTION ALTER TABLE t1 ENCRYPTED=YES; DROP TABLE t1; @@ -32,14 +30,10 @@ c VARCHAR(256), coordinate POINT NOT NULL) ENCRYPTED=YES ENGINE=INNODB; # FIXME: MDEV-13851 Encrypted table refuses some form of ALGORITHM=COPY, # but allows rebuild by FORCE --replace_regex /#sql-[0-9a-f_]*`/#sql-temporary`/ ---error ER_CANT_CREATE_TABLE ALTER TABLE t1 ADD SPATIAL INDEX b(coordinate), ALGORITHM=COPY; ---error ER_ILLEGAL_HA_CREATE_OPTION -ALTER TABLE t1 ADD SPATIAL INDEX b(coordinate), FORCE, ALGORITHM=INPLACE; ---error ER_ILLEGAL_HA_CREATE_OPTION +ALTER TABLE t1 ADD SPATIAL INDEX b1(coordinate), FORCE, ALGORITHM=INPLACE; ALTER TABLE t1 ADD SPATIAL INDEX(coordinate); ---error ER_ILLEGAL_HA_CREATE_OPTION -CREATE SPATIAL INDEX b on t1(coordinate); +CREATE SPATIAL INDEX b2 on t1(coordinate); DROP TABLE t1; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, @@ -74,4 +68,5 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ --sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +INSERT INTO t1 values(2, 'secret1', ST_GeomFromText('POINT(903994614 180726515)')); DROP TABLE t1, t2; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index a46d185051d..660b8a249e5 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -564,6 +564,8 @@ fil_encrypt_buf( ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); ibool page_compressed = (orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); uint header_len = FIL_PAGE_DATA; + bool rtree_page = (orig_page_type == FIL_PAGE_RTREE); + node_seq_t ssn_id; if (page_compressed) { header_len += (FIL_PAGE_COMPRESSED_SIZE + FIL_PAGE_COMPRESSION_METHOD_SIZE); @@ -572,6 +574,12 @@ fil_encrypt_buf( /* FIL page header is not encrypted */ memcpy(dst_frame, src_frame, header_len); + if (orig_page_type == FIL_PAGE_RTREE) { + ssn_id = static_cast<node_seq_t>( + mach_read_from_8(src_frame + FIL_RTREE_SPLIT_SEQ_NUM)); + mach_write_to_2(dst_frame + FIL_PAGE_TYPE, FIL_PAGE_ENCRYPTED_RTREE); + } + /* Store key version */ mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, key_version); @@ -586,11 +594,50 @@ fil_encrypt_buf( srclen = mach_read_from_2(src_frame + FIL_PAGE_DATA); } - int rc = encryption_scheme_encrypt(src, srclen, dst, &dstlen, - crypt_data, key_version, - (uint32)space, (uint32)offset, lsn); - ut_a(rc == MY_AES_OK); - ut_a(dstlen == srclen); + if (rtree_page) { + ulint orig_src_len = srclen; + byte ssn_char[4]; + + srclen = PAGE_BTR_SEG_TOP; + int rc = encryption_scheme_encrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + (uint32) space, (uint32) offset, + lsn); + ut_a(rc == MY_AES_OK); + ut_a(dstlen == srclen); + + /** Write the ssn number to PAGE_BTR_SEG_TOP location for + encrypted page. */ + dst += srclen; + + mach_write_to_4(ssn_char, ssn_id); + + rc = encryption_scheme_encrypt((unsigned char*) ssn_char, 4, dst, + &dstlen, crypt_data, key_version, + (uint32) space, (uint32) offset, + lsn); + ut_a(rc == MY_AES_OK); + ut_a(dstlen == 4); + + /** Encrypt the remaining page from PAGE_BTR_SEG_TOP. */ + src += srclen + 4; + dst += 4; + srclen = orig_src_len - (srclen + 4); + + rc = encryption_scheme_encrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + (uint32) space, (uint32) offset, + lsn); + ut_a(rc == MY_AES_OK); + ut_a(dstlen == srclen); + } else { + int rc = encryption_scheme_encrypt( + src, srclen, dst, &dstlen, + crypt_data, key_version, + (uint32)space, (uint32)offset, lsn); + ut_a(rc == MY_AES_OK); + ut_a(dstlen == srclen); + } /* For compressed tables we do not store the FIL header because the whole page is not stored to the disk. In compressed tables only @@ -643,7 +690,6 @@ fil_space_encrypt( switch (mach_read_from_2(src_frame+FIL_PAGE_TYPE)) { case FIL_PAGE_TYPE_FSP_HDR: case FIL_PAGE_TYPE_XDES: - case FIL_PAGE_RTREE: /* File space header, extent descriptor or spatial index are not encrypted. */ return src_frame; @@ -667,6 +713,9 @@ fil_space_encrypt( bool page_compressed_encrypted = (mach_read_from_2(tmp+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); byte uncomp_mem[UNIV_PAGE_SIZE_MAX]; byte tmp_mem[UNIV_PAGE_SIZE_MAX]; + bool rtree_encrypted = (mach_read_from_2(tmp + FIL_PAGE_TYPE) + == FIL_PAGE_ENCRYPTED_RTREE); + node_seq_t ssn_value = 0; if (page_compressed_encrypted) { memcpy(uncomp_mem, src, srv_page_size); @@ -680,7 +729,8 @@ fil_space_encrypt( ut_ad(!buf_page_is_corrupted(true, src, page_size, space)); ut_ad(fil_space_decrypt(crypt_data, tmp_mem, page_size, tmp, - &err)); + &err, rtree_encrypted ? &ssn_value : NULL)); + ut_ad(err == DB_SUCCESS); /* Need to decompress the page if it was also compressed */ @@ -691,8 +741,14 @@ fil_space_encrypt( ut_ad(unzipped2); } - memcpy(tmp_mem + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, - src + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8); + if (rtree_encrypted) { + mach_write_to_4(tmp_mem + FIL_RTREE_SPLIT_SEQ_NUM, 0); + mach_write_to_4(tmp_mem + FIL_RTREE_SPLIT_SEQ_NUM + 4, + ssn_value); + } else { + memcpy(tmp_mem + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, + src + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8); + } ut_ad(!memcmp(src, tmp_mem, page_size.physical())); } #endif /* UNIV_DEBUG */ @@ -706,6 +762,8 @@ fil_space_encrypt( @param[in] page_size Page size @param[in,out] src_frame Page to decrypt @param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED +@param[out] ssn_id split sequence number for spatial index + or NULL for other indexes @return true if page decrypted, false if not.*/ UNIV_INTERN bool @@ -714,7 +772,8 @@ fil_space_decrypt( byte* tmp_frame, const page_size_t& page_size, byte* src_frame, - dberr_t* err) + dberr_t* err, + ib_uint32_t* ssn_id) { ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); @@ -752,22 +811,69 @@ fil_space_decrypt( srclen = mach_read_from_2(src_frame + FIL_PAGE_DATA); } - int rc = encryption_scheme_decrypt(src, srclen, dst, &dstlen, - crypt_data, key_version, - space, offset, lsn); + if (page_type == FIL_PAGE_ENCRYPTED_RTREE) { + int orig_src_len = srclen; + srclen = PAGE_BTR_SEG_TOP; + int rc = encryption_scheme_decrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); + ut_a(rc == MY_AES_OK); + ut_ad(dstlen == srclen); + + src += srclen; + dst += srclen; + rc = encryption_scheme_decrypt(src, 4, dst, &dstlen, + crypt_data, key_version, space, + offset, lsn); + ut_a(rc == MY_AES_OK); + ut_a(dstlen == 4); + + src += 4; + dst += 4; + srclen = orig_src_len - (srclen + 4); + rc = encryption_scheme_decrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); + ut_a(rc == MY_AES_OK); + ut_ad(dstlen == srclen); - if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { + } else { + int rc = encryption_scheme_decrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); - if (rc == -1) { - *err = DB_DECRYPTION_FAILED; - return false; + if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { + + if (rc == -1) { + *err = DB_DECRYPTION_FAILED; + return false; + } + + ib::fatal() << "Unable to decrypt data-block " + << " src: " << src << "srclen: " + << srclen << " buf: " << dst << "buflen: " + << dstlen << " return-code: " << rc + << " Can't continue!"; } - ib::fatal() << "Unable to decrypt data-block " - << " src: " << src << "srclen: " - << srclen << " buf: " << dst << "buflen: " - << dstlen << " return-code: " << rc - << " Can't continue!"; + } + + if (page_type == FIL_PAGE_ENCRYPTED_RTREE) { + ib_uint32_t ssn_value = mach_read_from_4( + tmp_frame + PAGE_HEADER + PAGE_BTR_SEG_TOP); + + if (ssn_id != NULL) { + *ssn_id = ssn_value; + } + + memcpy(tmp_frame + PAGE_HEADER + PAGE_BTR_SEG_TOP, + tmp_frame + PAGE_HEADER + PAGE_BTR_SEG_LEAF, 4); + + mach_write_to_2(tmp_frame + FIL_PAGE_TYPE, FIL_PAGE_RTREE); + + mach_write_to_4(tmp_frame + FIL_RTREE_SPLIT_SEQ_NUM, 0); + + mach_write_to_4(tmp_frame + FIL_RTREE_SPLIT_SEQ_NUM + 4, ssn_value); } /* For compressed tables we do not store the FIL header because diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c4fafe142e5..171cf1f0800 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11501,7 +11501,7 @@ create_table_info_t::check_table_options() encryption */ for(ulint i = 0; i < m_form->s->keys; i++) { const KEY* key = m_form->key_info + i; - if (key->flags & HA_SPATIAL && should_encrypt) { + if (key->flags & HA_SPATIAL && should_encrypt && options->page_compressed) { push_warning_printf(m_thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_UNSUPPORTED, "InnoDB: ENCRYPTED=ON not supported for table because " diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index e520f189d63..f662659494e 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -350,6 +350,8 @@ Decrypt a page. @param[in] page_size Page size @param[in,out] src_frame Page to decrypt @param[out] err DB_SUCCESS or error +@param[out] ssn_id split sequence number for spatial + index pages. @return true if page decrypted, false if not.*/ UNIV_INTERN bool @@ -358,7 +360,8 @@ fil_space_decrypt( byte* tmp_frame, const page_size_t& page_size, byte* src_frame, - dberr_t* err); + dberr_t* err, + ib_uint32_t* ssn_id = NULL); /****************************************************************** Decrypt a page diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 53df19d6ded..e193a98e550 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -491,7 +491,7 @@ struct fil_addr_t { //#define FIL_PAGE_COMPRESSED 14 //#define FIL_PAGE_ENCRYPTED 15 //#define FIL_PAGE_COMPRESSED_AND_ENCRYPTED 16 -//#define FIL_PAGE_ENCRYPTED_RTREE 17 +#define FIL_PAGE_ENCRYPTED_RTREE 17 /** Clustered index root page after instant ADD COLUMN */ #define FIL_PAGE_TYPE_INSTANT 18 diff --git a/storage/innobase/include/fil0fil.ic b/storage/innobase/include/fil0fil.ic index 2a7d06e243f..7444ef36f9c 100644 --- a/storage/innobase/include/fil0fil.ic +++ b/storage/innobase/include/fil0fil.ic @@ -104,7 +104,8 @@ fil_page_type_validate( page_type == FIL_PAGE_TYPE_BLOB || page_type == FIL_PAGE_TYPE_ZBLOB || page_type == FIL_PAGE_TYPE_ZBLOB2 || - page_type == FIL_PAGE_TYPE_UNKNOWN))) { + page_type == FIL_PAGE_TYPE_UNKNOWN || + page_type == FIL_PAGE_ENCRYPTED_RTREE))) { ulint space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); ulint offset = mach_read_from_4(page + FIL_PAGE_OFFSET); |