v2-0004-WAL-encryption.patch
application/octet-stream
Filename: v2-0004-WAL-encryption.patch
Type: application/octet-stream
Part: 2
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