0004-Introduce-buffer-encryption-for-cluster-encyrption.patch
application/octet-stream
Filename: 0004-Introduce-buffer-encryption-for-cluster-encyrption.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0004
Subject: Introduce buffer encryption for cluster encyrption.
| File | + | − |
|---|---|---|
| contrib/bloom/blinsert.c | 1 | 0 |
| src/backend/access/hash/hashpage.c | 1 | 0 |
| src/backend/access/heap/rewriteheap.c | 4 | 0 |
| src/backend/access/nbtree/nbtree.c | 1 | 0 |
| src/backend/access/nbtree/nbtsort.c | 1 | 0 |
| src/backend/access/spgist/spginsert.c | 3 | 0 |
| src/backend/catalog/storage.c | 1 | 1 |
| src/backend/storage/buffer/bufmgr.c | 8 | 2 |
| src/backend/storage/encryption/bufenc.c | 83 | 0 |
| src/backend/storage/page/bufpage.c | 45 | 1 |
| src/include/storage/bufpage.h | 8 | 1 |
From b18671840cf54f252bdf4d1de39840f690fd7d0a Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
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