8000 Defer decryption of relation keys · percona/postgres@057705e · GitHub
[go: up one dir, main page]

Skip to content

Commit 057705e

Browse files
committed
Defer decryption of relation keys
Don't decrypt relation keys until they're actually needed. In some cases tde_mdopen() is called after the transaction is committed which means that we're not longer able to abort the transaction if we fail when we fetch the principal key. This happens, for example, if dropping an encrypted table. Previously this would cause postmaster to panic if it didn't have access to the principal key.
1 parent db4e47e commit 057705e

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

contrib/pg_tde/src/smgr/pg_tde_smgr.c

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ typedef enum TDEMgrRelationDataEncryptionStatus
1414

1515
/* This is an encrypted relation, and we have the key available. */
1616
RELATION_KEY_AVAILABLE = 1,
17+
18+
/* This is an encrypted relation, but we haven't loaded the key yet. */
19+
RELATION_KEY_NOT_AVAILABLE = 2,
1720
} TDEMgrRelationDataEncryptionStatus;
1821

1922
typedef struct TDESMgrRelationData
@@ -36,6 +39,16 @@ typedef TDESMgrRelationData *TDESMgrRelation;
3639

3740
static void CalcBlockIv(ForkNumber forknum, BlockNumber bn, const unsigned char *base_iv, unsigned char *iv);
3841

42+
static bool
43+
tde_smgr_is_encrypted(const RelFileLocatorBackend *smgr_rlocator)
44+
{
45+
/* Do not try to encrypt/decrypt catalog tables */
46+
if (IsCatalogRelationOid(smgr_rlocator->locator.relNumber))
47+
return false;
48+
49+
return IsSMGRRelationEncrypted(*smgr_rlocator);
50+
}
51+
3952
static InternalKey *
4053
tde_smgr_get_key(const RelFileLocatorBackend *smgr_rlocator)
4154
{
@@ -80,18 +93,26 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
8093
const void **buffers, BlockNumber nblocks, bool skipFsync)
8194
{
8295
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
83-
InternalKey *int_key = &tdereln->relKey;
8496

8597
if (tdereln->encryption_status == RELATION_NOT_ENCRYPTED)
8698
{
8799
mdwritev(reln, forknum, blocknum, buffers, nblocks, skipFsync);
88100
}
89101
else
90102
{
103+
InternalKey *int_key;
91104
unsigned char *local_blocks = palloc(BLCKSZ * (nblocks + 1));
92105
unsigned char *local_blocks_aligned = (unsigned char *) TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
93106
void **local_buffers = palloc_array(void *, nblocks);
94107

108+
if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
109+
{
110+
tdereln->relKey = *tde_smgr_get_key(&reln->smgr_rlocator);
111+
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
112+
}
113+
114+
int_key = &tdereln->relKey;
115+
95116
for (int i = 0; i < nblocks; ++i)
96117
{
97118
BlockNumber bn = blocknum + i;
@@ -139,18 +160,26 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
139160
const void *buffer, bool skipFsync)
140161
{
141162
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
142-
InternalKey *int_key = &tdereln->relKey;
143163

144164
if (tdereln->encryption_status == RELATION_NOT_ENCRYPTED)
145165
{
146166
mdextend(reln, forknum, blocknum, buffer, skipFsync);
147167
}
148168
else
149169
{
170+
InternalKey *int_key;
150171
unsigned char *local_blocks = palloc(BLCKSZ * (1 + 1));
151172
unsigned char *local_blocks_aligned = (unsigned char *) TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
152173
unsigned char iv[16];
153174

175+
if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
176+
{
177+
tdereln->relKey = *tde_smgr_get_key(&reln->smgr_rlocator);
178+
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
179+
}
180+
181+
int_key = &tdereln->relKey;
182+
154183
CalcBlockIv(forknum, blocknum, int_key->base_iv, iv);
155184

156185
AesEncrypt(int_key->key, iv, ((unsigned char *) buffer), BLCKSZ, local_blocks_aligned);
@@ -172,6 +201,13 @@ tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
172201

173202
if (tdereln->encryption_status == RELATION_NOT_ENCRYPTED)
174203
return;
204+
else if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
205+
{
206+
tdereln->relKey = *tde_smgr_get_key(&reln->smgr_rlocator);
207+
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
208+
}
209+
210+
int_key = &tdereln->relKey;
175211

176212
for (int i = 0; i < nblocks; ++i)
177213
{
@@ -255,21 +291,21 @@ tde_mdcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool
255291

256292
/*
257293
* mdopen() -- Initialize newly-opened relation.
294+
*
295+
* The current transaction might already be commited when this function is
296+
* called, so do not call any code that uses ereport(ERROR) or otherwise tries
297+
* to abort the transaction.
258298
*/
259299
static void
260300
tde_mdopen(SMgrRelation reln)
261301
{
262302
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
263-
InternalKey *key;
264303

265304
mdopen(reln);
266305

267-
key = tde_smgr_get_key(&reln->smgr_rlocator);
268-
269-
if (key)
306+
if (tde_smgr_is_encrypted(&reln->smgr_rlocator))
270307
{
271-
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
272-
tdereln->relKey = *key;
308+
tdereln->encryption_status = RELATION_KEY_NOT_AVAILABLE;
273309
}
274310
else
275311
{

contrib/pg_tde/t/001_basic.pl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
);
2525

2626
PGTDE::psql($node, 'postgres',
27-
"SELECT pg_tde_add_database_key_provider_file('file-vault', '/tmp/pg_tde_test_keyring.per');"
27+
"SELECT pg_tde_add_database_key_provider_file('file-vault', '/tmp/pg_tde_test_001_basic.per');"
2828
);
2929

3030
PGTDE::psql($node, 'postgres',
@@ -56,6 +56,12 @@
5656
$strings .= `strings $tablefile | grep foo`;
5757
PGTDE::append_to_result_file($strings);
5858

59+
60+
# An encrypted table can be dropped even if we don't have access to the principal key.
61+
$node->stop;
62+
unlink('/tmp/pg_tde_test_001_basic.per');
63+
$node->start;
64+
PGTDE::psql($node, 'postgres', 'SELECT pg_tde_verify_key()');
5965
PGTDE::psql($node, 'postgres', 'DROP TABLE test_enc;');
6066

6167
PGTDE::psql($node, 'postgres', 'DROP EXTENSION pg_tde;');

contrib/pg_tde/t/expected/001_basic.out

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ SELECT extname, extversion FROM pg_extension WHERE extname = 'pg_tde';
88
CREATE TABLE test_enc (id SERIAL, k INTEGER, PRIMARY KEY (id)) USING tde_heap;
99
psql:<stdin>:1: ERROR: principal key not configured
1010
HINT: create one using pg_tde_set_key before using encrypted tables
11-
SELECT pg_tde_add_database_key_provider_file('file-vault', '/tmp/pg_tde_test_keyring.per');
11+
SELECT pg_tde_add_database_key_provider_file('file-vault', '/tmp/pg_tde_test_001_basic.per');
1212
pg_tde_add_database_key_provider_file
1313
---------------------------------------
1414
1
@@ -39,5 +39,7 @@ SELECT * FROM test_enc ORDER BY id;
3939

4040
TABLEFILE FOUND: yes
4141
CONTAINS FOO (should be empty):
42+
SELECT pg_tde_verify_key()
43+
psql:<stdin>:1: ERROR: failed to retrieve principal key test-db-key from keyring with ID 1
4244
DROP TABLE test_enc;
4345
DROP EXTENSION pg_tde;

0 commit comments

Comments
 (0)
0