v2-0004-WAL-encryption.patch

application/octet-stream

Filename: v2-0004-WAL-encryption.patch
Type: application/octet-stream
Part: 2
Message: Re: [Proposal] Table-level Transparent Data Encryption (TDE) and Key Management Service (KMS)

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 v2-0004
Subject: WAL encryption
File+
src/backend/access/transam/xlog.c 64 21
src/backend/access/transam/xlogreader.c 19 0
src/backend/access/transam/xlogutils.c 4 0
src/backend/replication/walsender.c 5 0
src/include/access/xlog_internal.h 1 0
src/include/access/xlogreader.h 1 0
src/include/storage/encryption.h 7 0
From 6402e69577a38db617c7489b7467de64b818ef44 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Wed, 30 Oct 2019 16:18:43 +0900
Subject: [PATCH v2 4/5] WAL encryption

---
 src/backend/access/transam/xlog.c       | 85 +++++++++++++++++++------
 src/backend/access/transam/xlogreader.c | 19 ++++++
 src/backend/access/transam/xlogutils.c  |  4 ++
 src/backend/replication/walsender.c     |  5 ++
 src/include/access/xlog_internal.h      |  1 +
 src/include/access/xlogreader.h         |  1 +
 src/include/storage/encryption.h        |  7 ++
 7 files changed, 101 insertions(+), 21 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index fe7b253df4..c0d4b3bdd3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -911,6 +911,7 @@ static void WriteControlFile(void);
 static void ReadControlFile(void);
 static char *str_time(pg_time_t tnow);
 static bool CheckForStandbyTrigger(void);
+static void XLogWritePages(char *from, Size nbytes, uint32 startoffset);
 
 #ifdef WAL_DEBUG
 static void xlog_outrec(StringInfo buf, XLogReaderState *record);
@@ -2487,34 +2488,33 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 		{
 			char	   *from;
 			Size		nbytes;
-			Size		nleft;
-			int			written;
 
 			/* OK to write the page(s) */
 			from = XLogCtl->pages + startidx * (Size) XLOG_BLCKSZ;
 			nbytes = npages * (Size) XLOG_BLCKSZ;
-			nleft = nbytes;
-			do
+
+			if (DataEncryptionEnabled())
 			{
-				errno = 0;
-				pgstat_report_wait_start(WAIT_EVENT_WAL_WRITE);
-				written = pg_pwrite(openLogFile, from, nleft, startoffset);
-				pgstat_report_wait_end();
-				if (written <= 0)
+				int i;
+
+				/* Encrypt xlog pages one by one */
+				for (i = 0; i < npages; i++)
 				{
-					if (errno == EINTR)
-						continue;
-					ereport(PANIC,
-							(errcode_for_file_access(),
-							 errmsg("could not write to log file %s "
-									"at offset %u, length %zu: %m",
-									XLogFileNameP(ThisTimeLineID, openLogSegNo),
-									startoffset, nleft)));
+					char	*buftowrite;
+					Size	nwrite = Min(nbytes, XLOG_BLCKSZ);
+
+					buftowrite = EncryptXLog(from, nwrite, openLogSegNo,
+											 startoffset);
+					XLogWritePages(buftowrite, nwrite, startoffset);
+					startoffset += nwrite;
+					from += XLOG_BLCKSZ;
 				}
-				nleft -= written;
-				from += written;
-				startoffset += written;
-			} while (nleft > 0);
+			}
+			else
+			{
+				XLogWritePages(from, npages * (Size) XLOG_BLCKSZ, startoffset);
+				startoffset +=  npages * (Size) XLOG_BLCKSZ;
+			}
 
 			npages = 0;
 
@@ -2630,6 +2630,39 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 	}
 }
 
+/*
+ * Write XLOG pages starting from 'startoffset'.
+ */
+static void
+XLogWritePages(char *from, Size nbytes, uint32 startoffset)
+{
+	Size	nleft;
+	Size	nwritten;
+
+	nleft = nbytes;
+	do
+	{
+		errno = 0;
+		pgstat_report_wait_start(WAIT_EVENT_WAL_WRITE);
+		nwritten = pg_pwrite(openLogFile, from, nleft, startoffset);
+		pgstat_report_wait_end();
+		if (nwritten <= 0)
+		{
+			if (errno == EINTR)
+				continue;
+			ereport(PANIC,
+					(errcode_for_file_access(),
+					 errmsg("could not write to log file %s "
+							"at offset %u, length %zu: %m",
+							XLogFileNameP(ThisTimeLineID, openLogSegNo),
+							startoffset, nleft)));
+		}
+		nleft -= nwritten;
+		from += nwritten;
+		startoffset += nwritten;
+	} while (nleft > 0);
+}
+
 /*
  * Record the LSN for an asynchronous transaction commit/abort
  * and nudge the WALWriter if there is work for it to do.
@@ -11707,6 +11740,16 @@ retry:
 
 	xlogreader->seg.ws_tli = curFileTLI;
 
+	/*
+	 * Decrypt read record so that we can validate page both short header
+	 * and possibly long header.
+	 */
+	if (DataEncryptionEnabled())
+	{
+		DecryptXLog(readBuf, XLOG_BLCKSZ, readSegNo, readOff);
+		xlogreader->encrypted = false;
+	}
+
 	/*
 	 * Check the page header immediately, so that we can retry immediately if
 	 * it's not valid. This may seem unnecessary, because XLogReadRecord()
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index c8b0d2303d..1710d74d0e 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -27,6 +27,7 @@
 
 #ifndef FRONTEND
 #include "miscadmin.h"
+#include "storage/encryption.h"
 #include "utils/memutils.h"
 #endif
 
@@ -585,6 +586,16 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
 		/* we can be sure to have enough WAL available, we scrolled back */
 		Assert(readLen == XLOG_BLCKSZ);
 
