agora inbox for [email protected]
help / color / mirror / Atom feedFrom: Bruce Momjian <[email protected]>
Subject: [PATCH] cfe-12-rel_over_cfe-11-gist squash commit
Date: Tue, 6 Apr 2021 14:23:49 -0400
---
contrib/bloom/blinsert.c | 3 +
src/backend/access/gist/gist.c | 51 ++++----
src/backend/access/gist/gistbuild.c | 12 ++
src/backend/access/hash/hashpage.c | 1 +
src/backend/access/heap/rewriteheap.c | 7 ++
src/backend/access/nbtree/nbtree.c | 3 +
src/backend/access/nbtree/nbtsort.c | 4 +-
src/backend/access/spgist/spginsert.c | 6 +
src/backend/access/transam/xlog.c | 2 +
src/backend/bootstrap/bootstrap.c | 1 +
src/backend/catalog/storage.c | 7 +-
src/backend/crypto/Makefile | 1 +
src/backend/crypto/bufenc.c (new) | 174 ++++++++++++++++++++++++++
src/backend/postmaster/postmaster.c | 2 +
src/backend/storage/buffer/bufmgr.c | 22 +++-
src/backend/storage/buffer/localbuf.c | 8 +-
src/backend/storage/file/copydir.c | 27 +++-
src/backend/storage/file/reinit.c | 2 +-
src/backend/storage/page/bufpage.c | 51 +++++++-
src/backend/tcop/postgres.c | 2 +
src/include/access/gist.h | 5 +-
src/include/crypto/bufenc.h (new) | 28 +++++
src/include/storage/bufpage.h | 18 ++-
src/include/storage/copydir.h | 2 +-
24 files changed, 392 insertions(+), 47 deletions(-)
diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c
index d37ceef753..cb04aac963 100644
--- a/contrib/bloom/blinsert.c
+++ b/contrib/bloom/blinsert.c
@@ -177,7 +177,10 @@ blbuildempty(Relation index)
* XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we need
* this even when wal_level=minimal.
*/
+ PageEncryptInplace(metapage, INIT_FORKNUM, RelationIsPermanent(index),
+ BLOOM_METAPAGE_BLKNO);
PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO);
+
smgrwrite(index->rd_smgr, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO,
(char *) metapage, true);
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5ca5f17db3..5d5f109055 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -503,17 +503,14 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
if (is_build)
recptr = !FileEncryptionEnabled ? GistBuildLSN :
LSNForEncryption(RelationIsPermanent(rel));
+ else if (RelationNeedsWAL(rel))
+ recptr = gistXLogSplit(is_leaf,
+ dist, oldrlink, oldnsn, leftchildbuf,
+ markfollowright);
+ else if (FileEncryptionEnabled)
+ recptr = LSNForEncryption(RelationIsPermanent(rel));
else
- {
- if (RelationNeedsWAL(rel))
- recptr = gistXLogSplit(is_leaf,
- dist, oldrlink, oldnsn, leftchildbuf,
- markfollowright);
- else if (FileEncryptionEnabled)
- recptr = LSNForEncryption(RelationIsPermanent(rel));
- else
- recptr = gistGetFakeLSN(rel);
- }
+ recptr = gistGetFakeLSN(rel);
for (ptr = dist; ptr; ptr = ptr->next)
PageSetLSN(ptr->page, recptr);
@@ -573,28 +570,26 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
if (is_build)
recptr = !FileEncryptionEnabled ? GistBuildLSN :
LSNForEncryption(RelationIsPermanent(rel));
- else
+ else if (RelationNeedsWAL(rel))
{
- if (RelationNeedsWAL(rel))
- {
- OffsetNumber ndeloffs = 0,
- deloffs[1];
+ OffsetNumber ndeloffs = 0,
+ deloffs[1];
- if (OffsetNumberIsValid(oldoffnum))
- {
- deloffs[0] = oldoffnum;
- ndeloffs = 1;
- }
-
- recptr = gistXLogUpdate(buffer,
- deloffs, ndeloffs, itup, ntup,
- leftchildbuf);
+ if (OffsetNumberIsValid(oldoffnum))
+ {
+ deloffs[0] = oldoffnum;
+ ndeloffs = 1;
}
- else if (FileEncryptionEnabled)
- recptr = LSNForEncryption(RelationIsPermanent(rel));
- else
- recptr = gistGetFakeLSN(rel);
+
+ recptr = gistXLogUpdate(buffer,
+ deloffs, ndeloffs, itup, ntup,
+ leftchildbuf);
}
+ else if (FileEncryptionEnabled)
+ recptr = LSNForEncryption(RelationIsPermanent(rel));
+ else
+ recptr = gistGetFakeLSN(rel);
+
PageSetLSN(page, recptr);
if (newblkno)
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index a8b82483e8..bd3dc96eb9 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -454,6 +454,12 @@ gist_indexsortbuild(GISTBuildState *state)
RelationOpenSmgr(state->indexrel);
PageSetLSN(pagestate->page, !FileEncryptionEnabled ? GistBuildLSN :
LSNForEncryption(RelationIsPermanent(state->indexrel)));
+ /* Make sure LSNs are vaild, and if encryption, are not constant. */
+ Assert(!XLogRecPtrIsInvalid(PageGetLSN(pagestate->page)) &&
+ (!FileEncryptionEnabled ||
+ PageGetLSN(pagestate->page) != GistBuildLSN));
+ PageEncryptInplace(pagestate->page, MAIN_FORKNUM, RelationIsPermanent(state->indexrel),
+ GIST_ROOT_BLKNO);
PageSetChecksumInplace(pagestate->page, GIST_ROOT_BLKNO);
smgrwrite(state->indexrel->rd_smgr, MAIN_FORKNUM, GIST_ROOT_BLKNO,
pagestate->page, true);
@@ -577,6 +583,12 @@ gist_indexsortbuild_flush_ready_pages(GISTBuildState *state)
PageSetLSN(page, !FileEncryptionEnabled ? GistBuildLSN :
LSNForEncryption(RelationIsPermanent(state->indexrel)));
+ /* Make sure LSNs are vaild, and if encryption, are not constant. */
+ Assert(!XLogRecPtrIsInvalid(PageGetLSN(page)) &&
+ (!FileEncryptionEnabled ||
+ PageGetLSN(page) != GistBuildLSN));
+ PageEncryptInplace(page, MAIN_FORKNUM, RelationIsPermanent(state->indexrel),
+ blkno);
PageSetChecksumInplace(page, blkno);
smgrextend(state->indexrel->rd_smgr, MAIN_FORKNUM, blkno, page, true);
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 49a9867787..eae9a9f04a 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -1025,6 +1025,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
true);
RelationOpenSmgr(rel);
+ PageEncryptInplace(page, MAIN_FORKNUM, RelationIsPermanent(rel), lastblock);
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 1aff62cd42..981b73c101 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -324,6 +324,9 @@ end_heap_rewrite(RewriteState state)
state->rs_buffer,
true);
+ PageEncryptInplace(state->rs_buffer, MAIN_FORKNUM,
+ RelationIsPermanent(state->rs_new_rel),
+ state->rs_blockno);
PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);
RelationOpenSmgr(state->rs_new_rel);
@@ -697,6 +700,10 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
*/
RelationOpenSmgr(state->rs_new_rel);
+ /* XXX Do we need to encrypt a copy of the page here? */
+ PageEncryptInplace(page, MAIN_FORKNUM,
+ RelationIsPermanent(state->rs_old_rel),
+ 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 9282c9ea22..2dbb2d3ebc 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -162,7 +162,10 @@ btbuildempty(Relation index)
* XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we need
* this even when wal_level=minimal.
*/
+ PageEncryptInplace(metapage, INIT_FORKNUM, RelationIsPermanent(index),
+ BTREE_METAPAGE);
PageSetChecksumInplace(metapage, BTREE_METAPAGE);
+
smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE,
(char *) metapage, true);
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 2c4d7f6e25..6dbc1b6f25 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -657,13 +657,15 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
{
if (!wstate->btws_zeropage)
wstate->btws_zeropage = (Page) palloc0(BLCKSZ);
- /* don't set checksum for all-zero page */
+ /* don't set checksum or encryption for all-zero page */
smgrextend(wstate->index->rd_smgr, MAIN_FORKNUM,
wstate->btws_pages_written++,
(char *) wstate->btws_zeropage,
true);
}
+ PageEncryptInplace(page, MAIN_FORKNUM, RelationIsPermanent(wstate->index),
+ blkno);
PageSetChecksumInplace(page, blkno);
/*
diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c
index 1af0af7da2..4fd5645c6f 100644
--- a/src/backend/access/spgist/spginsert.c
+++ b/src/backend/access/spgist/spginsert.c
@@ -168,6 +168,8 @@ spgbuildempty(Relation index)
* of their existing content when the corresponding create records are
* replayed.
*/
+ PageEncryptInplace(page, INIT_FORKNUM, RelationIsPermanent(index),
+ SPGIST_METAPAGE_BLKNO);
PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO,
(char *) page, true);
@@ -177,6 +179,8 @@ spgbuildempty(Relation index)
/* Likewise for the root page. */
SpGistInitPage(page, SPGIST_LEAF);
+ PageEncryptInplace(page, INIT_FORKNUM, RelationIsPermanent(index),
+ SPGIST_ROOT_BLKNO);
PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_ROOT_BLKNO,
(char *) page, true);
@@ -186,6 +190,8 @@ spgbuildempty(Relation index)
/* Likewise for the null-tuples root page. */
SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS);
+ PageEncryptInplace(page, INIT_FORKNUM, RelationIsPermanent(index),
+ SPGIST_NULL_BLKNO);
PageSetChecksumInplace(page, SPGIST_NULL_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_NULL_BLKNO,
(char *) page, true);
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index dba690bc5e..7ac0ca8b4c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -45,6 +45,7 @@
#include "common/controldata_utils.h"
#include "crypto/kmgr.h"
#include "executor/instrument.h"
+#include "crypto/bufenc.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
@@ -5413,6 +5414,7 @@ BootStrapXLOG(void)
WriteControlFile();
BootStrapKmgr();
+ InitializeBufferEncryption();
if (terminal_fd != -1)
{
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index ce6419ddd6..e8545a72b8 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -29,6 +29,7 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/link-canary.h"
+#include "crypto/bufenc.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index cba7a9ada0..7f18020b9f 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -443,8 +443,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
smgrread(src, forkNum, blkno, buf.data);
- if (!PageIsVerifiedExtended(page, blkno,
- PIV_LOG_WARNING | PIV_REPORT_STAT))
+ if (!PageIsVerifiedExtended(page, forkNum,
+ relpersistence == RELPERSISTENCE_PERMANENT,
+ blkno, PIV_LOG_WARNING | PIV_REPORT_STAT))
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("invalid page in block %u of relation %s",
@@ -461,6 +462,8 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
if (use_wal)
log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
+ PageEncryptInplace(page, forkNum,
+ relpersistence == RELPERSISTENCE_PERMANENT, blkno);
PageSetChecksumInplace(page, blkno);
/*
diff --git a/src/backend/crypto/Makefile b/src/backend/crypto/Makefile
index c27362029d..8985a66875 100644
--- a/src/backend/crypto/Makefile
+++ b/src/backend/crypto/Makefile
@@ -13,6 +13,7 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = \
+ bufenc.o \
kmgr.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/crypto/bufenc.c b/src/backend/crypto/bufenc.c
new file mode 100644
index 0000000000..0c70c131e1
--- /dev/null
+++ b/src/backend/crypto/bufenc.c
@@ -0,0 +1,174 @@
+/*-------------------------------------------------------------------------
+ *
+ * bufenc.c
+ *
+ * Copyright (c) 2020, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/crypto/bufenc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "miscadmin.h"
+#include "lib/stringinfo.h"
+
+#include "access/gist.h"
+#include "access/xlog.h"
+#include "crypto/bufenc.h"
+#include "storage/bufpage.h"
+#include "storage/fd.h"
+
+/*
+ * We use the page LSN, page number, and permanent-bit to indicate if a fake
+ * LSN was used to create a nonce for each page.
+ */
+#define BUFENC_IV_SIZE 16
+
+static unsigned char buf_encryption_iv[BUFENC_IV_SIZE];
+
+PgCipherCtx *BufEncCtx = NULL;
+PgCipherCtx *BufDecCtx = NULL;
+
+static void set_buffer_encryption_iv(Page page, BlockNumber blkno,
+ bool relation_is_permanent);
+
+void
+InitializeBufferEncryption(void)
+{
+ const CryptoKey *key;
+
+ if (!FileEncryptionEnabled)
+ return;
+
+ key = KmgrGetKey(KMGR_KEY_ID_REL);
+
+ BufEncCtx = pg_cipher_ctx_create(PG_CIPHER_AES_CTR,
+ (unsigned char *) key->key,
+ (key->klen), true);
+ if (!BufEncCtx)
+ elog(ERROR, "cannot intialize encryption context");
+
+ BufDecCtx = pg_cipher_ctx_create(PG_CIPHER_AES_CTR,
+ (unsigned char *) key->key,
+ (key->klen), false);
+ if (!BufDecCtx)
+ elog(ERROR, "cannot intialize decryption context");
+}
+
+/* Encrypt the given page with the relation key */
+void
+EncryptPage(Page page, bool relation_is_permanent, BlockNumber blkno)
+{
+ unsigned char *ptr = (unsigned char *) page + PageEncryptOffset;
+ bool is_gist_page_or_similar;
+
+ int enclen;
+
+ Assert(BufEncCtx != NULL);
+
+ /*
+ * Permanent pages have valid LSNs, and non-permanent pages usually have
+ * invalid (not set) LSNs. (One exception are GiST fake LSNs, see below.)
+ * However, we need valid ones on all pages for encryption. There are too
+ * many places that set the page LSN for permanent pages to do the same
+ * for non-permanent pages, so we just set it here.
+ *
+ * Also, while permanent relations get new LSNs every time the page is
+ * modified, for non-permanent relations do not, so we just update the LSN
+ * here before it is encrypted.
+ *
+ * GiST indexes uses LSNs, which are also stored in NSN fields, to detect
+ * page splits. Therefore, we allow the GiST code to assign LSNs and we
+ * don't change them here.
+ */
+
+ /* Permanent relations should already have valid LSNs. */
+ Assert(!XLogRecPtrIsInvalid(PageGetLSN(page)) || !relation_is_permanent);
+
+ /*
+ * Check if the page has a special size == GISTPageOpaqueData, a valid
+ * GIST_PAGE_ID, no invalid GiST flag bits are set, and a valid LSN. This
+ * is true for all GiST pages, and perhaps a few pages that are not. The
+ * only downside of guessing wrong is that we might not update the LSN for
+ * some non-permanent relation page changes, and therefore reuse the IV,
+ * which seems acceptable.
+ */
+ is_gist_page_or_similar =
+ (PageGetSpecialSize(page) == MAXALIGN(sizeof(GISTPageOpaqueData)) &&
+ GistPageGetOpaque(page)->gist_page_id == GIST_PAGE_ID &&
+ (GistPageGetOpaque(page)->flags & ~GIST_FLAG_BITMASK) == 0 &&
+ !XLogRecPtrIsInvalid(PageGetLSN(page)));
+
+ if (!relation_is_permanent && !is_gist_page_or_similar)
+ PageSetLSN(page, LSNForEncryption(relation_is_permanent));
+
+ set_buffer_encryption_iv(page, blkno, relation_is_permanent);
+ if (unlikely(!pg_cipher_encrypt(BufEncCtx, PG_CIPHER_AES_CTR,
+ (const unsigned char *) ptr, /* input */
+ SizeOfPageEncryption,
+ ptr, /* length */
+ &enclen, /* resulting length */
+ buf_encryption_iv, /* iv */
+ BUFENC_IV_SIZE,
+ NULL, 0)))
+ elog(ERROR, "cannot encrypt page %u", blkno);
+
+ Assert(enclen == SizeOfPageEncryption);
+}
+
+/* Decrypt the given page with the relation key */
+void
+DecryptPage(Page page, bool relation_is_permanent, BlockNumber blkno)
+{
+ unsigned char *ptr = (unsigned char *) page + PageEncryptOffset;
+ int enclen;
+
+ Assert(BufDecCtx != NULL);
+
+ set_buffer_encryption_iv(page, blkno, relation_is_permanent);
+ if (unlikely(!pg_cipher_decrypt(BufDecCtx, PG_CIPHER_AES_CTR,
+ (const unsigned char *) ptr, /* input */
+ SizeOfPageEncryption,
+ ptr, /* output */
+ &enclen, /* resulting length */
+ buf_encryption_iv, /* iv */
+ BUFENC_IV_SIZE,
+ NULL, 0)))
+ elog(ERROR, "cannot decrypt page %u", blkno);
+
+ Assert(enclen == SizeOfPageEncryption);
+}
+
+/* Construct iv for the given page */
+static void
+set_buffer_encryption_iv(Page page, BlockNumber blkno,
+ bool relation_is_permanent)
+{
+ unsigned char *p = buf_encryption_iv;
+
+ MemSet(buf_encryption_iv, 0, BUFENC_IV_SIZE);
+
+ /* page lsn (8 byte) */
+ memcpy(p, &((PageHeader) page)->pd_lsn, sizeof(PageXLogRecPtr));
+ p += sizeof(PageXLogRecPtr);
+
+ /* block number (4 byte) */
+ memcpy(p, &blkno, sizeof(BlockNumber));
+ p += sizeof(BlockNumber);
+
+ /*
+ * Mark use of fake LSNs in IV so if the real and fake LSN counters
+ * overlap, the IV will remain unique. XXX Is there a better value?
+ */
+ if (!relation_is_permanent)
+ *p++ = 0x80;
+
+ /*
+ * The maximum required counter for AES-CTR is 2048, which fits in the
+ * last three bytes.
+ */
+}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 11dd3eadff..df238c6260 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -100,6 +100,7 @@
#include "common/file_perm.h"
#include "common/ip.h"
#include "common/string.h"
+#include "crypto/bufenc.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
#include "libpq/libpq.h"
@@ -1339,6 +1340,7 @@ PostmasterMain(int argc, char *argv[])
RemovePgTempFiles();
InitializeKmgr();
+ InitializeBufferEncryption();
if (terminal_fd != -1)
close(terminal_fd);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 367fed5e85..7d913e038a 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -37,6 +37,7 @@
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/storage.h"
+#include "crypto/bufenc.h"
#include "executor/instrument.h"
#include "lib/binaryheap.h"
#include "miscadmin.h"
@@ -930,7 +931,9 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
}
/* check for garbage data */
- if (!PageIsVerifiedExtended((Page) bufBlock, blockNum,
+ if (!PageIsVerifiedExtended((Page) bufBlock, forkNum,
+ relpersistence == RELPERSISTENCE_PERMANENT,
+ blockNum,
PIV_LOG_WARNING | PIV_REPORT_STAT))
{
if (mode == RBM_ZERO_ON_ERROR || zero_damaged_pages)
@@ -2810,12 +2813,24 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln)
*/
bufBlock = BufHdrGetBlock(buf);
+ if (FileEncryptionEnabled)
+ {
+ /*
+ * Technically BM_PERMANENT could indicate an init fork, but that's
+ * okay since forkNum would also tell us not to encrypt init forks.
+ */
+ bufToWrite = PageEncryptCopy((Page) bufBlock, buf->tag.forkNum,
+ buf_state & BM_PERMANENT, buf->tag.blockNum);
+ bufToWrite = PageSetChecksumCopy((Page) bufToWrite, buf->tag.blockNum);
+ }
+ else
+ bufToWrite = PageSetChecksumCopy((Page) bufBlock, 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);
if (track_io_timing)
INSTR_TIME_SET_CURRENT(io_start);
@@ -3474,6 +3489,9 @@ FlushRelationBuffers(Relation rel)
errcallback.previous = error_context_stack;
error_context_stack = &errcallback;
+ /* XXX should we be writing a copy of the page here? */
+ PageEncryptInplace(localpage, bufHdr->tag.forkNum,
+ RelationIsPermanent(rel), bufHdr->tag.blockNum);
PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
smgrwrite(rel->rd_smgr,
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index 04b3558ea3..1033467885 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -159,7 +159,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum,
}
return bufHdr;
}
-
+
#ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
smgr->smgr_rnode.node.relNode, forkNum, blockNum,
@@ -217,6 +217,12 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum,
/* Find smgr relation for buffer */
oreln = smgropen(bufHdr->tag.rnode, MyBackendId);
+ /*
+ * Technically BM_PERMANENT could indicate an init fork, but that's
+ * okay since forkNum would also tell us not to encrypt init forks.
+ */
+ PageEncryptInplace(localpage, bufHdr->tag.forkNum,
+ buf_state & BM_PERMANENT, bufHdr->tag.blockNum);
PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
/* And write... */
diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
index da8b7cbeca..f41387abd3 100644
--- a/src/backend/storage/file/copydir.c
+++ b/src/backend/storage/file/copydir.c
@@ -22,6 +22,8 @@
#include <unistd.h>
#include <sys/stat.h>
+#include "access/xloginsert.h"
+#include "crypto/bufenc.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/copydir.h"
@@ -74,7 +76,7 @@ copydir(char *fromdir, char *todir, bool recurse)
copydir(fromfile, tofile, true);
}
else if (S_ISREG(fst.st_mode))
- copy_file(fromfile, tofile);
+ copy_file(fromfile, tofile, false);
}
FreeDir(xldir);
@@ -124,7 +126,7 @@ copydir(char *fromdir, char *todir, bool recurse)
* copy one file
*/
void
-copy_file(char *fromfile, char *tofile)
+copy_file(char *fromfile, char *tofile, bool encrypt_init_file)
{
char *buffer;
int srcfd;
@@ -132,9 +134,8 @@ copy_file(char *fromfile, char *tofile)
int nbytes;
off_t offset;
off_t flush_offset;
-
/* Size of copy buffer (read and write requests) */
-#define COPY_BUF_SIZE (8 * BLCKSZ)
+ int copy_buf_size = (encrypt_init_file) ? BLCKSZ : 8 * BLCKSZ;
/*
* Size of data flush requests. It seems beneficial on most platforms to
@@ -149,7 +150,7 @@ copy_file(char *fromfile, char *tofile)
#endif
/* Use palloc to ensure we get a maxaligned buffer */
- buffer = palloc(COPY_BUF_SIZE);
+ buffer = palloc(copy_buf_size);
/*
* Open the files
@@ -187,7 +188,7 @@ copy_file(char *fromfile, char *tofile)
}
pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
- nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
+ nbytes = read(srcfd, buffer, copy_buf_size);
pgstat_report_wait_end();
if (nbytes < 0)
ereport(ERROR,
@@ -195,6 +196,20 @@ copy_file(char *fromfile, char *tofile)
errmsg("could not read file \"%s\": %m", fromfile)));
if (nbytes == 0)
break;
+ /*
+ * When we copy an init fork page to be part of an empty unlogged
+ * relation, its real LSN must be replaced with a fake one, and the
+ * page encrypted.
+ */
+ if (encrypt_init_file)
+ {
+ Page page = (Page) buffer;
+
+ Assert(nbytes == BLCKSZ);
+ PageSetLSN(page, LSNForEncryption(false));
+ PageEncryptInplace(page, MAIN_FORKNUM, false, offset / BLCKSZ);
+ }
+
errno = 0;
pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE);
if ((int) write(dstfd, buffer, nbytes) != nbytes)
diff --git a/src/backend/storage/file/reinit.c b/src/backend/storage/file/reinit.c
index 40c758d789..9953bb2e1f 100644
--- a/src/backend/storage/file/reinit.c
+++ b/src/backend/storage/file/reinit.c
@@ -300,7 +300,7 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
/* OK, we're ready to perform the actual copy. */
elog(DEBUG2, "copying %s to %s", srcpath, dstpath);
- copy_file(srcpath, dstpath);
+ copy_file(srcpath, dstpath, true);
}
FreeDir(dbspace_dir);
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index 5d5989c2f5..28cc9d3b36 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -17,6 +17,7 @@
#include "access/htup_details.h"
#include "access/itup.h"
#include "access/xlog.h"
+#include "crypto/bufenc.h"
#include "pgstat.h"
#include "storage/checksum.h"
#include "utils/memdebug.h"
@@ -85,7 +86,8 @@ PageInit(Page page, Size pageSize, Size specialSize)
* to pgstat.
*/
bool
-PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
+PageIsVerifiedExtended(Page page, ForkNumber forknum, bool relation_is_permanent,
+ BlockNumber blkno, int flags)
{
PageHeader p = (PageHeader) page;
size_t *pagebytes;
@@ -108,6 +110,8 @@ PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
checksum_failure = true;
}
+ PageDecryptInplace(page, forknum, relation_is_permanent, 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
@@ -1433,3 +1437,48 @@ PageSetChecksumInplace(Page page, BlockNumber blkno)
((PageHeader) page)->pd_checksum = pg_checksum_page((char *) page, blkno);
}
+
+char *
+PageEncryptCopy(Page page, ForkNumber forknum, bool relation_is_permanent,
+ BlockNumber blkno)
+{
+ static char *pageCopy = NULL;
+
+ /* If we don't need a checksum, just return the passed-in data */
+ if (PageIsNew(page) || !PageNeedsToBeEncrypted(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);
+ EncryptPage(pageCopy, relation_is_permanent, blkno);
+ return pageCopy;
+}
+
+void
+PageEncryptInplace(Page page, ForkNumber forknum, bool relation_is_permanent,
+ BlockNumber blkno)
+{
+ if (PageIsNew(page) || !PageNeedsToBeEncrypted(forknum))
+ return;
+
+ EncryptPage(page, relation_is_permanent, blkno);
+}
+
+
+void
+PageDecryptInplace(Page page, ForkNumber forknum, bool relation_is_permanent,
+ BlockNumber blkno)
+{
+ if (PageIsNew(page) || !PageNeedsToBeEncrypted(forknum))
+ return;
+
+ DecryptPage(page, relation_is_permanent, blkno);
+}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index d36ac60da3..d667e6fbdb 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -42,6 +42,7 @@
#include "catalog/pg_type.h"
#include "commands/async.h"
#include "commands/prepare.h"
+#include "crypto/bufenc.h"
#include "executor/spi.h"
#include "jit/jit.h"
#include "libpq/libpq.h"
@@ -4039,6 +4040,7 @@ PostgresMain(int argc, char *argv[],
if (!IsUnderPostmaster)
{
InitializeKmgr();
+ InitializeBufferEncryption();
if (terminal_fd != -1)
close(terminal_fd);
diff --git a/src/include/access/gist.h b/src/include/access/gist.h
index 4b06575d98..04f11fb369 100644
--- a/src/include/access/gist.h
+++ b/src/include/access/gist.h
@@ -41,7 +41,7 @@
#define GISTNProcs 11
/*
- * Page opaque data in a GiST index page.
+ * Page opaque data flags in a GiST index page.
*/
#define F_LEAF (1 << 0) /* leaf page */
#define F_DELETED (1 << 1) /* the page has been deleted */
@@ -51,6 +51,9 @@
#define F_HAS_GARBAGE (1 << 4) /* some tuples on the page are dead,
* but not deleted yet */
+/* Specifies the bits that can be set in the GiST flags field */
+#define GIST_FLAG_BITMASK 0x1F
+
/*
* NSN (node sequence number) is a special-purpose LSN which is stored on each
* index page in GISTPageOpaqueData and updated only during page splits. By
diff --git a/src/include/crypto/bufenc.h b/src/include/crypto/bufenc.h
new file mode 100644
index 0000000000..cc86ceb821
--- /dev/null
+++ b/src/include/crypto/bufenc.h
@@ -0,0 +1,28 @@
+/*-------------------------------------------------------------------------
+ *
+ * bufenc.h
+ *
+ * Portions Copyright (c) 2021, PostgreSQL Global Development Group
+ *
+ * src/include/crypto/bufenc.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef BUFENC_H
+#define BUFENC_H
+
+#include "storage/bufmgr.h"
+#include "crypto/kmgr.h"
+
+/* Cluster encryption encrypts only main forks */
+#define PageNeedsToBeEncrypted(forknum) \
+ (FileEncryptionEnabled && (forknum) == MAIN_FORKNUM)
+
+
+extern void InitializeBufferEncryption(void);
+extern void EncryptPage(Page page, bool relation_is_permanent,
+ BlockNumber blkno);
+extern void DecryptPage(Page page, bool relation_is_permanent,
+ BlockNumber blkno);
+
+#endif /* BUFENC_H */
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index 359b749f7f..f9d97e7c04 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"
@@ -164,6 +165,8 @@ typedef struct PageHeaderData
} PageHeaderData;
typedef PageHeaderData *PageHeader;
+#define PageEncryptOffset offsetof(PageHeaderData, pd_special)
+#define SizeOfPageEncryption (BLCKSZ - PageEncryptOffset)
/*
* pd_flags contains the following flag bits. Undefined bits are initialized
@@ -418,8 +421,8 @@ do { \
((overwrite) ? PAI_OVERWRITE : 0) | \
((is_heap) ? PAI_IS_HEAP : 0))
-#define PageIsVerified(page, blkno) \
- PageIsVerifiedExtended(page, blkno, \
+#define PageIsVerified(page, relation_is_permanent, blkno) \
+ PageIsVerifiedExtended(page, MAIN_FORKNUM, relation_is_permanent, blkno, \
PIV_LOG_WARNING | PIV_REPORT_STAT)
/*
@@ -433,7 +436,10 @@ StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)),
"BLCKSZ has to be a multiple of sizeof(size_t)");
extern void PageInit(Page page, Size pageSize, Size specialSize);
-extern bool PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags);
+extern bool PageIsVerifiedExtended(Page page, ForkNumber forknum,
+ bool relation_is_permanent,
+ BlockNumber blkno,
+ int flags);
extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
OffsetNumber offsetNumber, int flags);
extern Page PageGetTempPage(Page page);
@@ -452,5 +458,11 @@ 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,
+ bool relation_is_permanent, BlockNumber blkno);
+extern void PageEncryptInplace(Page page, ForkNumber forknum,
+ bool relation_is_permanent, BlockNumber blkno);
+extern void PageDecryptInplace(Page page, ForkNumber forknum,
+ bool relation_is_permanent, BlockNumber blkno);
#endif /* BUFPAGE_H */
diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h
index 2c3936b0da..669c04d581 100644
--- a/src/include/storage/copydir.h
+++ b/src/include/storage/copydir.h
@@ -14,6 +14,6 @@
#define COPYDIR_H
extern void copydir(char *fromdir, char *todir, bool recurse);
-extern void copy_file(char *fromfile, char *tofile);
+extern void copy_file(char *fromfile, char *tofile, bool encrypt_init_file);
#endif /* COPYDIR_H */
--
2.20.1
--gatW/ieO32f1wygP--
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [PATCH] cfe-12-rel_over_cfe-11-gist squash commit
In-Reply-To: <no-message-id-162822@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox