From b18671840cf54f252bdf4d1de39840f690fd7d0a Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Thu, 15 Aug 2019 13:16:47 +0900 Subject: [PATCH 4/5] Introduce buffer encryption for cluster encyrption. --- contrib/bloom/blinsert.c | 1 + src/backend/access/hash/hashpage.c | 1 + src/backend/access/heap/rewriteheap.c | 4 ++ src/backend/access/nbtree/nbtree.c | 1 + src/backend/access/nbtree/nbtsort.c | 1 + src/backend/access/spgist/spginsert.c | 3 ++ src/backend/catalog/storage.c | 2 +- src/backend/storage/buffer/bufmgr.c | 10 +++- src/backend/storage/encryption/bufenc.c | 83 +++++++++++++++++++++++++++++++++ src/backend/storage/page/bufpage.c | 46 +++++++++++++++++- src/include/storage/bufpage.h | 9 +++- 11 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/backend/storage/encryption/bufenc.c diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index 4b2186b..a0c0f89 100644 --- a/contrib/bloom/blinsert.c +++ b/contrib/bloom/blinsert.c @@ -178,6 +178,7 @@ blbuildempty(Relation index) * XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we need * this even when wal_level=minimal. */ + PageEncryptInplace(metapage, BLOOM_METAPAGE_BLKNO, INIT_FORKNUM); PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO, (char *) metapage, true); diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index 838ee68..7444982 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -1028,6 +1028,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks) true); RelationOpenSmgr(rel); + PageEncryptInplace(page, lastblock , MAIN_FORKNUM); PageSetChecksumInplace(page, lastblock); smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf.data, false); diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index a17508a..47c602e 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -338,6 +338,8 @@ end_heap_rewrite(RewriteState state) true); RelationOpenSmgr(state->rs_new_rel); + PageEncryptInplace(state->rs_buffer, MAIN_FORKNUM, state->rs_blockno); + PageSetChecksumInplace(state->rs_buffer, state->rs_blockno); smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno, @@ -710,6 +712,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup) */ RelationOpenSmgr(state->rs_new_rel); + PageEncryptInplace(page, MAIN_FORKNUM, state->rs_blockno); + PageSetChecksumInplace(page, state->rs_blockno); smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 4cfd528..61bc879 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -169,6 +169,7 @@ btbuildempty(Relation index) * XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we need * this even when wal_level=minimal. */ + PageEncryptInplace(metapage, INIT_FORKNUM, BTREE_METAPAGE); PageSetChecksumInplace(metapage, BTREE_METAPAGE); smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE, (char *) metapage, true); diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index e678690..119034c 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -679,6 +679,7 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno) true); } + PageEncryptInplace(page, MAIN_FORKNUM, blkno); PageSetChecksumInplace(page, blkno); /* diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index b40bd44..deca284 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -168,6 +168,7 @@ spgbuildempty(Relation index) * of their existing content when the corresponding create records are * replayed. */ + PageEncryptInplace(page, SPGIST_METAPAGE_BLKNO, INIT_FORKNUM); PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO, (char *) page, true); @@ -177,6 +178,7 @@ spgbuildempty(Relation index) /* Likewise for the root page. */ SpGistInitPage(page, SPGIST_LEAF); + PageEncryptInplace(page, SPGIST_ROOT_BLKNO, INIT_FORKNUM); PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_ROOT_BLKNO, (char *) page, true); @@ -186,6 +188,7 @@ spgbuildempty(Relation index) /* Likewise for the null-tuples root page. */ SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS); + PageEncryptInplace(page, SPGIST_NULL_BLKNO, INIT_FORKNUM); PageSetChecksumInplace(page, SPGIST_NULL_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_NULL_BLKNO, (char *) page, true); diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 3cc886f..fc37462 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -338,7 +338,7 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, smgrread(src, forkNum, blkno, buf.data); - if (!PageIsVerified(page, blkno)) + if (!PageIsVerified(page, forkNum, blkno)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("invalid page in block %u of relation %s", diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 6f3a402..0df225f 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -906,7 +906,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, } /* check for garbage data */ - if (!PageIsVerified((Page) bufBlock, blockNum)) + if (!PageIsVerified((Page) bufBlock, forkNum, blockNum)) { if (mode == RBM_ZERO_ON_ERROR || zero_damaged_pages) { @@ -2743,12 +2743,15 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln) */ bufBlock = BufHdrGetBlock(buf); + bufToWrite = PageEncryptCopy((Page) bufBlock, buf->tag.forkNum, + buf->tag.blockNum); + /* * Update page checksum if desired. Since we have only shared lock on the * buffer, other processes might be updating hint bits in it, so we must * copy the page to private storage if we do checksumming. */ - bufToWrite = PageSetChecksumCopy((Page) bufBlock, buf->tag.blockNum); + bufToWrite = PageSetChecksumCopy((Page) bufToWrite, buf->tag.blockNum); if (track_io_timing) INSTR_TIME_SET_CURRENT(io_start); @@ -3213,6 +3216,9 @@ FlushRelationBuffers(Relation rel) localpage = (char *) LocalBufHdrGetBlock(bufHdr); + PageEncryptInplace(localpage, bufHdr->tag.forkNum, + bufHdr->tag.blockNum); + /* Setup error traceback support for ereport() */ errcallback.callback = local_buffer_write_error_callback; errcallback.arg = (void *) bufHdr; diff --git a/src/backend/storage/encryption/bufenc.c b/src/backend/storage/encryption/bufenc.c new file mode 100644 index 0000000..be91343 --- /dev/null +++ b/src/backend/storage/encryption/bufenc.c @@ -0,0 +1,83 @@ +/*------------------------------------------------------------------------- + * + * bufenc.c + * + * Copyright (c) 2019, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/storage/encryption/bufenc.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "storage/bufpage.h" +#include "storage/encryption.h" +#include "storage/fd.h" +#include "storage/kmgr.h" + +static char buf_encryption_iv[ENC_IV_SIZE]; + +static void set_buffer_encryption_iv(Page page, BlockNumber blocknum); + +void +EncryptBufferBlock(BlockNumber blocknum, Page page) +{ + /* + fprintf(stderr, "ENC offset %d, encsize %d, blkno %u: ", + PageEncryptOffset, SizeOfPageEncryption, blocknum); + //dp(" key", (unsigned char *) GetTableEncryptionKey(), EncryptionKeySize); + */ + + set_buffer_encryption_iv(page, blocknum); + //dp(" iv", (unsigned char *) buf_encryption_iv, ENC_IV_SIZE); + pg_encrypt(page + PageEncryptOffset, + page + PageEncryptOffset, + SizeOfPageEncryption, + GetTableEncryptionKey(), + buf_encryption_iv); +} +void +DecryptBufferBlock(BlockNumber blocknum, Page page) +{ +/* + fprintf(stderr, "DEC offset %d, encsize %d, blkno %u: ", + PageEncryptOffset, SizeOfPageEncryption, blocknum); +*/ + //dp(" key", GetTableEncryptionKey(), EncryptionKeySize); + + set_buffer_encryption_iv(page, blocknum); + //dp(" iv", (unsigned char *) buf_encryption_iv, ENC_IV_SIZE); + pg_decrypt(page + PageEncryptOffset, + page + PageEncryptOffset, + SizeOfPageEncryption, + GetTableEncryptionKey(), + buf_encryption_iv); +} + +static void +set_buffer_encryption_iv(Page page, BlockNumber blocknum) +{ + char *p = buf_encryption_iv; + + MemSet(buf_encryption_iv, 0, ENC_IV_SIZE); + + //PageXLogRecPtr lsn = ((PageHeader) page)->pd_lsn; + //fprintf(stderr, " -> setting iv lsn %x/%x, blkno %u\n", lsn.xlogid, lsn.xrecoff, blocknum); + + /* page lsn (8 byte) */ + memcpy(p, &((PageHeader) page)->pd_lsn, sizeof(PageXLogRecPtr)); + p += sizeof(PageXLogRecPtr); + + /* block number (4 byte) */ + memcpy(p, &blocknum, sizeof(BlockNumber)); + p += sizeof(BlockNumber); + + /* Space for counter (4 byte) */ + memset(p, 0, ENC_BUFFER_AES_COUNTER_SIZE); + p += ENC_BUFFER_AES_COUNTER_SIZE; + +} + diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index 6b49810..b698865 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -19,6 +19,7 @@ #include "access/xlog.h" #include "pgstat.h" #include "storage/checksum.h" +#include "storage/encryption.h" #include "utils/memdebug.h" #include "utils/memutils.h" @@ -79,7 +80,7 @@ PageInit(Page page, Size pageSize, Size specialSize) * will clean up such a page and make it usable. */ bool -PageIsVerified(Page page, BlockNumber blkno) +PageIsVerified(Page page, ForkNumber forknum, BlockNumber blkno) { PageHeader p = (PageHeader) page; size_t *pagebytes; @@ -102,6 +103,8 @@ PageIsVerified(Page page, BlockNumber blkno) checksum_failure = true; } + PageDecryptInplace(page, forknum, blkno); + /* * The following checks don't prove the header is correct, only that * it looks sane enough to allow into the buffer pool. Later usage of @@ -1203,3 +1206,44 @@ PageSetChecksumInplace(Page page, BlockNumber blkno) ((PageHeader) page)->pd_checksum = pg_checksum_page((char *) page, blkno); } + +char * +PageEncryptCopy(Page page, ForkNumber forknum, BlockNumber blkno) +{ + static char *pageCopy = NULL; + + if (PageIsNew(page) || !DataEncryptionEnabled() || !EncryptForkNum(forknum)) + return (char *) page; + + /* + * We allocate the copy space once and use it over on each subsequent + * call. The point of palloc'ing here, rather than having a static char + * array, is first to ensure adequate alignment for the checksumming code + * and second to avoid wasting space in processes that never call this. + */ + if (pageCopy == NULL) + pageCopy = MemoryContextAlloc(TopMemoryContext, BLCKSZ); + + memcpy(pageCopy, (char *) page, BLCKSZ); + EncryptBufferBlock(blkno, pageCopy); + return pageCopy; +} + +void +PageEncryptInplace(Page page, ForkNumber forknum, BlockNumber blkno) +{ + if (PageIsNew(page) || !DataEncryptionEnabled() || !EncryptForkNum(forknum)) + return; + + EncryptBufferBlock(blkno, page); +} + + +void +PageDecryptInplace(Page page, ForkNumber forknum, BlockNumber blkno) +{ + if (PageIsNew(page) || !DataEncryptionEnabled() || !EncryptForkNum(forknum)) + return; + + DecryptBufferBlock(blkno, page); +} diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index 4ef6d8d..1737adc 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -15,6 +15,7 @@ #define BUFPAGE_H #include "access/xlogdefs.h" +#include "common/relpath.h" #include "storage/block.h" #include "storage/item.h" #include "storage/off.h" @@ -165,6 +166,9 @@ typedef struct PageHeaderData typedef PageHeaderData *PageHeader; +#define PageEncryptOffset offsetof(PageHeaderData, pd_flags) +#define SizeOfPageEncryption (BLCKSZ - PageEncryptOffset) + /* * pd_flags contains the following flag bits. Undefined bits are initialized * to zero and may be used in the future. @@ -419,7 +423,7 @@ do { \ ((is_heap) ? PAI_IS_HEAP : 0)) extern void PageInit(Page page, Size pageSize, Size specialSize); -extern bool PageIsVerified(Page page, BlockNumber blkno); +extern bool PageIsVerified(Page page, ForkNumber forknum, BlockNumber blkno); extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size, OffsetNumber offsetNumber, int flags); extern Page PageGetTempPage(Page page); @@ -438,5 +442,8 @@ extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize); extern char *PageSetChecksumCopy(Page page, BlockNumber blkno); extern void PageSetChecksumInplace(Page page, BlockNumber blkno); +extern char *PageEncryptCopy(Page page, ForkNumber forknum, BlockNumber blkno); +extern void PageEncryptInplace(Page page, ForkNumber forknum, BlockNumber blkno); +extern void PageDecryptInplace(Page page, ForkNumber forknum, BlockNumber blkno); #endif /* BUFPAGE_H */ -- 2.10.5