+#ifndef FRONTEND
+		if (state->encrypted)
+		{
+			uint32 off = XLogSegmentOffset(targetSegmentPtr, state->segcxt.ws_segsize);
+
+			DecryptXLog(state->readBuf, XLOG_BLCKSZ, targetSegNo, off);
+			state->encrypted = false;
+		}
+#endif
+
 		if (!XLogReaderValidatePageHeader(state, targetSegmentPtr,
 										  state->readBuf))
 			goto err;
@@ -620,6 +631,14 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
 			goto err;
 	}
 
+#ifndef FRONTEND
+	if (state->encrypted)
+	{
+		DecryptXLog(state->readBuf, XLOG_BLCKSZ, targetSegNo, targetPageOff);
+		state->encrypted = false;
+	}
+#endif
+
 	/*
 	 * Now that we know we have the full header, validate it.
 	 */
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 5f1e5ba75d..d83b7a5a65 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -25,6 +25,7 @@
 #include "access/xlogutils.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "storage/encryption.h"
 #include "storage/smgr.h"
 #include "utils/guc.h"
 #include "utils/hsearch.h"
@@ -1023,6 +1024,9 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
 	XLogRead(cur_page, state->segcxt.ws_segsize, state->seg.ws_tli, targetPagePtr,
 			 XLOG_BLCKSZ);
 
+	if (DataEncryptionEnabled())
+		state->encrypted = true;
+
 	/* number of valid bytes in the buffer */
 	return count;
 }
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index b0ebe5039c..691ac9f0f0 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -77,6 +77,7 @@
 #include "replication/walsender.h"
 #include "replication/walsender_private.h"
 #include "storage/condition_variable.h"
+#include "storage/encryption.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pmsignal.h"
@@ -788,6 +789,10 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req
 	/* now actually read the data, we know it's there */
 	XLogRead(sendCxt, cur_page, targetPagePtr, XLOG_BLCKSZ);
 
+	/* Decrypt xlog page if needed */
+	if (DataEncryptionEnabled())
+		state->encrypted = true;
+
 	return count;
 }
 
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 3f0de6625d..e11830e747 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -53,6 +53,7 @@ typedef struct XLogPageHeaderData
 } XLogPageHeaderData;
 
 #define SizeOfXLogShortPHD	MAXALIGN(sizeof(XLogPageHeaderData))
+#define XLogEncryptionOffset	SizeOfXLogShortPHD
 
 typedef XLogPageHeaderData *XLogPageHeader;
 
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 1bbee386e8..515f931157 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -164,6 +164,7 @@ struct XLogReaderState
 	 */
 	char	   *readBuf;
 	uint32		readLen;
+	bool		encrypted;	/* readBuf is encrypted? */
 
 	/* last read XLOG position for data currently in readBuf */
 	WALSegmentContext segcxt;
diff --git a/src/include/storage/encryption.h b/src/include/storage/encryption.h
index a8007fecb1..d38100d621 100644
--- a/src/include/storage/encryption.h
+++ b/src/include/storage/encryption.h
@@ -40,9 +40,16 @@
  * The size in byte for counter of AES-CTR mode in nonce.
  */
 #define ENC_BUFFER_AES_COUNTER_SIZE 4
+#define ENC_WAL_AES_COUNTER_SIZE 4
 
 /* bufenc.c */
 extern void DecryptBufferBlock(BlockNumber blocknum, Page page);
 extern void EncryptBufferBlock(BlockNumber blocknum, Page page);
 
+/* walenc.c */
+extern char *EncryptXLog(char *page, Size nbytes, XLogSegNo segno,
+						uint32 offset);
+extern void DecryptXLog(char *page, Size nbytes, XLogSegNo segno,
+						uint32 offset);
+
 #endif							/* ENCRYPTION_H */
-- 
2.23.0