PG-1095 Add format validation CI workflow and format sources (#308)

* PG-1095 Add code format validation to CI

* PG-1095 Manually fix some codestyle

* PG-1095 Add comment to pgindent_exclude file

* PG-1095 Format sources

* PG-1095 Fix makefile

* PG-1095 Remove accidentally commited file

* PG-1094 Update gitignore

* PG-1094 Update pgindent_exclude

* PG-1095 Update typedefs list

* PG-1095 Manual code formatting

* PG-1095 Update typedefs list

* PG-1095 More manual code formatting

* PG-1095 More manual code formatting

* PG-1095 More fixes

* PG-1095 Fix
pull/209/head
Artem Gavrilov 10 months ago committed by GitHub
parent 2f31c0ed45
commit d2237acde5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 57
      .github/workflows/check.yaml
  2. 4
      .gitignore
  3. 11
      Makefile.in
  4. 9
      pgindent_excludes
  5. 56
      src/access/pg_tde_ddl.c
  6. 112
      src/access/pg_tde_slot.c
  7. 276
      src/access/pg_tde_tdemap.c
  8. 13
      src/access/pg_tde_xlog.c
  9. 131
      src/access/pg_tde_xlog_encrypt.c
  10. 29
      src/catalog/tde_global_space.c
  11. 171
      src/catalog/tde_keyring.c
  12. 30
      src/catalog/tde_keyring_parse_opts.c
  13. 947
      src/catalog/tde_principal_key.c
  14. 52
      src/common/pg_tde_shmem.c
  15. 101
      src/common/pg_tde_utils.c
  16. 131
      src/encryption/enc_aes.c
  17. 200
      src/encryption/enc_tde.c
  18. 2
      src/include/access/pg_tde_ddl.h
  19. 18
      src/include/access/pg_tde_slot.h
  20. 10
      src/include/access/pg_tde_tdemap.h
  21. 4
      src/include/access/pg_tde_xlog.h
  22. 4
      src/include/access/pg_tde_xlog_encrypt.h
  23. 4
      src/include/access/pg_tde_xlog_encrypt_fe.h
  24. 2
      src/include/catalog/tde_global_space.h
  25. 29
      src/include/catalog/tde_keyring.h
  26. 28
      src/include/catalog/tde_principal_key.h
  27. 59
      src/include/common/pg_tde_shmem.h
  28. 8
      src/include/common/pg_tde_utils.h
  29. 8
      src/include/encryption/enc_aes.h
  30. 16
      src/include/encryption/enc_tde.h
  31. 12
      src/include/keyring/keyring_api.h
  32. 13
      src/include/keyring/keyring_curl.h
  33. 2
      src/include/keyring/keyring_file.h
  34. 2
      src/include/keyring/keyring_vault.h
  35. 10
      src/include/pg_tde.h
  36. 10
      src/include/pg_tde_defines.h
  37. 2
      src/include/pg_tde_defs.h
  38. 12
      src/include/pg_tde_event_capture.h
  39. 2
      src/include/smgr/pg_tde_smgr.h
  40. 4
      src/include/transam/pg_tde_xact_handler.h
  41. 24
      src/keyring/keyring_api.c
  42. 73
      src/keyring/keyring_curl.c
  43. 55
      src/keyring/keyring_file.c
  44. 88
      src/keyring/keyring_vault.c
  45. 39
      src/pg_tde.c
  46. 4
      src/pg_tde_defs.c
  47. 18
      src/pg_tde_event_capture.c
  48. 139
      src/smgr/pg_tde_smgr.c
  49. 166
      src/transam/pg_tde_xact_handler.c
  50. 113
      typedefs.list

@ -0,0 +1,57 @@
name: Checks
on:
pull_request:
jobs:
format:
name: Format
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libcurl4-openssl-dev
- name: Clone postgres repository
uses: actions/checkout@v4
with:
repository: 'postgres/postgres'
ref: 'REL_17_STABLE'
- name: Checkout sources
uses: actions/checkout@v4
with:
path: 'contrib/pg_tde'
- name: Configure postgres
run: ./configure
- name: Configure pg_tde
run: ./configure
working-directory: contrib/pg_tde
- name: Install perltidy
run: sudo cpan -T SHANCOCK/Perl-Tidy-20230309.tar.gz
- name: Install pg_bsd_indent
working-directory: src/tools/pg_bsd_indent
run: sudo make install
- name: Add pg_bsd_indent and pgindent to path
run: |
echo "/usr/local/pgsql/bin" >> $GITHUB_PATH
echo "${{ github.workspace }}/src/tools/pgindent" >> $GITHUB_PATH
- name: Format sources
working-directory: contrib/pg_tde
run: |
make update-typedefs
make indent
- name: Check files are formatted and no source code changes
working-directory: contrib/pg_tde
run: |
git status
git diff --exit-code

4
.gitignore vendored

@ -9,3 +9,7 @@ __pycache__
/autom4te.cache /autom4te.cache
/configure~ /configure~
t/results t/results
src/include/config.h
# tools files
typedefs-full.list

@ -74,3 +74,14 @@ include $(top_srcdir)/contrib/contrib-global.mk
endif endif
override SHLIB_LINK += @tde_LDFLAGS@ -lcrypto -lssl override SHLIB_LINK += @tde_LDFLAGS@ -lcrypto -lssl
# Fetches typedefs list for PostgreSQL core and merges it with typedefs defined in this project.
# https://wiki.postgresql.org/wiki/Running_pgindent_on_non-core_code_or_development_code
update-typedefs:
wget -q -O - "https://buildfarm.postgresql.org/cgi-bin/typedefs.pl?branch=REL_17_STABLE" | cat - typedefs.list | sort | uniq > typedefs-full.list
# Indents projects sources.
indent:
pgindent --typedefs=typedefs-full.list --excludes=pgindent_excludes .
.PHONY: update-typedefs indent

@ -0,0 +1,9 @@
# List of filename patterns to exclude from pgindent runs
#
# This contains code copied from postgres tree as is and slightly modified.
# We don't want to run pgindent on these files to avoid unnecessary conflicts.
src\d\d/
# This file is generated by configure and should not be formatted
src/include/config.h

@ -20,37 +20,39 @@
static object_access_hook_type prev_object_access_hook = NULL; static object_access_hook_type prev_object_access_hook = NULL;
static void tdeheap_object_access_hook(ObjectAccessType access, Oid classId, static void tdeheap_object_access_hook(ObjectAccessType access, Oid classId,
Oid objectId, int subId, void *arg); Oid objectId, int subId, void *arg);
void SetupTdeDDLHooks(void) void
SetupTdeDDLHooks(void)
{ {
prev_object_access_hook = object_access_hook; prev_object_access_hook = object_access_hook;
object_access_hook = tdeheap_object_access_hook; object_access_hook = tdeheap_object_access_hook;
} }
static void static void
tdeheap_object_access_hook(ObjectAccessType access, Oid classId, Oid objectId, tdeheap_object_access_hook(ObjectAccessType access, Oid classId, Oid objectId,
int subId, void *arg) int subId, void *arg)
{ {
Relation rel = NULL; Relation rel = NULL;
if (prev_object_access_hook) if (prev_object_access_hook)
prev_object_access_hook(access, classId, objectId, subId, arg); prev_object_access_hook(access, classId, objectId, subId, arg);
if (access == OAT_DROP && classId == RelationRelationId) if (access == OAT_DROP && classId == RelationRelationId)
{ {
ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg; ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
rel = relation_open(objectId, AccessShareLock);
} rel = relation_open(objectId, AccessShareLock);
if (rel != NULL) }
{ if (rel != NULL)
if ((rel->rd_rel->relkind == RELKIND_RELATION || {
rel->rd_rel->relkind == RELKIND_TOASTVALUE || if ((rel->rd_rel->relkind == RELKIND_RELATION ||
rel->rd_rel->relkind == RELKIND_MATVIEW) && rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
(subId == 0) && is_tdeheap_rel(rel)) rel->rd_rel->relkind == RELKIND_MATVIEW) &&
{ (subId == 0) && is_tdeheap_rel(rel))
pg_tde_delete_key_map_entry(&rel->rd_locator, MAP_ENTRY_VALID); {
} pg_tde_delete_key_map_entry(&rel->rd_locator, MAP_ENTRY_VALID);
relation_close(rel, AccessShareLock); }
} relation_close(rel, AccessShareLock);
}
} }

@ -41,14 +41,15 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple;
static HeapTuple slot_copytuple(void *buffer, HeapTuple tuple); static HeapTuple slot_copytuple(void *buffer, HeapTuple tuple);
static pg_attribute_always_inline void tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, int natts); static pg_attribute_always_inline void tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, int natts);
static inline void tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot, static inline void tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot,
HeapTuple tuple, HeapTuple tuple,
Buffer buffer, Buffer buffer,
bool transfer_pin); bool transfer_pin);
static inline RelKeyData *get_current_slot_relation_key(TDEBufferHeapTupleTableSlot *bslot, Relation rel); static inline RelKeyData *get_current_slot_relation_key(TDEBufferHeapTupleTableSlot *bslot, Relation rel);
static void static void
tdeheap_tts_buffer_heap_init(TupleTableSlot *slot) tdeheap_tts_buffer_heap_init(TupleTableSlot *slot)
{ {
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot; TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
bslot->cached_relation_key = NULL; bslot->cached_relation_key = NULL;
} }
@ -111,34 +112,34 @@ tdeheap_tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnul
*/ */
if (!bslot->base.tuple) if (!bslot->base.tuple)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot retrieve a system column in this context"))); errmsg("cannot retrieve a system column in this context")));
return tdeheap_getsysattr(bslot->base.tuple, attnum, return tdeheap_getsysattr(bslot->base.tuple, attnum,
slot->tts_tupleDescriptor, isnull); slot->tts_tupleDescriptor, isnull);
} }
static bool static bool
tdeheap_buffer_is_current_xact_tuple(TupleTableSlot *slot) tdeheap_buffer_is_current_xact_tuple(TupleTableSlot *slot)
{ {
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
TransactionId xmin; TransactionId xmin;
Assert(!TTS_EMPTY(slot)); Assert(!TTS_EMPTY(slot));
/* /*
* In some code paths it's possible to get here with a non-materialized * In some code paths it's possible to get here with a non-materialized
* slot, in which case we can't check if tuple is created by the current * slot, in which case we can't check if tuple is created by the current
* transaction. * transaction.
*/ */
if (!bslot->base.tuple) if (!bslot->base.tuple)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("don't have a storage tuple in this context"))); errmsg("don't have a storage tuple in this context")));
xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data); xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
return TransactionIdIsCurrentTransactionId(xmin); return TransactionIdIsCurrentTransactionId(xmin);
} }
static void static void
@ -172,8 +173,8 @@ tdeheap_tts_buffer_heap_materialize(TupleTableSlot *slot)
* materializable. * materializable.
*/ */
bslot->base.tuple = tdeheap_form_tuple(slot->tts_tupleDescriptor, bslot->base.tuple = tdeheap_form_tuple(slot->tts_tupleDescriptor,
slot->tts_values, slot->tts_values,
slot->tts_isnull); slot->tts_isnull);
} }
else else
{ {
@ -229,7 +230,7 @@ tdeheap_tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslo
Assert(BufferIsValid(bsrcslot->buffer)); Assert(BufferIsValid(bsrcslot->buffer));
tdeheap_tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple, tdeheap_tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
bsrcslot->buffer, false); bsrcslot->buffer, false);
/* /*
* The HeapTupleData portion of the source tuple might be shorter * The HeapTupleData portion of the source tuple might be shorter
@ -254,6 +255,7 @@ static HeapTuple
tdeheap_tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot) tdeheap_tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
{ {
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
Assert(!TTS_EMPTY(slot)); Assert(!TTS_EMPTY(slot));
if (!bslot->base.tuple) if (!bslot->base.tuple)
@ -289,7 +291,7 @@ tdeheap_tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
static inline void static inline void
tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
Buffer buffer, bool transfer_pin) Buffer buffer, bool transfer_pin)
{ {
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
@ -355,18 +357,19 @@ tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
*/ */
static pg_attribute_always_inline void static pg_attribute_always_inline void
tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
int natts) int natts)
{ {
TupleDesc tupleDesc = slot->tts_tupleDescriptor; TupleDesc tupleDesc = slot->tts_tupleDescriptor;
Datum *values = slot->tts_values; Datum *values = slot->tts_values;
bool *isnull = slot->tts_isnull; bool *isnull = slot->tts_isnull;
HeapTupleHeader tup = tuple->t_data; HeapTupleHeader tup = tuple->t_data;
bool hasnulls = HeapTupleHasNulls(tuple); bool hasnulls = HeapTupleHasNulls(tuple);
int attnum; int attnum;
char *tp; /* ptr to tuple data */ char *tp; /* ptr to tuple data */
uint32 off; /* offset in tuple data */ uint32 off; /* offset in tuple data */
bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */ bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
bool slow; /* can we use/set attcacheoff? */ bool slow; /* can we use/set attcacheoff? */
/* We can only fetch as many attributes as the tuple has. */ /* We can only fetch as many attributes as the tuple has. */
natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts); natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
@ -453,9 +456,9 @@ tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *of
} }
static HeapTuple static HeapTuple
slot_copytuple(void* buffer, HeapTuple tuple) slot_copytuple(void *buffer, HeapTuple tuple)
{ {
HeapTuple newTuple; HeapTuple newTuple;
if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL) if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
return NULL; return NULL;
@ -465,7 +468,7 @@ slot_copytuple(void* buffer, HeapTuple tuple)
newTuple->t_self = tuple->t_self; newTuple->t_self = tuple->t_self;
newTuple->t_tableOid = tuple->t_tableOid; newTuple->t_tableOid = tuple->t_tableOid;
newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE); newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
// We don't copy the data, it will be copied by the decryption code /* We don't copy the data, it will be copied by the decryption code */
memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_data->t_hoff); memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_data->t_hoff);
return newTuple; return newTuple;
} }
@ -487,7 +490,8 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple = {
/* A buffer heap tuple table slot can not "own" a minimal tuple. */ /* A buffer heap tuple table slot can not "own" a minimal tuple. */
.get_minimal_tuple = NULL, .get_minimal_tuple = NULL,
.copy_heap_tuple = tdeheap_tts_buffer_heap_copy_heap_tuple, .copy_heap_tuple = tdeheap_tts_buffer_heap_copy_heap_tuple,
.copy_minimal_tuple = tdeheap_tts_buffer_heap_copy_minimal_tuple}; .copy_minimal_tuple = tdeheap_tts_buffer_heap_copy_minimal_tuple
};
/* -------------------------------- /* --------------------------------
* ExecStoreBufferHeapTuple * ExecStoreBufferHeapTuple
@ -510,12 +514,13 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple = {
*/ */
TupleTableSlot * TupleTableSlot *
PGTdeExecStoreBufferHeapTuple(Relation rel, PGTdeExecStoreBufferHeapTuple(Relation rel,
HeapTuple tuple, HeapTuple tuple,
TupleTableSlot *slot, TupleTableSlot *slot,
Buffer buffer) Buffer buffer)
{ {
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *)slot; TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
/* /*
* sanity checks * sanity checks
*/ */
@ -535,8 +540,8 @@ PGTdeExecStoreBufferHeapTuple(Relation rel,
Assert(key != NULL); Assert(key != NULL);
slot_copytuple(bslot->decrypted_buffer, tuple); slot_copytuple(bslot->decrypted_buffer, tuple);
PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple)bslot->decrypted_buffer, key, "ExecStoreBuffer"); PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple) bslot->decrypted_buffer, key, "ExecStoreBuffer");
tuple->t_data = ((HeapTuple)bslot->decrypted_buffer)->t_data; tuple->t_data = ((HeapTuple) bslot->decrypted_buffer)->t_data;
} }
tdeheap_tts_buffer_heap_store_tuple(slot, tuple, buffer, false); tdeheap_tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
@ -552,11 +557,12 @@ PGTdeExecStoreBufferHeapTuple(Relation rel,
*/ */
TupleTableSlot * TupleTableSlot *
PGTdeExecStorePinnedBufferHeapTuple(Relation rel, PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
HeapTuple tuple, HeapTuple tuple,
TupleTableSlot *slot, TupleTableSlot *slot,
Buffer buffer) Buffer buffer)
{ {
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *)slot; TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
/* /*
* sanity checks * sanity checks
*/ */
@ -571,12 +577,12 @@ PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
if (rel->rd_rel->relkind != RELKIND_TOASTVALUE) if (rel->rd_rel->relkind != RELKIND_TOASTVALUE)
{ {
RelKeyData *key = get_current_slot_relation_key(bslot,rel); RelKeyData *key = get_current_slot_relation_key(bslot, rel);
slot_copytuple(bslot->decrypted_buffer, tuple); slot_copytuple(bslot->decrypted_buffer, tuple);
PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple)bslot->decrypted_buffer, key, "ExecStorePinnedBuffer"); PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple) bslot->decrypted_buffer, key, "ExecStorePinnedBuffer");
/* TODO: revisit this */ /* TODO: revisit this */
tuple->t_data = ((HeapTuple)bslot->decrypted_buffer)->t_data; tuple->t_data = ((HeapTuple) bslot->decrypted_buffer)->t_data;
} }
tdeheap_tts_buffer_heap_store_tuple(slot, tuple, buffer, true); tdeheap_tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
@ -586,7 +592,7 @@ PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
return slot; return slot;
} }
static inline RelKeyData* static inline RelKeyData *
get_current_slot_relation_key(TDEBufferHeapTupleTableSlot *bslot, Relation rel) get_current_slot_relation_key(TDEBufferHeapTupleTableSlot *bslot, Relation rel)
{ {
Assert(bslot != NULL); Assert(bslot != NULL);

@ -55,14 +55,14 @@
} }
#endif #endif
#define PG_TDE_MAP_FILENAME "pg_tde.map" #define PG_TDE_MAP_FILENAME "pg_tde.map"
#define PG_TDE_KEYDATA_FILENAME "pg_tde.dat" #define PG_TDE_KEYDATA_FILENAME "pg_tde.dat"
#define PG_TDE_FILEMAGIC 0x01454454 /* version ID value = TDE 01 */ #define PG_TDE_FILEMAGIC 0x01454454 /* version ID value = TDE 01 */
#define MAP_ENTRY_SIZE sizeof(TDEMapEntry) #define MAP_ENTRY_SIZE sizeof(TDEMapEntry)
#define TDE_FILE_HEADER_SIZE sizeof(TDEFileHeader) #define TDE_FILE_HEADER_SIZE sizeof(TDEFileHeader)
typedef struct TDEFileHeader typedef struct TDEFileHeader
{ {
@ -90,34 +90,34 @@ typedef struct RelKeyCacheRec
RelKeyData key; RelKeyData key;
} RelKeyCacheRec; } RelKeyCacheRec;
/* /*
* Relation keys cache. * Relation keys cache.
* *
* This is a slice backed by memory `*data`. Initially, we allocate one memory * This is a slice backed by memory `*data`. Initially, we allocate one memory
* page (usually 4Kb). We reallocate it by adding another page when we run out * page (usually 4Kb). We reallocate it by adding another page when we run out
* of space. This memory is locked in the RAM so it won't be paged to the swap * of space. This memory is locked in the RAM so it won't be paged to the swap
* (we don't want decrypted keys on disk). We do allocations in mem pages as * (we don't want decrypted keys on disk). We do allocations in mem pages as
* these are the units `mlock()` operations are performed in. * these are the units `mlock()` operations are performed in.
* *
* Currently, the cache can only grow (no eviction). The data is located in * Currently, the cache can only grow (no eviction). The data is located in
* TopMemoryContext hence being wiped when the process exits, as well as memory * TopMemoryContext hence being wiped when the process exits, as well as memory
* is being unlocked by OS. * is being unlocked by OS.
*/ */
typedef struct RelKeyCache typedef struct RelKeyCache
{ {
RelKeyCacheRec *data; /* must be a multiple of a memory page (usually 4Kb) */ RelKeyCacheRec *data; /* must be a multiple of a memory page (usually 4Kb) */
int len; /* num of RelKeyCacheRecs currenty in cache */ int len; /* num of RelKeyCacheRecs currenty in cache */
int cap; /* max amount of RelKeyCacheRec data can fit */ int cap; /* max amount of RelKeyCacheRec data can fit */
} RelKeyCache; } RelKeyCache;
RelKeyCache *tde_rel_key_cache = NULL; RelKeyCache *tde_rel_key_cache = NULL;
static int32 pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *db_map_path, off_t *offset, bool should_delete); static int32 pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *db_map_path, off_t *offset, bool should_delete);
static RelKeyData* pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key); static RelKeyData *pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key);
static int pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing); static int pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing);
static int pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read); static int pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read);
static bool pg_tde_read_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset); static bool pg_tde_read_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset);
static RelKeyData* pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key); static RelKeyData *pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key);
static int pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *offset); static int pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *offset);
static RelKeyData *pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type); static RelKeyData *pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type);
@ -160,7 +160,7 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator, uint32 entry_type
RelKeyData *enc_rel_key_data; RelKeyData *enc_rel_key_data;
TDEPrincipalKey *principal_key; TDEPrincipalKey *principal_key;
XLogRelKey xlrec; XLogRelKey xlrec;
LWLock *lock_pk = tde_lwlock_enc_keys(); LWLock *lock_pk = tde_lwlock_enc_keys();
LWLockAcquire(lock_pk, LW_EXCLUSIVE); LWLockAcquire(lock_pk, LW_EXCLUSIVE);
principal_key = GetPrincipalKey(newrlocator->dbOid, newrlocator->spcOid, LW_EXCLUSIVE); principal_key = GetPrincipalKey(newrlocator->dbOid, newrlocator->spcOid, LW_EXCLUSIVE);
@ -182,8 +182,8 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator, uint32 entry_type
LWLockRelease(lock_pk); LWLockRelease(lock_pk);
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_INTERNAL_ERROR), (errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not generate internal key for relation \"%s\": %s", errmsg("could not generate internal key for relation \"%s\": %s",
"TODO", ERR_error_string(ERR_get_error(), NULL)))); "TODO", ERR_error_string(ERR_get_error(), NULL))));
return NULL; return NULL;
} }
@ -215,10 +215,10 @@ const char *
tde_sprint_key(InternalKey *k) tde_sprint_key(InternalKey *k)
{ {
static char buf[256]; static char buf[256];
int i; int i;
for (i = 0; i < sizeof(k->key); i++) for (i = 0; i < sizeof(k->key); i++)
sprintf(buf+i, "%02X", k->key[i]); sprintf(buf + i, "%02X", k->key[i]);
return buf; return buf;
} }
@ -230,7 +230,8 @@ tde_sprint_key(InternalKey *k)
RelKeyData * RelKeyData *
tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo *principal_key_info) tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo *principal_key_info)
{ {
RelKeyData rel_key_data; RelKeyData rel_key_data;
memcpy(&rel_key_data.principal_key_id, &principal_key_info->keyId, sizeof(TDEPrincipalKeyId)); memcpy(&rel_key_data.principal_key_id, &principal_key_info->keyId, sizeof(TDEPrincipalKeyId));
memcpy(&rel_key_data.internal_key, key, sizeof(InternalKey)); memcpy(&rel_key_data.internal_key, key, sizeof(InternalKey));
rel_key_data.internal_key.ctx = NULL; rel_key_data.internal_key.ctx = NULL;
@ -238,6 +239,7 @@ tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo
/* Add to the decrypted key to cache */ /* Add to the decrypted key to cache */
return pg_tde_put_key_into_cache(rel_num, &rel_key_data); return pg_tde_put_key_into_cache(rel_num, &rel_key_data);
} }
/* /*
* Encrypts a given key and returns the encrypted one. * Encrypts a given key and returns the encrypted one.
*/ */
@ -287,13 +289,13 @@ pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info)
off_t curr_pos = 0; off_t curr_pos = 0;
bool is_new_map = false; bool is_new_map = false;
bool is_new_key_data = false; bool is_new_key_data = false;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_paths(principal_key_info->databaseId, pg_tde_set_db_file_paths(principal_key_info->databaseId,
principal_key_info->tablespaceId, principal_key_info->tablespaceId,
db_map_path, db_keydata_path); db_map_path, db_keydata_path);
ereport(LOG, (errmsg("pg_tde_save_principal_key"))); ereport(LOG, (errmsg("pg_tde_save_principal_key")));
@ -333,7 +335,7 @@ pg_tde_file_header_write(char *tde_filename, int fd, TDEPrincipalKeyInfo *princi
{ {
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write tde file \"%s\": %m", errmsg("could not write tde file \"%s\": %m",
tde_filename))); tde_filename)));
} }
@ -363,7 +365,7 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
int32 key_index = 0; int32 key_index = 0;
TDEMapEntry map_entry; TDEMapEntry map_entry;
bool is_new_file; bool is_new_file;
off_t curr_pos = 0; off_t curr_pos = 0;
off_t prev_pos = 0; off_t prev_pos = 0;
bool found = false; bool found = false;
@ -373,15 +375,18 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
/* /*
* Read until we find an empty slot. Otherwise, read until end. This seems * Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here rather * to be less frequent than vacuum. So let's keep this function here
* than overloading the vacuum process. * rather than overloading the vacuum process.
*/ */
while(1) while (1)
{ {
prev_pos = curr_pos; prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &map_entry, &curr_pos); found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &map_entry, &curr_pos);
/* We either reach EOF or found an empty slot in the middle of the file */ /*
* We either reach EOF or found an empty slot in the middle of the
* file
*/
if (prev_pos == curr_pos || found) if (prev_pos == curr_pos || found)
break; break;
@ -389,7 +394,10 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
key_index++; key_index++;
} }
/* Write the given entry at the location pointed by prev_pos; i.e. the free entry */ /*
* Write the given entry at the location pointed by prev_pos; i.e. the
* free entry
*/
curr_pos = prev_pos; curr_pos = prev_pos;
pg_tde_write_one_map_entry(map_fd, rlocator, entry_type, key_index, &map_entry, &prev_pos); pg_tde_write_one_map_entry(map_fd, rlocator, entry_type, key_index, &map_entry, &prev_pos);
@ -425,15 +433,17 @@ pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, uint32 flags,
if (bytes_written != MAP_ENTRY_SIZE) if (bytes_written != MAP_ENTRY_SIZE)
{ {
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL); pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL);
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write tde map file \"%s\": %m", errmsg("could not write tde map file \"%s\": %m",
db_map_path))); db_map_path)));
} }
if (pg_fsync(fd) != 0) if (pg_fsync(fd) != 0)
{ {
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL); pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL);
ereport(data_sync_elevel(ERROR), ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(), (errcode_for_file_access(),
@ -487,7 +497,7 @@ pg_tde_write_one_keydata(int fd, int32 key_index, RelKeyData *enc_rel_key_data)
{ {
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write tde key data file: %m"))); errmsg("could not write tde key data file: %m")));
} }
if (pg_fsync(fd) != 0) if (pg_fsync(fd) != 0)
@ -508,9 +518,9 @@ pg_tde_write_one_keydata(int fd, int32 key_index, RelKeyData *enc_rel_key_data)
void void
pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_key_data, TDEPrincipalKeyInfo *principal_key_info) pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_key_data, TDEPrincipalKeyInfo *principal_key_info)
{ {
int32 key_index = 0; int32 key_index = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator); Assert(rlocator);
@ -528,13 +538,14 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_k
* Deletes a map entry by setting marking it as unused. We don't have to delete * Deletes a map entry by setting marking it as unused. We don't have to delete
* the actual key data as valid key data entries are identify by valid map entries. * the actual key data as valid key data entries are identify by valid map entries.
*/ */
void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type) void
pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type)
{ {
int32 key_index = 0; int32 key_index = 0;
off_t offset = 0; off_t offset = 0;
LWLock *lock_files = tde_lwlock_enc_keys(); LWLock *lock_files = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator); Assert(rlocator);
@ -544,14 +555,14 @@ void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type
errno = 0; errno = 0;
/* Remove the map entry if found */ /* Remove the map entry if found */
LWLockAcquire(lock_files, LW_EXCLUSIVE); LWLockAcquire(lock_files, LW_EXCLUSIVE);
key_index = pg_tde_process_map_entry(rlocator, key_type, db_map_path, &offset, false); key_index = pg_tde_process_map_entry(rlocator, key_type, db_map_path, &offset, false);
LWLockRelease(lock_files); LWLockRelease(lock_files);
if (key_index == -1) if (key_index == -1)
{ {
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_NO_DATA_FOUND), (errcode(ERRCODE_NO_DATA_FOUND),
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m", errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
rlocator->relNumber, rlocator->relNumber,
db_map_path))); db_map_path)));
@ -575,7 +586,8 @@ void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type
* *
* A caller should hold an EXCLUSIVE tde_lwlock_enc_keys lock. * A caller should hold an EXCLUSIVE tde_lwlock_enc_keys lock.
*/ */
void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type, off_t offset) void
pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type, off_t offset)
{ {
int32 key_index = 0; int32 key_index = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
@ -593,7 +605,7 @@ void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type,
{ {
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_NO_DATA_FOUND), (errcode(ERRCODE_NO_DATA_FOUND),
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m", errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
rlocator->relNumber, rlocator->relNumber,
db_map_path))); db_map_path)));
@ -621,7 +633,10 @@ void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type,
static File static File
keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos) keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos)
{ {
/* Set the new filenames for the key rotation process - temporary at the moment */ /*
* Set the new filenames for the key rotation process - temporary at the
* moment
*/
snprintf(rotated_filename, MAXPGPATH, "%s.r", filename); snprintf(rotated_filename, MAXPGPATH, "%s.r", filename);
/* Create file, truncate if the rotate file already exits */ /* Create file, truncate if the rotate file already exits */
@ -649,13 +664,13 @@ finalize_key_rotation(char *m_path_old, char *k_path_old, char *m_path_new, char
bool bool
pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_principal_key) pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_principal_key)
{ {
#define OLD_PRINCIPAL_KEY 0 #define OLD_PRINCIPAL_KEY 0
#define NEW_PRINCIPAL_KEY 1 #define NEW_PRINCIPAL_KEY 1
#define PRINCIPAL_KEY_COUNT 2 #define PRINCIPAL_KEY_COUNT 2
off_t curr_pos[PRINCIPAL_KEY_COUNT] = {0}; off_t curr_pos[PRINCIPAL_KEY_COUNT] = {0};
off_t prev_pos[PRINCIPAL_KEY_COUNT] = {0}; off_t prev_pos[PRINCIPAL_KEY_COUNT] = {0};
int32 key_index[PRINCIPAL_KEY_COUNT] = {0}; int32 key_index[PRINCIPAL_KEY_COUNT] = {0};
RelKeyData *rel_key_data[PRINCIPAL_KEY_COUNT]; RelKeyData *rel_key_data[PRINCIPAL_KEY_COUNT];
RelKeyData *enc_rel_key_data[PRINCIPAL_KEY_COUNT]; RelKeyData *enc_rel_key_data[PRINCIPAL_KEY_COUNT];
int m_fd[PRINCIPAL_KEY_COUNT] = {-1}; int m_fd[PRINCIPAL_KEY_COUNT] = {-1};
@ -668,20 +683,26 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
off_t map_size; off_t map_size;
off_t keydata_size; off_t keydata_size;
XLogPrincipalKeyRotate *xlrec; XLogPrincipalKeyRotate *xlrec;
off_t xlrec_size; off_t xlrec_size;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId,
principal_key->keyInfo.tablespaceId, principal_key->keyInfo.tablespaceId,
db_map_path, db_keydata_path); db_map_path, db_keydata_path);
/* Let's update the pathnames in the local variable for ease of use/readability */ /*
* Let's update the pathnames in the local variable for ease of
* use/readability
*/
strncpy(m_path[OLD_PRINCIPAL_KEY], db_map_path, MAXPGPATH); strncpy(m_path[OLD_PRINCIPAL_KEY], db_map_path, MAXPGPATH);
strncpy(k_path[OLD_PRINCIPAL_KEY], db_keydata_path, MAXPGPATH); strncpy(k_path[OLD_PRINCIPAL_KEY], db_keydata_path, MAXPGPATH);
/* Open both files in read only mode. We don't need to track the current position of the keydata file. We always use the key index */ /*
* Open both files in read only mode. We don't need to track the current
* position of the keydata file. We always use the key index
*/
m_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(m_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_PRINCIPAL_KEY]); m_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(m_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_PRINCIPAL_KEY]);
k_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(k_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp); k_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(k_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp);
@ -689,9 +710,10 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
k_fd[NEW_PRINCIPAL_KEY] = keyrotation_init_file(&new_principal_key->keyInfo, k_path[NEW_PRINCIPAL_KEY], k_path[OLD_PRINCIPAL_KEY], &is_new_file, &read_pos_tmp); k_fd[NEW_PRINCIPAL_KEY] = keyrotation_init_file(&new_principal_key->keyInfo, k_path[NEW_PRINCIPAL_KEY], k_path[OLD_PRINCIPAL_KEY], &is_new_file, &read_pos_tmp);
/* Read all entries until EOF */ /* Read all entries until EOF */
for(key_index[OLD_PRINCIPAL_KEY] = 0; ; key_index[OLD_PRINCIPAL_KEY]++) for (key_index[OLD_PRINCIPAL_KEY] = 0;; key_index[OLD_PRINCIPAL_KEY]++)
{ {
TDEMapEntry read_map_entry, write_map_entry; TDEMapEntry read_map_entry,
write_map_entry;
RelFileLocator rloc; RelFileLocator rloc;
prev_pos[OLD_PRINCIPAL_KEY] = curr_pos[OLD_PRINCIPAL_KEY]; prev_pos[OLD_PRINCIPAL_KEY] = curr_pos[OLD_PRINCIPAL_KEY];
@ -705,14 +727,17 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
if (found == false) if (found == false)
continue; continue;
/* Set the relNumber of rlocator. Ignore the tablespace Oid since we only place our files under the default. */ /*
* Set the relNumber of rlocator. Ignore the tablespace Oid since we
* only place our files under the default.
*/
rloc.relNumber = read_map_entry.relNumber; rloc.relNumber = read_map_entry.relNumber;
rloc.dbOid = principal_key->keyInfo.databaseId; rloc.dbOid = principal_key->keyInfo.databaseId;
rloc.spcOid = DEFAULTTABLESPACE_OID; /* TODO. Revisit*/ rloc.spcOid = DEFAULTTABLESPACE_OID; /* TODO. Revisit */
/* Let's get the decrypted key and re-encrypt it with the new key. */ /* Let's get the decrypted key and re-encrypt it with the new key. */
enc_rel_key_data[OLD_PRINCIPAL_KEY] = pg_tde_read_one_keydata(k_fd[OLD_PRINCIPAL_KEY], key_index[OLD_PRINCIPAL_KEY], principal_key); enc_rel_key_data[OLD_PRINCIPAL_KEY] = pg_tde_read_one_keydata(k_fd[OLD_PRINCIPAL_KEY], key_index[OLD_PRINCIPAL_KEY], principal_key);
/* Decrypt and re-encrypt keys */ /* Decrypt and re-encrypt keys */
rel_key_data[OLD_PRINCIPAL_KEY] = tde_decrypt_rel_key(principal_key, enc_rel_key_data[OLD_PRINCIPAL_KEY], &rloc); rel_key_data[OLD_PRINCIPAL_KEY] = tde_decrypt_rel_key(principal_key, enc_rel_key_data[OLD_PRINCIPAL_KEY], &rloc);
enc_rel_key_data[NEW_PRINCIPAL_KEY] = tde_encrypt_rel_key(new_principal_key, rel_key_data[OLD_PRINCIPAL_KEY], &rloc); enc_rel_key_data[NEW_PRINCIPAL_KEY] = tde_encrypt_rel_key(new_principal_key, rel_key_data[OLD_PRINCIPAL_KEY], &rloc);
@ -777,24 +802,24 @@ bool
pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_size, char *k_file_data) pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_size, char *k_file_data)
{ {
TDEFileHeader *fheader; TDEFileHeader *fheader;
char m_path_new[MAXPGPATH]; char m_path_new[MAXPGPATH];
char k_path_new[MAXPGPATH]; char k_path_new[MAXPGPATH];
int m_fd_new; int m_fd_new;
int k_fd_new; int k_fd_new;
bool is_new_file; bool is_new_file;
off_t curr_pos = 0; off_t curr_pos = 0;
off_t read_pos_tmp = 0; off_t read_pos_tmp = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
bool is_err = false; bool is_err = false;
/* Let's get the header. Buff should start with the map file header. */ /* Let's get the header. Buff should start with the map file header. */
fheader = (TDEFileHeader *) m_file_data; fheader = (TDEFileHeader *) m_file_data;
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_paths(fheader->principal_key_info.databaseId, pg_tde_set_db_file_paths(fheader->principal_key_info.databaseId,
fheader->principal_key_info.tablespaceId, fheader->principal_key_info.tablespaceId,
db_map_path, db_keydata_path); db_map_path, db_keydata_path);
/* Initialize the new files and set the names */ /* Initialize the new files and set the names */
m_fd_new = keyrotation_init_file(&fheader->principal_key_info, m_path_new, db_map_path, &is_new_file, &curr_pos); m_fd_new = keyrotation_init_file(&fheader->principal_key_info, m_path_new, db_map_path, &is_new_file, &curr_pos);
@ -805,7 +830,7 @@ pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_
{ {
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write tde file \"%s\": %m", errmsg("could not write tde file \"%s\": %m",
m_path_new))); m_path_new)));
is_err = true; is_err = true;
goto FINALIZE; goto FINALIZE;
@ -824,7 +849,7 @@ pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_
{ {
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write tde file \"%s\": %m", errmsg("could not write tde file \"%s\": %m",
k_path_new))); k_path_new)));
is_err = true; is_err = true;
goto FINALIZE; goto FINALIZE;
@ -938,29 +963,28 @@ pg_tde_move_rel_key(const RelFileLocator *newrlocator, const RelFileLocator *old
RelKeyData * RelKeyData *
pg_tde_get_key_from_file(const RelFileLocator *rlocator, uint32 key_type, bool no_map_ok) pg_tde_get_key_from_file(const RelFileLocator *rlocator, uint32 key_type, bool no_map_ok)
{ {
int32 key_index = 0; int32 key_index = 0;
TDEPrincipalKey *principal_key; TDEPrincipalKey *principal_key;
RelKeyData *rel_key_data; RelKeyData *rel_key_data;
RelKeyData *enc_rel_key_data; RelKeyData *enc_rel_key_data;
off_t offset = 0; off_t offset = 0;
LWLock *lock_pk = tde_lwlock_enc_keys(); LWLock *lock_pk = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator); Assert(rlocator);
/* /*
* Get/generate a principal key, create the key for relation and get the * Get/generate a principal key, create the key for relation and get the
* encrypted key with bytes to write * encrypted key with bytes to write
* *
* We should hold the lock until the internal key is loaded to be sure the * We should hold the lock until the internal key is loaded to be sure the
* retrieved key was encrypted with the obtained principal key. Otherwise, * retrieved key was encrypted with the obtained principal key. Otherwise,
* the next may happen: * the next may happen: - GetPrincipalKey returns key "PKey_1". - Some
* - GetPrincipalKey returns key "PKey_1". * other process rotates the Principal key and re-encrypt an Internal key
* - Some other process rotates the Principal key and re-encrypt an * with "PKey_2". - We read the Internal key and decrypt it with "PKey_1"
* Internal key with "PKey_2". * (that's what we've got). As the result we return an invalid Internal
* - We read the Internal key and decrypt it with "PKey_1" (that's what * key.
* we've got). As the result we return an invalid Internal key.
*/ */
LWLockAcquire(lock_pk, LW_SHARED); LWLockAcquire(lock_pk, LW_SHARED);
principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid, LW_SHARED); principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid, LW_SHARED);
@ -1031,8 +1055,8 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
Assert(offset); Assert(offset);
/* /*
* Open and validate file for basic correctness. DO NOT create it. * Open and validate file for basic correctness. DO NOT create it. The
* The file should pre-exist otherwise we should never be here. * file should pre-exist otherwise we should never be here.
*/ */
map_fd = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos); map_fd = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos);
@ -1049,8 +1073,8 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
{ {
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not seek in tde map file \"%s\": %m", errmsg("could not seek in tde map file \"%s\": %m",
db_map_path))); db_map_path)));
} }
} }
else else
@ -1061,10 +1085,10 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
/* /*
* Read until we find an empty slot. Otherwise, read until end. This seems * Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here rather * to be less frequent than vacuum. So let's keep this function here
* than overloading the vacuum process. * rather than overloading the vacuum process.
*/ */
while(1) while (1)
{ {
prev_pos = curr_pos; prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_fd, rlocator, key_type, &map_entry, &curr_pos); found = pg_tde_read_one_map_entry(map_fd, rlocator, key_type, &map_entry, &curr_pos);
@ -1175,7 +1199,7 @@ pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bo
/* In case it's a new file, let's add the header now. */ /* In case it's a new file, let's add the header now. */
if (*is_new_file && principal_key_info) if (*is_new_file && principal_key_info)
pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written); pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written);
#endif /* FRONTEND */ #endif /* FRONTEND */
*curr_pos = bytes_read + bytes_written; *curr_pos = bytes_read + bytes_written;
return fd; return fd;
@ -1227,13 +1251,13 @@ pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool
return fd; return fd;
if (*bytes_read != TDE_FILE_HEADER_SIZE if (*bytes_read != TDE_FILE_HEADER_SIZE
|| fheader->file_version != PG_TDE_FILEMAGIC) || fheader->file_version != PG_TDE_FILEMAGIC)
{ {
/* Corrupt file */ /* Corrupt file */
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("TDE map file \"%s\" is corrupted: %m", errmsg("TDE map file \"%s\" is corrupted: %m",
tde_filename))); tde_filename)));
} }
return fd; return fd;
@ -1300,10 +1324,11 @@ pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *princi
if ((read_pos + INTERNAL_KEY_DAT_LEN) > lseek(keydata_fd, 0, SEEK_END)) if ((read_pos + INTERNAL_KEY_DAT_LEN) > lseek(keydata_fd, 0, SEEK_END))
{ {
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_NO_DATA_FOUND), (errcode(ERRCODE_NO_DATA_FOUND),
errmsg("could not find the required key at index %d in tde data file \"%s\": %m", errmsg("could not find the required key at index %d in tde data file \"%s\": %m",
key_index, key_index,
db_keydata_path))); db_keydata_path)));
} }
@ -1312,11 +1337,12 @@ pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *princi
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */ /* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pread(keydata_fd, &(enc_rel_key_data->internal_key), INTERNAL_KEY_DAT_LEN, read_pos) != INTERNAL_KEY_DAT_LEN) if (pg_pread(keydata_fd, &(enc_rel_key_data->internal_key), INTERNAL_KEY_DAT_LEN, read_pos) != INTERNAL_KEY_DAT_LEN)
{ {
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path); pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read key at index %d in tde key data file \"%s\": %m", errmsg("could not read key at index %d in tde key data file \"%s\": %m",
key_index, key_index,
db_keydata_path))); db_keydata_path)));
} }
@ -1337,7 +1363,7 @@ pg_tde_get_principal_key_info(Oid dbOid, Oid spcOid)
TDEPrincipalKeyInfo *principal_key_info = NULL; TDEPrincipalKeyInfo *principal_key_info = NULL;
bool is_new_file = false; bool is_new_file = false;
off_t bytes_read = 0; off_t bytes_read = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_paths(dbOid, spcOid, db_map_path, NULL); pg_tde_set_db_file_paths(dbOid, spcOid, db_map_path, NULL);
@ -1356,7 +1382,10 @@ pg_tde_get_principal_key_info(Oid dbOid, Oid spcOid)
close(fd); close(fd);
/* It's not a new file. So we can memcpy the principal key info from the header */ /*
* It's not a new file. So we can memcpy the principal key info from the
* header
*/
if (!is_new_file) if (!is_new_file)
{ {
size_t sz = sizeof(TDEPrincipalKeyInfo); size_t sz = sizeof(TDEPrincipalKeyInfo);
@ -1420,14 +1449,14 @@ GetTdeGlobaleRelationKey(RelFileLocator rel)
static RelKeyData * static RelKeyData *
pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type) pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type)
{ {
RelKeyCacheRec *rec; RelKeyCacheRec *rec;
if (tde_rel_key_cache == NULL) if (tde_rel_key_cache == NULL)
return NULL; return NULL;
for (int i = 0; i < tde_rel_key_cache->len; i++) for (int i = 0; i < tde_rel_key_cache->len; i++)
{ {
rec = tde_rel_key_cache->data+i; rec = tde_rel_key_cache->data + i;
if (rec != NULL && if (rec != NULL &&
(rel_number == InvalidOid || (rec->rel_number == rel_number)) && (rel_number == InvalidOid || (rec->rel_number == rel_number)) &&
rec->key.internal_key.rel_type & key_type) rec->key.internal_key.rel_type & key_type)
@ -1440,23 +1469,23 @@ pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type)
} }
/* Add key to cache. See comments on `RelKeyCache`. /* Add key to cache. See comments on `RelKeyCache`.
* *
* TODO: add tests. * TODO: add tests.
*/ */
RelKeyData * RelKeyData *
pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key) pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
{ {
static long pageSize = 0; static long pageSize = 0;
RelKeyCacheRec *rec; RelKeyCacheRec *rec;
MemoryContext oldCtx; MemoryContext oldCtx;
if (pageSize == 0) if (pageSize == 0)
{ {
#ifndef _SC_PAGESIZE #ifndef _SC_PAGESIZE
pageSize = getpagesize(); pageSize = getpagesize();
#else #else
pageSize = sysconf(_SC_PAGESIZE); pageSize = sysconf(_SC_PAGESIZE);
#endif #endif
} }
if (tde_rel_key_cache == NULL) if (tde_rel_key_cache == NULL)
@ -1479,17 +1508,18 @@ pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
tde_rel_key_cache->cap = pageSize / sizeof(RelKeyCacheRec); tde_rel_key_cache->cap = pageSize / sizeof(RelKeyCacheRec);
} }
/* Add another mem page if there is no more room left for another key. We /*
* Add another mem page if there is no more room left for another key. We
* allocate `current_memory_size` + 1 page and copy data there. * allocate `current_memory_size` + 1 page and copy data there.
*/ */
if (tde_rel_key_cache->len+1 > if (tde_rel_key_cache->len + 1 >
(tde_rel_key_cache->cap * sizeof(RelKeyCacheRec)) / sizeof(RelKeyCacheRec)) (tde_rel_key_cache->cap * sizeof(RelKeyCacheRec)) / sizeof(RelKeyCacheRec))
{ {
size_t size; size_t size;
size_t old_size; size_t old_size;
RelKeyCacheRec *chachePage; RelKeyCacheRec *chachePage;
size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap+1) * sizeof(RelKeyCacheRec)); size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap + 1) * sizeof(RelKeyCacheRec));
old_size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap) * sizeof(RelKeyCacheRec)); old_size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap) * sizeof(RelKeyCacheRec));
#ifndef FRONTEND #ifndef FRONTEND
@ -1518,4 +1548,4 @@ pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
tde_rel_key_cache->len++; tde_rel_key_cache->len++;
return &rec->key; return &rec->key;
} }

@ -33,7 +33,7 @@
void void
tdeheap_rmgr_redo(XLogReaderState *record) tdeheap_rmgr_redo(XLogReaderState *record)
{ {
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
if (info == XLOG_TDE_ADD_RELATION_KEY) if (info == XLOG_TDE_ADD_RELATION_KEY)
{ {
@ -57,14 +57,15 @@ tdeheap_rmgr_redo(XLogReaderState *record)
} }
else if (info == XLOG_TDE_EXTENSION_INSTALL_KEY) else if (info == XLOG_TDE_EXTENSION_INSTALL_KEY)
{ {
XLogExtensionInstall *xlrec = (XLogExtensionInstall *)XLogRecGetData(record); XLogExtensionInstall *xlrec = (XLogExtensionInstall *) XLogRecGetData(record);
extension_install_redo(xlrec); extension_install_redo(xlrec);
} }
else if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY) else if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY)
{ {
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *)XLogRecGetData(record); KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *) XLogRecGetData(record);
redo_key_provider_info(xlrec); redo_key_provider_info(xlrec);
} }
@ -95,7 +96,7 @@ tdeheap_rmgr_redo(XLogReaderState *record)
void void
tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record) tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
{ {
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
if (info == XLOG_TDE_ADD_RELATION_KEY) if (info == XLOG_TDE_ADD_RELATION_KEY)
{ {
@ -111,7 +112,7 @@ tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
} }
if (info == XLOG_TDE_EXTENSION_INSTALL_KEY) if (info == XLOG_TDE_EXTENSION_INSTALL_KEY)
{ {
XLogExtensionInstall *xlrec = (XLogExtensionInstall *)XLogRecGetData(record); XLogExtensionInstall *xlrec = (XLogExtensionInstall *) XLogRecGetData(record);
appendStringInfo(buf, "tde extension install for db %u/%u", xlrec->database_id, xlrec->tablespace_id); appendStringInfo(buf, "tde extension install for db %u/%u", xlrec->database_id, xlrec->tablespace_id);
} }
@ -123,7 +124,7 @@ tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
} }
if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY) if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY)
{ {
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *)XLogRecGetData(record); KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *) XLogRecGetData(record);
appendStringInfo(buf, "add key provider %s for %u", xlrec->provider.provider_name, xlrec->database_id); appendStringInfo(buf, "add key provider %s for %u", xlrec->provider.provider_name, xlrec->database_id);
} }

@ -34,7 +34,7 @@
static XLogPageHeaderData DecryptCurrentPageHrd; static XLogPageHeaderData DecryptCurrentPageHrd;
static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix); static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char *iv_prefix);
#ifndef FRONTEND #ifndef FRONTEND
/* GUC */ /* GUC */
@ -52,8 +52,8 @@ XLogInitGUC(void)
DefineCustomBoolVariable("pg_tde.wal_encrypt", /* name */ DefineCustomBoolVariable("pg_tde.wal_encrypt", /* name */
"Enable/Disable encryption of WAL.", /* short_desc */ "Enable/Disable encryption of WAL.", /* short_desc */
NULL, /* long_desc */ NULL, /* long_desc */
&EncryptXLog, /* value address */ &EncryptXLog, /* value address */
false, /* boot value */ false, /* boot value */
PGC_POSTMASTER, /* context */ PGC_POSTMASTER, /* context */
0, /* flags */ 0, /* flags */
NULL, /* check_hook */ NULL, /* check_hook */
@ -65,7 +65,7 @@ XLogInitGUC(void)
static int static int
XLOGChooseNumBuffers(void) XLOGChooseNumBuffers(void)
{ {
int xbuffers; int xbuffers;
xbuffers = NBuffers / 32; xbuffers = NBuffers / 32;
if (xbuffers > (wal_segment_size / XLOG_BLCKSZ)) if (xbuffers > (wal_segment_size / XLOG_BLCKSZ))
@ -75,72 +75,72 @@ XLOGChooseNumBuffers(void)
return xbuffers; return xbuffers;
} }
/* /*
* Defines the size of the XLog encryption buffer * Defines the size of the XLog encryption buffer
*/ */
Size Size
TDEXLogEncryptBuffSize(void) TDEXLogEncryptBuffSize(void)
{ {
int xbuffers; int xbuffers;
xbuffers = (XLOGbuffers == -1) ? XLOGChooseNumBuffers() : XLOGbuffers; xbuffers = (XLOGbuffers == -1) ? XLOGChooseNumBuffers() : XLOGbuffers;
return (Size) XLOG_BLCKSZ * xbuffers; return (Size) XLOG_BLCKSZ * xbuffers;
} }
/* /*
* Alloc memory for the encryption buffer. * Alloc memory for the encryption buffer.
* *
* It should fit XLog buffers (XLOG_BLCKSZ * wal_buffers). We can't * It should fit XLog buffers (XLOG_BLCKSZ * wal_buffers). We can't
* (re)alloc this buf in tdeheap_xlog_seg_write() based on the write size as * (re)alloc this buf in tdeheap_xlog_seg_write() based on the write size as
* it's called in the CRIT section, hence no allocations are allowed. * it's called in the CRIT section, hence no allocations are allowed.
* *
* Access to this buffer happens during XLogWrite() call which should * Access to this buffer happens during XLogWrite() call which should
* be called with WALWriteLock held, hence no need in extra locks. * be called with WALWriteLock held, hence no need in extra locks.
*/ */
void void
TDEXLogShmemInit(void) TDEXLogShmemInit(void)
{ {
bool foundBuf; bool foundBuf;
if (EncryptXLog) if (EncryptXLog)
{ {
TDEXLogEncryptBuf = (char *) TDEXLogEncryptBuf = (char *)
TYPEALIGN(PG_IO_ALIGN_SIZE, TYPEALIGN(PG_IO_ALIGN_SIZE,
ShmemInitStruct("TDE XLog Encryption Buffer", ShmemInitStruct("TDE XLog Encryption Buffer",
XLOG_TDE_ENC_BUFF_ALIGNED_SIZE, XLOG_TDE_ENC_BUFF_ALIGNED_SIZE,
&foundBuf)); &foundBuf));
elog(DEBUG1, "pg_tde: initialized encryption buffer %lu bytes", XLOG_TDE_ENC_BUFF_ALIGNED_SIZE); elog(DEBUG1, "pg_tde: initialized encryption buffer %lu bytes", XLOG_TDE_ENC_BUFF_ALIGNED_SIZE);
} }
} }
/* /*
* Encrypt XLog page(s) from the buf and write to the segment file. * Encrypt XLog page(s) from the buf and write to the segment file.
*/ */
static ssize_t static ssize_t
TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset) TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
{ {
char iv_prefix[16] = {0,}; char iv_prefix[16] = {0,};
size_t data_size = 0; size_t data_size = 0;
XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd; XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd;
XLogPageHeader enc_buf_page; XLogPageHeader enc_buf_page;
RelKeyData *key = GetTdeGlobaleRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); RelKeyData *key = GetTdeGlobaleRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID));
off_t enc_off; off_t enc_off;
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ; size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
uint32 iv_ctr = 0; uint32 iv_ctr = 0;
#ifdef TDE_XLOG_DEBUG #ifdef TDE_XLOG_DEBUG
elog(DEBUG1, "write encrypted WAL, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset); elog(DEBUG1, "write encrypted WAL, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset);
#endif #endif
/* /*
* Go through the buf page-by-page and encrypt them. * Go through the buf page-by-page and encrypt them. We may start or
* We may start or finish writing from/in the middle of the page * finish writing from/in the middle of the page (walsender or
* (walsender or `full_page_writes = off`). So preserve a page header * `full_page_writes = off`). So preserve a page header for the IV init
* for the IV init data. * data.
* *
* TODO: check if walsender restarts form the beggining of the page * TODO: check if walsender restarts form the beggining of the page in
* in case of the crash. * case of the crash.
*/ */
for (enc_off = 0; enc_off < count;) for (enc_off = 0; enc_off < count;)
{ {
@ -150,9 +150,10 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
{ {
memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD); memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD);
/* /*
* Need to use a separate buf for the encryption so the page remains non-crypted * Need to use a separate buf for the encryption so the page
* in the XLog buf (XLogInsert has to have access to records' lsn). * remains non-crypted in the XLog buf (XLogInsert has to have
* access to records' lsn).
*/ */
enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off); enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off);
memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr)); memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr));
@ -163,35 +164,35 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
/* it's a beginning of the page */ /* it's a beginning of the page */
iv_ctr = 0; iv_ctr = 0;
} }
else else
{ {
/* we're in the middle of the page */ /* we're in the middle of the page */
iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr); iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr);
} }
if (data_size + enc_off > count) if (data_size + enc_off > count)
{ {
data_size = count - enc_off; data_size = count - enc_off;
} }
/* /*
* The page is zeroed (no data), no sense to enctypt. * The page is zeroed (no data), no sense to enctypt. This may happen
* This may happen when base_backup or other requests XLOG SWITCH and * when base_backup or other requests XLOG SWITCH and some pages in
* some pages in XLog buffer still not used. * XLog buffer still not used.
*/ */
if (curr_page_hdr->xlp_magic == 0) if (curr_page_hdr->xlp_magic == 0)
{ {
/* ensure all the page is {0} */ /* ensure all the page is {0} */
Assert((*((char *) buf + enc_off) == 0) && Assert((*((char *) buf + enc_off) == 0) &&
memcmp((char *) buf + enc_off, (char *) buf + enc_off + 1, data_size - 1) == 0); memcmp((char *) buf + enc_off, (char *) buf + enc_off + 1, data_size - 1) == 0);
memcpy((char *) enc_buf_page, (char *) buf + enc_off, data_size); memcpy((char *) enc_buf_page, (char *) buf + enc_off, data_size);
} }
else else
{ {
SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix); SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix);
PG_TDE_ENCRYPT_DATA(iv_prefix, iv_ctr, (char *) buf + enc_off, data_size, PG_TDE_ENCRYPT_DATA(iv_prefix, iv_ctr, (char *) buf + enc_off, data_size,
TDEXLogEncryptBuf + enc_off, key); TDEXLogEncryptBuf + enc_off, key);
} }
page_size = XLOG_BLCKSZ; page_size = XLOG_BLCKSZ;
@ -200,7 +201,7 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
return pg_pwrite(fd, TDEXLogEncryptBuf, count, offset); return pg_pwrite(fd, TDEXLogEncryptBuf, count, offset);
} }
#endif /* !FRONTEND */ #endif /* !FRONTEND */
void void
TDEXLogSmgrInit(void) TDEXLogSmgrInit(void)
@ -219,20 +220,20 @@ tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset)
return pg_pwrite(fd, buf, count, offset); return pg_pwrite(fd, buf, count, offset);
} }
/* /*
* Read the XLog pages from the segment file and dectypt if need. * Read the XLog pages from the segment file and dectypt if need.
*/ */
ssize_t ssize_t
tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset) tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
{ {
ssize_t readsz; ssize_t readsz;
char iv_prefix[16] = {0,}; char iv_prefix[16] = {0,};
size_t data_size = 0; size_t data_size = 0;
XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd; XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd;
RelKeyData *key = GetTdeGlobaleRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); RelKeyData *key = GetTdeGlobaleRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID));
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ; size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
off_t dec_off; off_t dec_off;
uint32 iv_ctr = 0; uint32 iv_ctr = 0;
#ifdef TDE_XLOG_DEBUG #ifdef TDE_XLOG_DEBUG
elog(DEBUG1, "read from a WAL segment, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset); elog(DEBUG1, "read from a WAL segment, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset);
@ -240,14 +241,14 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
readsz = pg_pread(fd, buf, count, offset); readsz = pg_pread(fd, buf, count, offset);
/* /*
* Read the buf page by page and decypt ecnrypted pages. * Read the buf page by page and decypt ecnrypted pages. We may start or
* We may start or fihish reading from/in the middle of the page (walreceiver) * fihish reading from/in the middle of the page (walreceiver) in such a
* in such a case we should preserve the last read page header for * case we should preserve the last read page header for the IV data and
* the IV data and the encryption state. * the encryption state.
* *
* TODO: check if walsender/receiver restarts form the beggining of the page * TODO: check if walsender/receiver restarts form the beggining of the
* in case of the crash. * page in case of the crash.
*/ */
for (dec_off = 0; dec_off < readsz;) for (dec_off = 0; dec_off < readsz;)
{ {
@ -266,13 +267,13 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
/* it's a beginning of the page */ /* it's a beginning of the page */
iv_ctr = 0; iv_ctr = 0;
} }
else else
{ {
/* we're in the middle of the page */ /* we're in the middle of the page */
iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr); iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr);
} }
if ((data_size + dec_off) > readsz) if ((data_size + dec_off) > readsz)
{ {
data_size = readsz - dec_off; data_size = readsz - dec_off;
} }
@ -281,10 +282,10 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
{ {
SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix); SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix);
PG_TDE_DECRYPT_DATA( PG_TDE_DECRYPT_DATA(
iv_prefix, iv_ctr, iv_prefix, iv_ctr,
(char *) buf + dec_off, data_size, (char *) buf + dec_off, key); (char *) buf + dec_off, data_size, (char *) buf + dec_off, key);
} }
page_size = XLOG_BLCKSZ; page_size = XLOG_BLCKSZ;
dec_off += data_size; dec_off += data_size;
} }
@ -294,7 +295,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
/* IV: TLI(uint32) + XLogRecPtr(uint64)*/ /* IV: TLI(uint32) + XLogRecPtr(uint64)*/
static void static void
SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix) SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char *iv_prefix)
{ {
iv_prefix[0] = (tli >> 24); iv_prefix[0] = (tli >> 24);
iv_prefix[1] = ((tli >> 16) & 0xFF); iv_prefix[1] = ((tli >> 16) & 0xFF);
@ -311,4 +312,4 @@ SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix)
iv_prefix[11] = (lsn & 0xFF); iv_prefix[11] = (lsn & 0xFF);
} }
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */

@ -41,19 +41,19 @@
#ifndef FRONTEND #ifndef FRONTEND
static void init_keys(void); static void init_keys(void);
static void init_default_keyring(void); static void init_default_keyring(void);
static TDEPrincipalKey * create_principal_key(const char *key_name, static TDEPrincipalKey *create_principal_key(const char *key_name,
GenericKeyring * keyring, Oid dbOid, GenericKeyring *keyring, Oid dbOid,
Oid spcOid); Oid spcOid);
#endif /* !FRONTEND */ #endif /* !FRONTEND */
void void
TDEInitGlobalKeys(const char *dir) TDEInitGlobalKeys(const char *dir)
{ {
#ifndef FRONTEND #ifndef FRONTEND
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID, db_map_path, NULL); pg_tde_set_db_file_paths(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID, db_map_path, NULL);
if (access(db_map_path, F_OK) == -1) if (access(db_map_path, F_OK) == -1)
{ {
init_default_keyring(); init_default_keyring();
@ -89,23 +89,23 @@ init_default_keyring(void)
{ {
if (GetAllKeyringProviders(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) == NIL) if (GetAllKeyringProviders(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) == NIL)
{ {
char path[MAXPGPATH] = {0}; char path[MAXPGPATH] = {0};
static KeyringProvideRecord provider = static KeyringProvideRecord provider =
{ {
.provider_name = KEYRING_DEFAULT_NAME, .provider_name = KEYRING_DEFAULT_NAME,
.provider_type = FILE_KEY_PROVIDER, .provider_type = FILE_KEY_PROVIDER,
}; };
if (getcwd(path, sizeof(path)) == NULL) if (getcwd(path, sizeof(path)) == NULL)
elog(WARNING, "unable to get current working dir"); elog(WARNING, "unable to get current working dir");
/* TODO: not sure about the location. Currently it's in $PGDATA */ /* TODO: not sure about the location. Currently it's in $PGDATA */
join_path_components(path, path, KEYRING_DEFAULT_FILE_NAME); join_path_components(path, path, KEYRING_DEFAULT_FILE_NAME);
snprintf(provider.options, MAX_KEYRING_OPTION_LEN, snprintf(provider.options, MAX_KEYRING_OPTION_LEN,
"{" "{"
"\"type\": \"file\"," "\"type\": \"file\","
"\"path\": \"%s\"" "\"path\": \"%s\""
"}", path "}", path
); );
@ -175,11 +175,11 @@ init_keys(void)
* first. * first.
*/ */
static TDEPrincipalKey * static TDEPrincipalKey *
create_principal_key(const char *key_name, GenericKeyring * keyring, create_principal_key(const char *key_name, GenericKeyring *keyring,
Oid dbOid, Oid spcOid) Oid dbOid, Oid spcOid)
{ {
TDEPrincipalKey *principalKey; TDEPrincipalKey *principalKey;
keyInfo *keyInfo = NULL; keyInfo *keyInfo = NULL;
principalKey = palloc(sizeof(TDEPrincipalKey)); principalKey = palloc(sizeof(TDEPrincipalKey));
principalKey->keyInfo.databaseId = dbOid; principalKey->keyInfo.databaseId = dbOid;
@ -200,10 +200,11 @@ create_principal_key(const char *key_name, GenericKeyring * keyring,
} }
principalKey->keyLength = keyInfo->data.len; principalKey->keyLength = keyInfo->data.len;
memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len); memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len);
return principalKey; return principalKey;
} }
#endif /* FRONTEND */ #endif /* FRONTEND */
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */

@ -37,7 +37,7 @@
#else #else
#include "fe_utils/simple_list.h" #include "fe_utils/simple_list.h"
#include "pg_tde_fe.h" #include "pg_tde_fe.h"
#endif /* !FRONTEND */ #endif /* !FRONTEND */
typedef enum ProviderScanType typedef enum ProviderScanType
{ {
@ -55,7 +55,7 @@ static VaultV2Keyring *load_vaultV2_keyring_provider_options(char *keyring_optio
static void debug_print_kerying(GenericKeyring *keyring); static void debug_print_kerying(GenericKeyring *keyring);
static GenericKeyring *load_keyring_provider_from_record(KeyringProvideRecord *provider); static GenericKeyring *load_keyring_provider_from_record(KeyringProvideRecord *provider);
static char *get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid); static char *get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid);
static bool fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider); static bool fetch_next_key_provider(int fd, off_t *curr_pos, KeyringProvideRecord *provider);
#ifdef FRONTEND #ifdef FRONTEND
@ -89,14 +89,14 @@ typedef struct TdeKeyProviderInfoSharedState
LWLockPadded *Locks; LWLockPadded *Locks;
} TdeKeyProviderInfoSharedState; } TdeKeyProviderInfoSharedState;
TdeKeyProviderInfoSharedState* sharedPrincipalKeyState = NULL; /* Lives in shared state */ TdeKeyProviderInfoSharedState *sharedPrincipalKeyState = NULL; /* Lives in shared state */
static const TDEShmemSetupRoutine key_provider_info_shmem_routine = { static const TDEShmemSetupRoutine key_provider_info_shmem_routine = {
.init_shared_state = initialize_shared_state, .init_shared_state = initialize_shared_state,
.init_dsa_area_objects = NULL, .init_dsa_area_objects = NULL,
.required_shared_mem_size = required_shared_mem_size, .required_shared_mem_size = required_shared_mem_size,
.shmem_kill = NULL .shmem_kill = NULL
}; };
static Size static Size
required_shared_mem_size(void) required_shared_mem_size(void)
@ -107,7 +107,7 @@ required_shared_mem_size(void)
static Size static Size
initialize_shared_state(void *start_address) initialize_shared_state(void *start_address)
{ {
sharedPrincipalKeyState = (TdeKeyProviderInfoSharedState *)start_address; sharedPrincipalKeyState = (TdeKeyProviderInfoSharedState *) start_address;
sharedPrincipalKeyState->Locks = GetNamedLWLockTranche(TDE_TRANCHE_NAME); sharedPrincipalKeyState->Locks = GetNamedLWLockTranche(TDE_TRANCHE_NAME);
return sizeof(TdeKeyProviderInfoSharedState); return sizeof(TdeKeyProviderInfoSharedState);
@ -120,7 +120,8 @@ tde_provider_info_lock(void)
return &sharedPrincipalKeyState->Locks[TDE_LWLOCK_PI_FILES].lock; return &sharedPrincipalKeyState->Locks[TDE_LWLOCK_PI_FILES].lock;
} }
void InitializeKeyProviderInfo(void) void
InitializeKeyProviderInfo(void)
{ {
ereport(LOG, (errmsg("initializing TDE key provider info"))); ereport(LOG, (errmsg("initializing TDE key provider info")));
RegisterShmemRequest(&key_provider_info_shmem_routine); RegisterShmemRequest(&key_provider_info_shmem_routine);
@ -157,12 +158,12 @@ get_keyring_provider_typename(ProviderType p_type)
{ {
switch (p_type) switch (p_type)
{ {
case FILE_KEY_PROVIDER: case FILE_KEY_PROVIDER:
return FILE_KEYRING_TYPE; return FILE_KEYRING_TYPE;
case VAULT_V2_KEY_PROVIDER: case VAULT_V2_KEY_PROVIDER:
return VAULTV2_KEYRING_TYPE; return VAULTV2_KEYRING_TYPE;
default: default:
break; break;
} }
return NULL; return NULL;
} }
@ -177,10 +178,11 @@ GenericKeyring *
GetKeyProviderByName(const char *provider_name, Oid dbOid, Oid spcOid) GetKeyProviderByName(const char *provider_name, Oid dbOid, Oid spcOid)
{ {
GenericKeyring *keyring = NULL; GenericKeyring *keyring = NULL;
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_NAME, (void*)provider_name, dbOid, spcOid); List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_NAME, (void *) provider_name, dbOid, spcOid);
if (providers != NIL) if (providers != NIL)
{ {
keyring = (GenericKeyring *)linitial(providers); keyring = (GenericKeyring *) linitial(providers);
list_free(providers); list_free(providers);
} }
else else
@ -216,12 +218,15 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
{ {
LWLockRelease(tde_provider_info_lock()); LWLockRelease(tde_provider_info_lock());
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path))); errmsg("could not open tde file \"%s\": %m", kp_info_path)));
} }
if (position == -1) if (position == -1)
{ {
/* we also need to verify the name conflict and generate the next provider ID */ /*
* we also need to verify the name conflict and generate the next
* provider ID
*/
while (fetch_next_key_provider(fd, &curr_pos, &existing_provider)) while (fetch_next_key_provider(fd, &curr_pos, &existing_provider))
{ {
if (strcmp(existing_provider.provider_name, provider->provider_name) == 0) if (strcmp(existing_provider.provider_name, provider->provider_name) == 0)
@ -244,7 +249,8 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
provider->provider_id = max_provider_id + 1; provider->provider_id = max_provider_id + 1;
curr_pos = lseek(fd, 0, SEEK_END); curr_pos = lseek(fd, 0, SEEK_END);
/* emit the xlog here. So that we can handle partial file write errors /*
* emit the xlog here. So that we can handle partial file write errors
* but cannot make new WAL entries during recovery. * but cannot make new WAL entries during recovery.
*/ */
if (write_xlog) if (write_xlog)
@ -257,18 +263,20 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
memcpy(&xlrec.provider, provider, sizeof(KeyringProvideRecord)); memcpy(&xlrec.provider, provider, sizeof(KeyringProvideRecord));
XLogBeginInsert(); XLogBeginInsert();
XLogRegisterData((char *)&xlrec, sizeof(KeyringProviderXLRecord)); XLogRegisterData((char *) &xlrec, sizeof(KeyringProviderXLRecord));
XLogInsert(RM_TDERMGR_ID, XLOG_TDE_ADD_KEY_PROVIDER_KEY); XLogInsert(RM_TDERMGR_ID, XLOG_TDE_ADD_KEY_PROVIDER_KEY);
} }
} }
else else
{ {
/* we are performing redo, just go to the position received from the /*
* xlog and write the record there. * we are performing redo, just go to the position received from the
* No need to verify the name conflict and generate the provider ID * xlog and write the record there. No need to verify the name
* conflict and generate the provider ID
*/ */
curr_pos = lseek(fd, position, SEEK_SET); curr_pos = lseek(fd, position, SEEK_SET);
} }
/* /*
* All good, Just add a new provider * All good, Just add a new provider
*/ */
@ -315,7 +323,7 @@ copy_key_provider_info(KeyringProvideRecord* provider, Oid newdatabaseId, Oid ne
} }
uint32 uint32
redo_key_provider_info(KeyringProviderXLRecord* xlrec) redo_key_provider_info(KeyringProviderXLRecord *xlrec)
{ {
return write_key_provider_info(&xlrec->provider, xlrec->database_id, xlrec->tablespace_id, xlrec->offset_in_file, true, false); return write_key_provider_info(&xlrec->provider, xlrec->database_id, xlrec->tablespace_id, xlrec->offset_in_file, true, false);
} }
@ -324,7 +332,7 @@ void
cleanup_key_provider_info(Oid databaseId, Oid tablespaceId) cleanup_key_provider_info(Oid databaseId, Oid tablespaceId)
{ {
/* Remove the key provider info file */ /* Remove the key provider info file */
char kp_info_path[MAXPGPATH] = {0}; char kp_info_path[MAXPGPATH] = {0};
get_keyring_infofile_path(kp_info_path, databaseId, tablespaceId); get_keyring_infofile_path(kp_info_path, databaseId, tablespaceId);
PathNameDeleteTemporaryFile(kp_info_path, false); PathNameDeleteTemporaryFile(kp_info_path, false);
@ -358,13 +366,14 @@ pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS)
Datum Datum
pg_tde_list_all_key_providers(PG_FUNCTION_ARGS) pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
{ {
List* all_providers = GetAllKeyringProviders(MyDatabaseId, MyDatabaseTableSpace); List *all_providers = GetAllKeyringProviders(MyDatabaseId, MyDatabaseTableSpace);
ListCell *lc; ListCell *lc;
Tuplestorestate *tupstore; Tuplestorestate *tupstore;
TupleDesc tupdesc; TupleDesc tupdesc;
MemoryContext per_query_ctx; MemoryContext per_query_ctx;
MemoryContext oldcontext; MemoryContext oldcontext;
ReturnSetInfo *rsinfo = (ReturnSetInfo *)fcinfo->resultinfo; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
/* check to see if caller supports us returning a tuplestore */ /* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR, ereport(ERROR,
@ -390,11 +399,11 @@ pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
foreach (lc, all_providers) foreach(lc, all_providers)
{ {
Datum values[PG_TDE_LIST_PROVIDERS_COLS] = {0}; Datum values[PG_TDE_LIST_PROVIDERS_COLS] = {0};
bool nulls[PG_TDE_LIST_PROVIDERS_COLS] = {0}; bool nulls[PG_TDE_LIST_PROVIDERS_COLS] = {0};
GenericKeyring *keyring = (GenericKeyring *)lfirst(lc); GenericKeyring *keyring = (GenericKeyring *) lfirst(lc);
int i = 0; int i = 0;
values[i++] = Int32GetDatum(keyring->key_id); values[i++] = Int32GetDatum(keyring->key_id);
@ -406,7 +415,7 @@ pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
debug_print_kerying(keyring); debug_print_kerying(keyring);
} }
list_free_deep(all_providers); list_free_deep(all_providers);
return (Datum)0; return (Datum) 0;
} }
GenericKeyring * GenericKeyring *
@ -414,15 +423,16 @@ GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid)
{ {
GenericKeyring *keyring = NULL; GenericKeyring *keyring = NULL;
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid);
if (providers != NIL) if (providers != NIL)
{ {
keyring = (GenericKeyring *)linitial(providers); keyring = (GenericKeyring *) linitial(providers);
list_free(providers); list_free(providers);
} }
return keyring; return keyring;
} }
#endif /* !FRONTEND */ #endif /* !FRONTEND */
#ifdef FRONTEND #ifdef FRONTEND
GenericKeyring * GenericKeyring *
@ -430,6 +440,7 @@ GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid)
{ {
GenericKeyring *keyring = NULL; GenericKeyring *keyring = NULL;
SimplePtrList *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); SimplePtrList *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid);
if (providers != NULL) if (providers != NULL)
{ {
keyring = (GenericKeyring *) providers->head->ptr; keyring = (GenericKeyring *) providers->head->ptr;
@ -453,7 +464,7 @@ simple_list_free(SimplePtrList *list)
cell = next; cell = next;
} }
} }
#endif /* FRONTEND */ #endif /* FRONTEND */
/* /*
* Scan the key provider info file and can also apply filter based on scanType * Scan the key provider info file and can also apply filter based on scanType
@ -487,29 +498,30 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid
{ {
LWLockRelease(tde_provider_info_lock()); LWLockRelease(tde_provider_info_lock());
ereport(DEBUG2, ereport(DEBUG2,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path))); errmsg("could not open tde file \"%s\": %m", kp_info_path)));
return providers_list; return providers_list;
} }
while (fetch_next_key_provider(fd, &curr_pos, &provider)) while (fetch_next_key_provider(fd, &curr_pos, &provider))
{ {
bool match = false; bool match = false;
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name))); (errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name)));
if (scanType == PROVIDER_SCAN_BY_NAME) if (scanType == PROVIDER_SCAN_BY_NAME)
{ {
if (strcasecmp(provider.provider_name, (char*)scanKey) == 0) if (strcasecmp(provider.provider_name, (char *) scanKey) == 0)
match = true; match = true;
} }
else if (scanType == PROVIDER_SCAN_BY_ID) else if (scanType == PROVIDER_SCAN_BY_ID)
{ {
if (provider.provider_id == *(int *)scanKey) if (provider.provider_id == *(int *) scanKey)
match = true; match = true;
} }
else if (scanType == PROVIDER_SCAN_BY_TYPE) else if (scanType == PROVIDER_SCAN_BY_TYPE)
{ {
if (provider.provider_type == *(ProviderType*)scanKey) if (provider.provider_type == *(ProviderType *) scanKey)
match = true; match = true;
} }
else if (scanType == PROVIDER_SCAN_ALL) else if (scanType == PROVIDER_SCAN_ALL)
@ -518,6 +530,7 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid
if (match) if (match)
{ {
GenericKeyring *keyring = load_keyring_provider_from_record(&provider); GenericKeyring *keyring = load_keyring_provider_from_record(&provider);
if (keyring) if (keyring)
{ {
#ifndef FRONTEND #ifndef FRONTEND
@ -558,14 +571,14 @@ load_keyring_provider_options(ProviderType provider_type, char *keyring_options)
{ {
switch (provider_type) switch (provider_type)
{ {
case FILE_KEY_PROVIDER: case FILE_KEY_PROVIDER:
return (GenericKeyring *)load_file_keyring_provider_options(keyring_options); return (GenericKeyring *) load_file_keyring_provider_options(keyring_options);
break; break;
case VAULT_V2_KEY_PROVIDER: case VAULT_V2_KEY_PROVIDER:
return (GenericKeyring *)load_vaultV2_keyring_provider_options(keyring_options); return (GenericKeyring *) load_vaultV2_keyring_provider_options(keyring_options);
break; break;
default: default:
break; break;
} }
return NULL; return NULL;
} }
@ -573,17 +586,17 @@ load_keyring_provider_options(ProviderType provider_type, char *keyring_options)
static FileKeyring * static FileKeyring *
load_file_keyring_provider_options(char *keyring_options) load_file_keyring_provider_options(char *keyring_options)
{ {
FileKeyring *file_keyring = palloc0(sizeof(FileKeyring)); FileKeyring *file_keyring = palloc0(sizeof(FileKeyring));
file_keyring->keyring.type = FILE_KEY_PROVIDER; file_keyring->keyring.type = FILE_KEY_PROVIDER;
if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring, if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring,
keyring_options, strlen(keyring_options))) keyring_options, strlen(keyring_options)))
{ {
return NULL; return NULL;
} }
if(strlen(file_keyring->file_name) == 0) if (strlen(file_keyring->file_name) == 0)
{ {
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -597,26 +610,26 @@ load_file_keyring_provider_options(char *keyring_options)
static VaultV2Keyring * static VaultV2Keyring *
load_vaultV2_keyring_provider_options(char *keyring_options) load_vaultV2_keyring_provider_options(char *keyring_options)
{ {
VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring)); VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring));
vaultV2_keyring->keyring.type = VAULT_V2_KEY_PROVIDER; vaultV2_keyring->keyring.type = VAULT_V2_KEY_PROVIDER;
if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring, if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring,
keyring_options, strlen(keyring_options))) keyring_options, strlen(keyring_options)))
{ {
return NULL; return NULL;
} }
if(strlen(vaultV2_keyring->vault_token) == 0 || if (strlen(vaultV2_keyring->vault_token) == 0 ||
strlen(vaultV2_keyring->vault_url) == 0 || strlen(vaultV2_keyring->vault_url) == 0 ||
strlen(vaultV2_keyring->vault_mount_path) == 0) strlen(vaultV2_keyring->vault_mount_path) == 0)
{ {
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("missing in the keyring options:%s%s%s", errmsg("missing in the keyring options:%s%s%s",
*(vaultV2_keyring->vault_token) ? "" : " token", *(vaultV2_keyring->vault_token) ? "" : " token",
*(vaultV2_keyring->vault_url) ? "" : " url", *(vaultV2_keyring->vault_url) ? "" : " url",
*(vaultV2_keyring->vault_mount_path) ? "" : " mountPath"))); *(vaultV2_keyring->vault_mount_path) ? "" : " mountPath")));
return NULL; return NULL;
} }
@ -627,30 +640,32 @@ static void
debug_print_kerying(GenericKeyring *keyring) debug_print_kerying(GenericKeyring *keyring)
{ {
int debug_level = DEBUG2; int debug_level = DEBUG2;
elog(debug_level, "Keyring type: %d", keyring->type); elog(debug_level, "Keyring type: %d", keyring->type);
elog(debug_level, "Keyring name: %s", keyring->provider_name); elog(debug_level, "Keyring name: %s", keyring->provider_name);
elog(debug_level, "Keyring id: %d", keyring->key_id); elog(debug_level, "Keyring id: %d", keyring->key_id);
switch (keyring->type) switch (keyring->type)
{ {
case FILE_KEY_PROVIDER: case FILE_KEY_PROVIDER:
elog(debug_level, "File Keyring Path: %s", ((FileKeyring *)keyring)->file_name); elog(debug_level, "File Keyring Path: %s", ((FileKeyring *) keyring)->file_name);
break; break;
case VAULT_V2_KEY_PROVIDER: case VAULT_V2_KEY_PROVIDER:
elog(debug_level, "Vault Keyring Token: %s", ((VaultV2Keyring *)keyring)->vault_token); elog(debug_level, "Vault Keyring Token: %s", ((VaultV2Keyring *) keyring)->vault_token);
elog(debug_level, "Vault Keyring URL: %s", ((VaultV2Keyring *)keyring)->vault_url); elog(debug_level, "Vault Keyring URL: %s", ((VaultV2Keyring *) keyring)->vault_url);
elog(debug_level, "Vault Keyring Mount Path: %s", ((VaultV2Keyring *)keyring)->vault_mount_path); elog(debug_level, "Vault Keyring Mount Path: %s", ((VaultV2Keyring *) keyring)->vault_mount_path);
elog(debug_level, "Vault Keyring CA Path: %s", ((VaultV2Keyring *)keyring)->vault_ca_path); elog(debug_level, "Vault Keyring CA Path: %s", ((VaultV2Keyring *) keyring)->vault_ca_path);
break; break;
case UNKNOWN_KEY_PROVIDER: case UNKNOWN_KEY_PROVIDER:
elog(debug_level, "Unknown Keyring "); elog(debug_level, "Unknown Keyring ");
break; break;
} }
} }
static char* static char *
get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid) get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid)
{ {
char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid); char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid);
Assert(db_path != NULL); Assert(db_path != NULL);
join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME); join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME);
pfree(db_path); pfree(db_path);
@ -661,7 +676,7 @@ get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid)
* Fetch the next key provider from the file and update the curr_pos * Fetch the next key provider from the file and update the curr_pos
*/ */
static bool static bool
fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider) fetch_next_key_provider(int fd, off_t *curr_pos, KeyringProvideRecord *provider)
{ {
off_t bytes_read = 0; off_t bytes_read = 0;
@ -679,8 +694,8 @@ fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider)
/* Corrupt file */ /* Corrupt file */
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("key provider info file is corrupted: %m"), errmsg("key provider info file is corrupted: %m"),
errdetail("invalid key provider record size %lld expected %lu", bytes_read, sizeof(KeyringProvideRecord) ))); errdetail("invalid key provider record size %lld expected %lu", bytes_read, sizeof(KeyringProvideRecord))));
} }
return true; return true;
} }

@ -2,7 +2,7 @@
* *
* tde_keyring_parse_opts.c * tde_keyring_parse_opts.c
* Parser routines for the keyring JSON options * Parser routines for the keyring JSON options
* *
* Each value in the JSON document can be either scalar (string) - a value itself * Each value in the JSON document can be either scalar (string) - a value itself
* or a reference to the external object that contains the value. Though the top * or a reference to the external object that contains the value. Though the top
* level field "type" can be only scalar. * level field "type" can be only scalar.
@ -47,7 +47,7 @@ typedef enum JsonKeringSemState
{ {
JK_EXPECT_TOP_FIELD, JK_EXPECT_TOP_FIELD,
JK_EXPECT_EXTERN_VAL, JK_EXPECT_EXTERN_VAL,
} JsonKeringSemState; } JsonKeringSemState;
#define KEYRING_REMOTE_FIELD_TYPE "remote" #define KEYRING_REMOTE_FIELD_TYPE "remote"
#define KEYRING_FILE_FIELD_TYPE "file" #define KEYRING_FILE_FIELD_TYPE "file"
@ -71,7 +71,7 @@ typedef enum JsonKeyringField
/* must be the last */ /* must be the last */
JK_FIELDS_TOTAL JK_FIELDS_TOTAL
} JsonKeyringField; } JsonKeyringField;
static const char *JK_FIELD_NAMES[JK_FIELDS_TOTAL] = { static const char *JK_FIELD_NAMES[JK_FIELDS_TOTAL] = {
[JK_FIELD_UNKNOWN] = "unknownField", [JK_FIELD_UNKNOWN] = "unknownField",
@ -100,7 +100,7 @@ typedef struct JsonKeyringState
* Caller's options to be set from JSON values. Expected either * Caller's options to be set from JSON values. Expected either
* `VaultV2Keyring` or `FileKeyring` * `VaultV2Keyring` or `FileKeyring`
*/ */
void *provider_opts; void *provider_opts;
/* /*
* A field hierarchy of the current branch, field[level] is the current * A field hierarchy of the current branch, field[level] is the current
@ -109,25 +109,25 @@ typedef struct JsonKeyringState
*/ */
JsonKeyringField field[MAX_JSON_DEPTH]; JsonKeyringField field[MAX_JSON_DEPTH];
JsonKeringSemState state; JsonKeringSemState state;
int level; int level;
/* /*
* The rest of the scalar fields might be in the JSON document but has no * The rest of the scalar fields might be in the JSON document but has no
* direct value for the caller. Although we need them for the values * direct value for the caller. Although we need them for the values
* extraction or state tracking. * extraction or state tracking.
*/ */
char *kring_type; char *kring_type;
char *field_type; char *field_type;
char *extern_url; char *extern_url;
char *extern_path; char *extern_path;
} JsonKeyringState; } JsonKeyringState;
static JsonParseErrorType json_kring_scalar(void *state, char *token, JsonTokenType tokentype); static JsonParseErrorType json_kring_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType json_kring_object_field_start(void *state, char *fname, bool isnull); static JsonParseErrorType json_kring_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType json_kring_object_start(void *state); static JsonParseErrorType json_kring_object_start(void *state);
static JsonParseErrorType json_kring_object_end(void *state); static JsonParseErrorType json_kring_object_end(void *state);
static void json_kring_assign_scalar(JsonKeyringState * parse, JsonKeyringField field, char *value); static void json_kring_assign_scalar(JsonKeyringState *parse, JsonKeyringField field, char *value);
static char *get_remote_kring_value(const char *url, const char *field_name); static char *get_remote_kring_value(const char *url, const char *field_name);
static char *get_file_kring_value(const char *path, const char *field_name); static char *get_file_kring_value(const char *path, const char *field_name);
@ -364,7 +364,7 @@ json_kring_scalar(void *state, char *token, JsonTokenType tokentype)
} }
static void static void
json_kring_assign_scalar(JsonKeyringState * parse, JsonKeyringField field, char *value) json_kring_assign_scalar(JsonKeyringState *parse, JsonKeyringField field, char *value)
{ {
VaultV2Keyring *vault = parse->provider_opts; VaultV2Keyring *vault = parse->provider_opts;
FileKeyring *file = parse->provider_opts; FileKeyring *file = parse->provider_opts;
@ -437,15 +437,15 @@ get_remote_kring_value(const char *url, const char *field_name)
/* remove trailing whitespace */ /* remove trailing whitespace */
outStr.ptr[strcspn(outStr.ptr, " \t\n\r")] = '\0'; outStr.ptr[strcspn(outStr.ptr, " \t\n\r")] = '\0';
return outStr.ptr; return outStr.ptr;
} }
static char * static char *
get_file_kring_value(const char *path, const char *field_name) get_file_kring_value(const char *path, const char *field_name)
{ {
int fd = -1; int fd = -1;
char *val; char *val;
fd = BasicOpenFile(path, O_RDONLY); fd = BasicOpenFile(path, O_RDONLY);
if (fd < 0) if (fd < 0)

File diff suppressed because it is too large Load Diff

@ -19,16 +19,15 @@ typedef struct TdeSharedState
{ {
LWLock *principalKeyLock; LWLock *principalKeyLock;
int principalKeyHashTrancheId; int principalKeyHashTrancheId;
void *rawDsaArea; /* DSA area pointer to store cache hashes */ void *rawDsaArea; /* DSA area pointer to store cache hashes */
dshash_table_handle principalKeyHashHandle; dshash_table_handle principalKeyHashHandle;
} TdeSharedState; } TdeSharedState;
typedef struct TDELocalState typedef struct TDELocalState
{ {
TdeSharedState *sharedTdeState; TdeSharedState *sharedTdeState;
dsa_area **dsa; /* local dsa area for backend attached to the dsa_area **dsa; /* local dsa area for backend attached to the
* dsa area created by postmaster at startup. * dsa area created by postmaster at startup. */
*/
dshash_table *principalKeySharedHash; dshash_table *principalKeySharedHash;
} TDELocalState; } TDELocalState;
@ -37,19 +36,23 @@ static void tde_shmem_shutdown(int code, Datum arg);
List *registeredShmemRequests = NIL; List *registeredShmemRequests = NIL;
bool shmemInited = false; bool shmemInited = false;
void RegisterShmemRequest(const TDEShmemSetupRoutine *routine) void
RegisterShmemRequest(const TDEShmemSetupRoutine *routine)
{ {
Assert(shmemInited == false); Assert(shmemInited == false);
registeredShmemRequests = lappend(registeredShmemRequests, (void *)routine); registeredShmemRequests = lappend(registeredShmemRequests, (void *) routine);
} }
Size TdeRequiredSharedMemorySize(void) Size
TdeRequiredSharedMemorySize(void)
{ {
Size sz = 0; Size sz = 0;
ListCell *lc; ListCell *lc;
foreach (lc, registeredShmemRequests)
foreach(lc, registeredShmemRequests)
{ {
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->required_shared_mem_size) if (routine->required_shared_mem_size)
sz = add_size(sz, routine->required_shared_mem_size()); sz = add_size(sz, routine->required_shared_mem_size());
} }
@ -57,12 +60,14 @@ Size TdeRequiredSharedMemorySize(void)
return MAXALIGN(sz); return MAXALIGN(sz);
} }
int TdeRequiredLocksCount(void) int
TdeRequiredLocksCount(void)
{ {
return TDE_LWLOCK_COUNT; return TDE_LWLOCK_COUNT;
} }
void TdeShmemInit(void) void
TdeShmemInit(void)
{ {
bool found; bool found;
TdeSharedState *tdeState; TdeSharedState *tdeState;
@ -76,7 +81,7 @@ void TdeShmemInit(void)
if (!found) if (!found)
{ {
/* First time through ... */ /* First time through ... */
char *p = (char *)tdeState; char *p = (char *) tdeState;
dsa_area *dsa; dsa_area *dsa;
ListCell *lc; ListCell *lc;
Size used_size = 0; Size used_size = 0;
@ -85,10 +90,11 @@ void TdeShmemInit(void)
p += MAXALIGN(sizeof(TdeSharedState)); p += MAXALIGN(sizeof(TdeSharedState));
used_size += MAXALIGN(sizeof(TdeSharedState)); used_size += MAXALIGN(sizeof(TdeSharedState));
/* Now place all shared state structures */ /* Now place all shared state structures */
foreach (lc, registeredShmemRequests) foreach(lc, registeredShmemRequests)
{ {
Size sz = 0; Size sz = 0;
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->init_shared_state) if (routine->init_shared_state)
{ {
sz = routine->init_shared_state(p); sz = routine->init_shared_state(p);
@ -110,29 +116,33 @@ void TdeShmemInit(void)
dsa_set_size_limit(dsa, dsa_area_size); dsa_set_size_limit(dsa, dsa_area_size);
/* Initialize all DSA area objects */ /* Initialize all DSA area objects */
foreach (lc, registeredShmemRequests) foreach(lc, registeredShmemRequests)
{ {
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->init_dsa_area_objects) if (routine->init_dsa_area_objects)
routine->init_dsa_area_objects(dsa, tdeState->rawDsaArea); routine->init_dsa_area_objects(dsa, tdeState->rawDsaArea);
} }
ereport(LOG, (errmsg("setting no limit to DSA area of size %lu", dsa_area_size))); ereport(LOG, (errmsg("setting no limit to DSA area of size %lu", dsa_area_size)));
dsa_set_size_limit(dsa, -1); /* Let it grow outside the shared memory */ dsa_set_size_limit(dsa, -1); /* Let it grow outside the shared
* memory */
shmemInited = true; shmemInited = true;
} }
LWLockRelease(AddinShmemInitLock); LWLockRelease(AddinShmemInitLock);
on_shmem_exit(tde_shmem_shutdown, (Datum)0); on_shmem_exit(tde_shmem_shutdown, (Datum) 0);
} }
static void static void
tde_shmem_shutdown(int code, Datum arg) tde_shmem_shutdown(int code, Datum arg)
{ {
ListCell *lc; ListCell *lc;
foreach (lc, registeredShmemRequests)
foreach(lc, registeredShmemRequests)
{ {
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->shmem_kill) if (routine->shmem_kill)
routine->shmem_kill(code, arg); routine->shmem_kill(code, arg);
} }

@ -23,89 +23,92 @@
Oid Oid
get_tde_basic_table_am_oid(void) get_tde_basic_table_am_oid(void)
{ {
return get_table_am_oid("tde_heap_basic", false); return get_table_am_oid("tde_heap_basic", false);
} }
Oid Oid
get_tde_table_am_oid(void) get_tde_table_am_oid(void)
{ {
return get_table_am_oid("tde_heap", false); return get_table_am_oid("tde_heap", false);
} }
/* /*
* Returns the list of OIDs for all TDE tables in a database * Returns the list of OIDs for all TDE tables in a database
*/ */
List* List *
get_all_tde_tables(void) get_all_tde_tables(void)
{ {
Relation pg_class; Relation pg_class;
SysScanDesc scan; SysScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
List* tde_tables = NIL; List *tde_tables = NIL;
Oid am_oid = get_tde_basic_table_am_oid(); Oid am_oid = get_tde_basic_table_am_oid();
/* Open the pg_class table */ /* Open the pg_class table */
pg_class = table_open(RelationRelationId, AccessShareLock); pg_class = table_open(RelationRelationId, AccessShareLock);
/* Start a scan */ /* Start a scan */
scan = systable_beginscan(pg_class, ClassOidIndexId, true, scan = systable_beginscan(pg_class, ClassOidIndexId, true,
SnapshotSelf, 0, NULL); SnapshotSelf, 0, NULL);
/* Iterate over all tuples in the table */ /* Iterate over all tuples in the table */
while ((tuple = systable_getnext(scan)) != NULL) while ((tuple = systable_getnext(scan)) != NULL)
{ {
Form_pg_class classForm = (Form_pg_class)GETSTRUCT(tuple); Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
/* Check if the table uses the specified access method */ /* Check if the table uses the specified access method */
if (classForm->relam == am_oid) if (classForm->relam == am_oid)
{ {
/* Print the name of the table */ /* Print the name of the table */
tde_tables = lappend_oid(tde_tables, classForm->oid); tde_tables = lappend_oid(tde_tables, classForm->oid);
elog(DEBUG2, "Table %s uses the TDE access method.", NameStr(classForm->relname)); elog(DEBUG2, "Table %s uses the TDE access method.", NameStr(classForm->relname));
} }
} }
/* End the scan */ /* End the scan */
systable_endscan(scan); systable_endscan(scan);
/* Close the pg_class table */ /* Close the pg_class table */
table_close(pg_class, AccessShareLock); table_close(pg_class, AccessShareLock);
return tde_tables; return tde_tables;
} }
int int
get_tde_tables_count(void) get_tde_tables_count(void)
{ {
List* tde_tables = get_all_tde_tables(); List *tde_tables = get_all_tde_tables();
int count = list_length(tde_tables); int count = list_length(tde_tables);
list_free(tde_tables);
return count; list_free(tde_tables);
return count;
} }
#endif /* !FRONTEND */ #endif /* !FRONTEND */
static char globalspace_dir[MAXPGPATH] = {0}; static char globalspace_dir[MAXPGPATH] = {0};
void void
pg_tde_set_globalspace_dir(const char *dir) pg_tde_set_globalspace_dir(const char *dir)
{ {
Assert(dir != NULL); Assert(dir != NULL);
strncpy(globalspace_dir, dir, sizeof(globalspace_dir)); strncpy(globalspace_dir, dir, sizeof(globalspace_dir));
} }
/* returns the palloc'd string */ /* returns the palloc'd string */
char * char *
pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid) pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid)
{ {
/* `dbOid` is set to a value for the XLog keys caching but GetDatabasePath() /*
* expects it (`dbOid`) to be `0` if this is a global space. * `dbOid` is set to a value for the XLog keys caching but
* GetDatabasePath() expects it (`dbOid`) to be `0` if this is a global
* space.
*/ */
if (spcOid == GLOBALTABLESPACE_OID) if (spcOid == GLOBALTABLESPACE_OID)
{ {
if (strlen(globalspace_dir) > 0) if (strlen(globalspace_dir) > 0)
return pstrdup(globalspace_dir); return pstrdup(globalspace_dir);
return pstrdup("global"); return pstrdup("global");
} }
return GetDatabasePath(dbOid, spcOid); return GetDatabasePath(dbOid, spcOid);
} }

@ -39,48 +39,51 @@
* * When a new block is requested, we use this stored context to encrypt the position information * * When a new block is requested, we use this stored context to encrypt the position information
* * And then XOR it with the data * * And then XOR it with the data
* *
* This is still not as fast as using 8k blocks, but already 2 orders of magnitude better than direct CTR with * This is still not as fast as using 8k blocks, but already 2 orders of magnitude better than direct CTR with
* 16 byte blocks. * 16 byte blocks.
*/ */
const EVP_CIPHER* cipher = NULL; const EVP_CIPHER *cipher = NULL;
const EVP_CIPHER* cipher2 = NULL; const EVP_CIPHER *cipher2 = NULL;
int cipher_block_size = 0; int cipher_block_size = 0;
void AesInit(void) void
AesInit(void)
{ {
static int initialized = 0; static int initialized = 0;
if(!initialized) { if (!initialized)
{
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
cipher = EVP_aes_128_cbc(); cipher = EVP_aes_128_cbc();
cipher_block_size = EVP_CIPHER_block_size(cipher); // == buffer size cipher_block_size = EVP_CIPHER_block_size(cipher);
cipher2 = EVP_aes_128_ecb(); //== buffer size
cipher2 = EVP_aes_128_ecb();
initialized = 1; initialized = 1;
} }
} }
// TODO: a few things could be optimized in this. It's good enough for a prototype. /* TODO: a few things could be optimized in this. It's good enough for a prototype. */
static void static void
AesRunCtr(EVP_CIPHER_CTX** ctxPtr, int enc, const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) AesRunCtr(EVP_CIPHER_CTX **ctxPtr, int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
if (*ctxPtr == NULL) if (*ctxPtr == NULL)
{ {
*ctxPtr = EVP_CIPHER_CTX_new(); *ctxPtr = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(*ctxPtr); EVP_CIPHER_CTX_init(*ctxPtr);
if(EVP_CipherInit_ex(*ctxPtr, cipher2, NULL, key, iv, enc) == 0) if (EVP_CipherInit_ex(*ctxPtr, cipher2, NULL, key, iv, enc) == 0)
{ {
#ifdef FRONTEND #ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else #else
ereport(ERROR, ereport(ERROR,
(errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)))); (errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif #endif
return; return;
} }
@ -88,103 +91,109 @@ AesRunCtr(EVP_CIPHER_CTX** ctxPtr, int enc, const unsigned char* key, const unsi
EVP_CIPHER_CTX_set_padding(*ctxPtr, 0); EVP_CIPHER_CTX_set_padding(*ctxPtr, 0);
} }
if(EVP_CipherUpdate(*ctxPtr, out, out_len, in, in_len) == 0) if (EVP_CipherUpdate(*ctxPtr, out, out_len, in, in_len) == 0)
{ {
#ifdef FRONTEND #ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else #else
ereport(ERROR, ereport(ERROR,
(errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)))); (errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif #endif
return; return;
} }
} }
static void AesRunCbc(int enc, const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) static void
AesRunCbc(int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
int out_len_final = 0; int out_len_final = 0;
EVP_CIPHER_CTX* ctx = NULL; EVP_CIPHER_CTX *ctx = NULL;
ctx = EVP_CIPHER_CTX_new(); ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx); EVP_CIPHER_CTX_init(ctx);
if(EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) == 0) if (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) == 0)
{ {
#ifdef FRONTEND #ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else #else
ereport(ERROR, ereport(ERROR,
(errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)))); (errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif #endif
goto cleanup; goto cleanup;
} }
EVP_CIPHER_CTX_set_padding(ctx, 0); EVP_CIPHER_CTX_set_padding(ctx, 0);
Assert(in_len % cipher_block_size == 0); Assert(in_len % cipher_block_size == 0);
if(EVP_CipherUpdate(ctx, out, out_len, in, in_len) == 0) if (EVP_CipherUpdate(ctx, out, out_len, in, in_len) == 0)
{ {
#ifdef FRONTEND #ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else #else
ereport(ERROR, ereport(ERROR,
(errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)))); (errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif #endif
goto cleanup; goto cleanup;
} }
if(EVP_CipherFinal_ex(ctx, out + *out_len, &out_len_final) == 0) if (EVP_CipherFinal_ex(ctx, out + *out_len, &out_len_final) == 0)
{ {
#ifdef FRONTEND #ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else #else
ereport(ERROR, ereport(ERROR,
(errmsg("EVP_CipherFinal_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)))); (errmsg("EVP_CipherFinal_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif #endif
goto cleanup; goto cleanup;
} }
/* We encrypt one block (16 bytes) /*
* Our expectation is that the result should also be 16 bytes, without any additional padding * We encrypt one block (16 bytes) Our expectation is that the result
* should also be 16 bytes, without any additional padding
*/ */
*out_len += out_len_final; *out_len += out_len_final;
Assert(in_len == *out_len); Assert(in_len == *out_len);
cleanup: cleanup:
EVP_CIPHER_CTX_cleanup(ctx); EVP_CIPHER_CTX_cleanup(ctx);
EVP_CIPHER_CTX_free(ctx); EVP_CIPHER_CTX_free(ctx);
} }
void AesEncrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) void
AesEncrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
AesRunCbc(1, key, iv, in, in_len, out, out_len); AesRunCbc(1, key, iv, in, in_len, out, out_len);
} }
void AesDecrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) void
AesDecrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
AesRunCbc(0, key, iv, in, in_len, out, out_len); AesRunCbc(0, key, iv, in, in_len, out, out_len);
} }
/* This function assumes that the out buffer is big enough: at least (blockNumber2 - blockNumber1) * 16 bytes /* This function assumes that the out buffer is big enough: at least (blockNumber2 - blockNumber1) * 16 bytes
*/ */
void Aes128EncryptedZeroBlocks(void* ctxPtr, const unsigned char* key, const char* iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char* out) void
Aes128EncryptedZeroBlocks(void *ctxPtr, const unsigned char *key, const char *iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char *out)
{ {
const unsigned char iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned dataLen = (blockNumber2 - blockNumber1) * 16; const unsigned dataLen = (blockNumber2 - blockNumber1) * 16;
int outLen; int outLen;
Assert(blockNumber2 >= blockNumber1); Assert(blockNumber2 >= blockNumber1);
for(int j=blockNumber1;j<blockNumber2;++j) for (int j = blockNumber1; j < blockNumber2; ++j)
{ {
/* /*
* We have 16 bytes, and a 4 byte counter. The counter is the last 4 bytes. * We have 16 bytes, and a 4 byte counter. The counter is the last 4
* Technically, this isn't correct: the byte order of the counter depends * bytes. Technically, this isn't correct: the byte order of the
* on the endianness of the CPU running it. * counter depends on the endianness of the CPU running it. As this is
* As this is a generic limitation of Postgres, it's fine. * a generic limitation of Postgres, it's fine.
*/ */
memcpy(out + (16*(j-blockNumber1)), iv_prefix, 12); memcpy(out + (16 * (j - blockNumber1)), iv_prefix, 12);
memcpy(out + (16*(j-blockNumber1)) + 12, (char*)&j, 4); memcpy(out + (16 * (j - blockNumber1)) + 12, (char *) &j, 4);
} }
AesRunCtr(ctxPtr, 1, key, iv, out, dataLen, out, &outLen); AesRunCtr(ctxPtr, 1, key, iv, out, dataLen, out, &outLen);

@ -11,23 +11,26 @@
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
static void iv_prefix_debug(const char* iv_prefix, char* out_hex) static void
iv_prefix_debug(const char *iv_prefix, char *out_hex)
{ {
for(int i =0;i<16;++i) { for (int i = 0; i < 16; ++i)
sprintf(out_hex + i*2, "%02x", (int)*(iv_prefix + i)); {
sprintf(out_hex + i * 2, "%02x", (int) *(iv_prefix + i));
} }
out_hex[32] = 0; out_hex[32] = 0;
} }
#endif #endif
static void static void
SetIVPrefix(ItemPointerData* ip, char* iv_prefix) SetIVPrefix(ItemPointerData *ip, char *iv_prefix)
{ {
/* We have up to 16 bytes for the entire IV /*
* The higher bytes (starting with 15) are used for the incrementing counter * We have up to 16 bytes for the entire IV The higher bytes (starting
* The lower bytes (in this case, 0..5) are used for the tuple identification * with 15) are used for the incrementing counter The lower bytes (in this
* Tuple identification is based on CTID, which currently is 48 bytes in * case, 0..5) are used for the tuple identification Tuple identification
* postgres: 4 bytes for the block id and 2 bytes for the position id * is based on CTID, which currently is 48 bytes in postgres: 4 bytes for
* the block id and 2 bytes for the position id
*/ */
iv_prefix[0] = ip->ip_blkid.bi_hi / 256; iv_prefix[0] = ip->ip_blkid.bi_hi / 256;
iv_prefix[1] = ip->ip_blkid.bi_hi % 256; iv_prefix[1] = ip->ip_blkid.bi_hi % 256;
@ -37,20 +40,20 @@ SetIVPrefix(ItemPointerData* ip, char* iv_prefix)
iv_prefix[5] = ip->ip_posid % 256; iv_prefix[5] = ip->ip_posid % 256;
} }
/* /*
* ================================================================ * ================================================================
* ACTUAL ENCRYPTION/DECRYPTION FUNCTIONS * ACTUAL ENCRYPTION/DECRYPTION FUNCTIONS
* ================================================================ * ================================================================
*/ */
/* /*
* pg_tde_crypt_simple: * pg_tde_crypt_simple:
* Encrypts/decrypts `data` with a given `key`. The result is written to `out`. * Encrypts/decrypts `data` with a given `key`. The result is written to `out`.
* start_offset: is the absolute location of start of data in the file. * start_offset: is the absolute location of start of data in the file.
* This function assumes that everything is in a single block, and has an assertion ensuring this * This function assumes that everything is in a single block, and has an assertion ensuring this
*/ */
static void static void
pg_tde_crypt_simple(const char* iv_prefix, uint32 start_offset, const char* data, uint32 data_len, char* out, RelKeyData* key, const char* context) pg_tde_crypt_simple(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, const char *context)
{ {
const uint64 aes_start_block = start_offset / AES_BLOCK_SIZE; const uint64 aes_start_block = start_offset / AES_BLOCK_SIZE;
const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE; const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE;
@ -63,38 +66,39 @@ pg_tde_crypt_simple(const char* iv_prefix, uint32 start_offset, const char* data
Aes128EncryptedZeroBlocks(&(key->internal_key.ctx), key->internal_key.key, iv_prefix, aes_start_block, aes_end_block, enc_key); Aes128EncryptedZeroBlocks(&(key->internal_key.ctx), key->internal_key.key, iv_prefix, aes_start_block, aes_end_block, enc_key);
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
{ {
char ivp_debug[33]; char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG, iv_prefix_debug(iv_prefix, ivp_debug);
(errmsg("%s: Start offset: %lu Data_Len: %u, aes_start_block: %lu, aes_end_block: %lu, IV prefix: %s", ereport(LOG,
context?context:"", start_offset, data_len, aes_start_block, aes_end_block, ivp_debug))); (errmsg("%s: Start offset: %lu Data_Len: %u, aes_start_block: %lu, aes_end_block: %lu, IV prefix: %s",
} context ? context : "", start_offset, data_len, aes_start_block, aes_end_block, ivp_debug)));
}
#endif #endif
for(uint32 i = 0; i < data_len; ++i) for (uint32 i = 0; i < data_len; ++i)
{ {
out[i] = data[i] ^ enc_key[i + aes_block_no]; out[i] = data[i] ^ enc_key[i + aes_block_no];
} }
} }
/* /*
* pg_tde_crypt_complex: * pg_tde_crypt_complex:
* Encrypts/decrypts `data` with a given `key`. The result is written to `out`. * Encrypts/decrypts `data` with a given `key`. The result is written to `out`.
* start_offset: is the absolute location of start of data in the file. * start_offset: is the absolute location of start of data in the file.
* This is a generic function intended for large data, that do not fit into a single block * This is a generic function intended for large data, that do not fit into a single block
*/ */
static void static void
pg_tde_crypt_complex(const char* iv_prefix, uint32 start_offset, const char* data, uint32 data_len, char* out, RelKeyData* key, const char* context) pg_tde_crypt_complex(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, const char *context)
{ {
const uint64 aes_start_block = start_offset / AES_BLOCK_SIZE; const uint64 aes_start_block = start_offset / AES_BLOCK_SIZE;
const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE -1)) / AES_BLOCK_SIZE; const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE;
const uint64 aes_block_no = start_offset % AES_BLOCK_SIZE; const uint64 aes_block_no = start_offset % AES_BLOCK_SIZE;
uint32 batch_no = 0; uint32 batch_no = 0;
uint32 data_index = 0; uint32 data_index = 0;
uint64 batch_end_block; uint64 batch_end_block;
uint32 current_batch_bytes; uint32 current_batch_bytes;
unsigned char enc_key[DATA_BYTES_PER_AES_BATCH]; unsigned char enc_key[DATA_BYTES_PER_AES_BATCH];
/* do max NUM_AES_BLOCKS_IN_BATCH blocks at a time */ /* do max NUM_AES_BLOCKS_IN_BATCH blocks at a time */
@ -104,60 +108,64 @@ pg_tde_crypt_complex(const char* iv_prefix, uint32 start_offset, const char* dat
Aes128EncryptedZeroBlocks(&(key->internal_key.ctx), key->internal_key.key, iv_prefix, batch_start_block, batch_end_block, enc_key); Aes128EncryptedZeroBlocks(&(key->internal_key.ctx), key->internal_key.key, iv_prefix, batch_start_block, batch_end_block, enc_key);
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
{ {
char ivp_debug[33]; char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG, iv_prefix_debug(iv_prefix, ivp_debug);
(errmsg("%s: Batch-No:%d Start offset: %lu Data_Len: %u, batch_start_block: %lu, batch_end_block: %lu, IV prefix: %s", ereport(LOG,
context?context:"", batch_no, start_offset, data_len, batch_start_block, batch_end_block, ivp_debug))); (errmsg("%s: Batch-No:%d Start offset: %lu Data_Len: %u, batch_start_block: %lu, batch_end_block: %lu, IV prefix: %s",
} context ? context : "", batch_no, start_offset, data_len, batch_start_block, batch_end_block, ivp_debug)));
}
#endif #endif
current_batch_bytes = ((batch_end_block - batch_start_block) * AES_BLOCK_SIZE) current_batch_bytes = ((batch_end_block - batch_start_block) * AES_BLOCK_SIZE)
- (batch_no > 0 ? 0 : aes_block_no); /* first batch skips `aes_block_no`-th bytes of enc_key */ - (batch_no > 0 ? 0 : aes_block_no); /* first batch skips
* `aes_block_no`-th bytes
* of enc_key */
if ((data_index + current_batch_bytes) > data_len) if ((data_index + current_batch_bytes) > data_len)
current_batch_bytes = data_len - data_index; current_batch_bytes = data_len - data_index;
for(uint32 i = 0; i < current_batch_bytes; ++i) for (uint32 i = 0; i < current_batch_bytes; ++i)
{ {
/* /*
* As the size of enc_key always is a multiple of 16 we * As the size of enc_key always is a multiple of 16 we start from
* start from `aes_block_no`-th index of the enc_key[] * `aes_block_no`-th index of the enc_key[] so N-th will be
* so N-th will be crypted with the same enc_key byte despite * crypted with the same enc_key byte despite what start_offset
* what start_offset the function was called with. * the function was called with. For example start_offset = 10;
* For example start_offset = 10; MAX_AES_ENC_BATCH_KEY_SIZE = 6: * MAX_AES_ENC_BATCH_KEY_SIZE = 6: data: [10 11 12
* data: [10 11 12 13 14 15 16] * 13 14 15 16] encKey: [...][0 1 2 3 4 5][0 1 2 3 4 5] so
* encKey: [...][0 1 2 3 4 5][0 1 2 3 4 5] * the 10th data byte is encoded with the 4th byte of the 2nd
* so the 10th data byte is encoded with the 4th byte of the 2nd enc_key etc. * enc_key etc. We need this shift so each byte will be coded the
* We need this shift so each byte will be coded the same despite * same despite the initial offset. Let's see the same data but
* the initial offset. * sent to the func starting from the offset 0: data: [0 1 2 3
* Let's see the same data but sent to the func starting from the offset 0: * 4 5 6 7 8 9 10 11 12 13 14 15 16] encKey: [0 1 2 3 4 5][0 1 2 3
* data: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] * 4 5][ 0 1 2 3 4 5] again, the 10th data byte is encoded
* encKey: [0 1 2 3 4 5][0 1 2 3 4 5][ 0 1 2 3 4 5] * with the 4th byte of the 2nd enc_key etc.
* again, the 10th data byte is encoded with the 4th byte of the 2nd enc_key etc.
*/ */
uint32 enc_key_index = i + (batch_no > 0 ? 0 : aes_block_no); uint32 enc_key_index = i + (batch_no > 0 ? 0 : aes_block_no);
out[data_index] = data[data_index] ^ enc_key[enc_key_index]; out[data_index] = data[data_index] ^ enc_key[enc_key_index];
data_index++; data_index++;
} }
batch_no++; batch_no++;
} }
} }
/* /*
* pg_tde_crypt: * pg_tde_crypt:
* Encrypts/decrypts `data` with a given `key`. The result is written to `out`. * Encrypts/decrypts `data` with a given `key`. The result is written to `out`.
* start_offset: is the absolute location of start of data in the file. * start_offset: is the absolute location of start of data in the file.
* This function simply selects between the two above variations based on the data length * This function simply selects between the two above variations based on the data length
*/ */
void void
pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint32 data_len, char* out, RelKeyData* key, const char* context) pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, const char *context)
{ {
if(data_len >= DATA_BYTES_PER_AES_BATCH) if (data_len >= DATA_BYTES_PER_AES_BATCH)
{ {
pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, context); pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, context);
} else }
else
{ {
pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, context); pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, context);
} }
@ -172,51 +180,52 @@ pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint3
* context: Optional context message to be used in debug log * context: Optional context message to be used in debug log
* */ * */
void void
pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData* key, const char* context) pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData *key, const char *context)
{ {
char iv_prefix[16] = {0}; char iv_prefix[16] = {0};
uint32 data_len = tuple->t_len - tuple->t_data->t_hoff; uint32 data_len = tuple->t_len - tuple->t_data->t_hoff;
char *tup_data = (char*)tuple->t_data + tuple->t_data->t_hoff; char *tup_data = (char *) tuple->t_data + tuple->t_data->t_hoff;
char *out_data = (char*)out_tuple->t_data + out_tuple->t_data->t_hoff; char *out_data = (char *) out_tuple->t_data + out_tuple->t_data->t_hoff;
SetIVPrefix(&tuple->t_self, iv_prefix); SetIVPrefix(&tuple->t_self, iv_prefix);
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
ereport(LOG, ereport(LOG,
(errmsg("%s: table Oid: %u data size: %u", (errmsg("%s: table Oid: %u data size: %u",
context?context:"", tuple->t_tableOid, context ? context : "", tuple->t_tableOid,
data_len))); data_len)));
#endif #endif
pg_tde_crypt(iv_prefix, 0, tup_data, data_len, out_data, key, context); pg_tde_crypt(iv_prefix, 0, tup_data, data_len, out_data, key, context);
} }
// ================================================================ /* ================================================================ */
// HELPER FUNCTIONS FOR ENCRYPTION /* HELPER FUNCTIONS FOR ENCRYPTION */
// ================================================================ /* ================================================================ */
OffsetNumber OffsetNumber
PGTdePageAddItemExtended(RelFileLocator rel, PGTdePageAddItemExtended(RelFileLocator rel,
Oid oid, Oid oid,
BlockNumber bn, BlockNumber bn,
Page page, Page page,
Item item, Item item,
Size size, Size size,
OffsetNumber offsetNumber, OffsetNumber offsetNumber,
int flags) int flags)
{ {
OffsetNumber off = PageAddItemExtended(page,item,size,offsetNumber,flags); OffsetNumber off = PageAddItemExtended(page, item, size, offsetNumber, flags);
PageHeader phdr = (PageHeader) page; PageHeader phdr = (PageHeader) page;
unsigned long header_size = ((HeapTupleHeader)item)->t_hoff; unsigned long header_size = ((HeapTupleHeader) item)->t_hoff;
char iv_prefix[16] = {0,}; char iv_prefix[16] = {0,};
char* toAddr = ((char*)phdr) + phdr->pd_upper + header_size; char *toAddr = ((char *) phdr) + phdr->pd_upper + header_size;
char* data = item + header_size; char *data = item + header_size;
uint32 data_len = size - header_size; uint32 data_len = size - header_size;
/* ctid stored in item is incorrect (not set) at this point */ /* ctid stored in item is incorrect (not set) at this point */
ItemPointerData ip; ItemPointerData ip;
RelKeyData *key = GetHeapBaiscRelationKey(rel); RelKeyData *key = GetHeapBaiscRelationKey(rel);
ItemPointerSet(&ip, bn, off); ItemPointerSet(&ip, bn, off);
SetIVPrefix(&ip, iv_prefix); SetIVPrefix(&ip, iv_prefix);
@ -234,21 +243,21 @@ PGTdePageAddItemExtended(RelFileLocator rel,
void void
AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData *rel_key_data, RelKeyData **p_enc_rel_key_data, size_t *enc_key_bytes) AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData *rel_key_data, RelKeyData **p_enc_rel_key_data, size_t *enc_key_bytes)
{ {
unsigned char iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* Ensure we are getting a valid pointer here */ /* Ensure we are getting a valid pointer here */
Assert(principal_key); Assert(principal_key);
memcpy(iv, &rlocator->spcOid, sizeof(Oid)); memcpy(iv, &rlocator->spcOid, sizeof(Oid));
memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid)); memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid));
*p_enc_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData)); *p_enc_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData));
memcpy(*p_enc_rel_key_data, rel_key_data, sizeof(RelKeyData)); memcpy(*p_enc_rel_key_data, rel_key_data, sizeof(RelKeyData));
AesEncrypt(principal_key->keyData, iv, ((unsigned char*)&rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *)&(*p_enc_rel_key_data)->internal_key), (int *)enc_key_bytes); AesEncrypt(principal_key->keyData, iv, ((unsigned char *) &rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *) &(*p_enc_rel_key_data)->internal_key), (int *) enc_key_bytes);
} }
#endif /* FRONTEND */ #endif /* FRONTEND */
/* /*
* Provide a simple interface to decrypt a given key. * Provide a simple interface to decrypt a given key.
@ -257,31 +266,32 @@ AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocat
* to note that memory is allocated in the TopMemoryContext so we expect this to be added * to note that memory is allocated in the TopMemoryContext so we expect this to be added
* to our key cache. * to our key cache.
*/ */
void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes) void
AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes)
{ {
unsigned char iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* Ensure we are getting a valid pointer here */ /* Ensure we are getting a valid pointer here */
Assert(principal_key); Assert(principal_key);
memcpy(iv, &rlocator->spcOid, sizeof(Oid)); memcpy(iv, &rlocator->spcOid, sizeof(Oid));
memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid)); memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid));
#ifndef FRONTEND #ifndef FRONTEND
MemoryContext oldcontext; MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(TopMemoryContext); oldcontext = MemoryContextSwitchTo(TopMemoryContext);
#endif #endif
*p_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData)); *p_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData));
#ifndef FRONTEND #ifndef FRONTEND
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
#endif #endif
/* Fill in the structure */ /* Fill in the structure */
memcpy(*p_rel_key_data, enc_rel_key_data, sizeof(RelKeyData)); memcpy(*p_rel_key_data, enc_rel_key_data, sizeof(RelKeyData));
(*p_rel_key_data)->internal_key.ctx = NULL; (*p_rel_key_data)->internal_key.ctx = NULL;
AesDecrypt(principal_key->keyData, iv, ((unsigned char*) &enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *)&(*p_rel_key_data)->internal_key) , (int *)key_bytes); AesDecrypt(principal_key->keyData, iv, ((unsigned char *) &enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *) &(*p_rel_key_data)->internal_key), (int *) key_bytes);
} }

@ -14,4 +14,4 @@
extern void SetupTdeDDLHooks(void); extern void SetupTdeDDLHooks(void);
#endif /* PG_TDE_DDL_H */ #endif /* PG_TDE_DDL_H */

@ -29,8 +29,8 @@ typedef struct TDEBufferHeapTupleTableSlot
* reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set in * reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set in
* such a case, since presumably base.tuple is pointing into the buffer.) * such a case, since presumably base.tuple is pointing into the buffer.)
*/ */
Buffer buffer; /* tuple's buffer, or InvalidBuffer */ Buffer buffer; /* tuple's buffer, or InvalidBuffer */
char decrypted_buffer[BLCKSZ]; char decrypted_buffer[BLCKSZ];
RelKeyData *cached_relation_key; RelKeyData *cached_relation_key;
} TDEBufferHeapTupleTableSlot; } TDEBufferHeapTupleTableSlot;
@ -39,12 +39,12 @@ extern PGDLLIMPORT const TupleTableSlotOps TTSOpsTDEBufferHeapTuple;
#define TTS_IS_TDE_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsTDEBufferHeapTuple) #define TTS_IS_TDE_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsTDEBufferHeapTuple)
extern TupleTableSlot *PGTdeExecStorePinnedBufferHeapTuple(Relation rel, extern TupleTableSlot *PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
HeapTuple tuple, HeapTuple tuple,
TupleTableSlot *slot, TupleTableSlot *slot,
Buffer buffer); Buffer buffer);
extern TupleTableSlot *PGTdeExecStoreBufferHeapTuple(Relation rel, extern TupleTableSlot *PGTdeExecStoreBufferHeapTuple(Relation rel,
HeapTuple tuple, HeapTuple tuple,
TupleTableSlot *slot, TupleTableSlot *slot,
Buffer buffer); Buffer buffer);
#endif /* PG_TDE_SLOT_H */ #endif /* PG_TDE_SLOT_H */

@ -18,7 +18,7 @@
#define MAP_ENTRY_EMPTY 0x00 #define MAP_ENTRY_EMPTY 0x00
#define TDE_KEY_TYPE_HEAP_BASIC 0x01 #define TDE_KEY_TYPE_HEAP_BASIC 0x01
#define TDE_KEY_TYPE_SMGR 0x02 #define TDE_KEY_TYPE_SMGR 0x02
#define TDE_KEY_TYPE_GLOBAL 0x04 #define TDE_KEY_TYPE_GLOBAL 0x04
#define MAP_ENTRY_VALID (TDE_KEY_TYPE_HEAP_BASIC | TDE_KEY_TYPE_SMGR | TDE_KEY_TYPE_GLOBAL) #define MAP_ENTRY_VALID (TDE_KEY_TYPE_HEAP_BASIC | TDE_KEY_TYPE_SMGR | TDE_KEY_TYPE_GLOBAL)
typedef struct InternalKey typedef struct InternalKey
@ -37,8 +37,8 @@ typedef struct InternalKey
typedef struct RelKeyData typedef struct RelKeyData
{ {
TDEPrincipalKeyId principal_key_id; TDEPrincipalKeyId principal_key_id;
InternalKey internal_key; InternalKey internal_key;
} RelKeyData; } RelKeyData;
@ -76,8 +76,8 @@ extern bool pg_tde_move_rel_key(const RelFileLocator *newrlocator, const RelFile
extern void pg_tde_set_db_file_paths(Oid dbOid, Oid spcOid, char *map_path, char *keydata_path); extern void pg_tde_set_db_file_paths(Oid dbOid, Oid spcOid, char *map_path, char *keydata_path);
const char * tde_sprint_key(InternalKey *k); const char *tde_sprint_key(InternalKey *k);
extern RelKeyData *pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key); extern RelKeyData *pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key);
#endif /*PG_TDE_MAP_H*/ #endif /* PG_TDE_MAP_H */

@ -38,5 +38,5 @@ static const RmgrData tdeheap_rmgr = {
.rm_identify = tdeheap_rmgr_identify .rm_identify = tdeheap_rmgr_identify
}; };
#endif /* !FRONTEND */ #endif /* !FRONTEND */
#endif /* PG_TDE_XLOG_H */ #endif /* PG_TDE_XLOG_H */

@ -30,6 +30,6 @@ static const XLogSmgr tde_xlog_smgr = {
extern void TDEXLogSmgrInit(void); extern void TDEXLogSmgrInit(void);
extern void XLogInitGUC(void); extern void XLogInitGUC(void);
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */
#endif /* PG_TDE_XLOGENCRYPT_H */ #endif /* PG_TDE_XLOGENCRYPT_H */

@ -24,6 +24,6 @@
TDEInitGlobalKeys(kring_dir); \ TDEInitGlobalKeys(kring_dir); \
TDEXLogSmgrInit() TDEXLogSmgrInit()
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */
#endif /* PG_TDE_XLOGENCRYPT_FE_H */ #endif /* PG_TDE_XLOGENCRYPT_FE_H */

@ -34,4 +34,4 @@
extern void TDEInitGlobalKeys(const char *dir); extern void TDEInitGlobalKeys(const char *dir);
#endif /* TDE_GLOBAL_CATALOG_H */ #endif /* TDE_GLOBAL_CATALOG_H */

@ -22,34 +22,35 @@
#define FILE_KEYRING_TYPE "file" #define FILE_KEYRING_TYPE "file"
#define VAULTV2_KEYRING_TYPE "vault-v2" #define VAULTV2_KEYRING_TYPE "vault-v2"
#define MAX_PROVIDER_NAME_LEN 128 /* pg_tde_key_provider's provider_name size*/ #define MAX_PROVIDER_NAME_LEN 128 /* pg_tde_key_provider's provider_name
#define MAX_VAULT_V2_KEY_LEN 128 /* From hashi corp docs */ * size */
#define MAX_KEYRING_OPTION_LEN 1024 #define MAX_VAULT_V2_KEY_LEN 128 /* From hashi corp docs */
#define MAX_KEYRING_OPTION_LEN 1024
typedef enum ProviderType typedef enum ProviderType
{ {
UNKNOWN_KEY_PROVIDER, UNKNOWN_KEY_PROVIDER,
FILE_KEY_PROVIDER, FILE_KEY_PROVIDER,
VAULT_V2_KEY_PROVIDER, VAULT_V2_KEY_PROVIDER,
} ProviderType; } ProviderType;
/* Base type for all keyring */ /* Base type for all keyring */
typedef struct GenericKeyring typedef struct GenericKeyring
{ {
ProviderType type; /* Must be the first field */ ProviderType type; /* Must be the first field */
Oid key_id; Oid key_id;
char provider_name[MAX_PROVIDER_NAME_LEN]; char provider_name[MAX_PROVIDER_NAME_LEN];
char options[MAX_KEYRING_OPTION_LEN]; /* User provided options string*/ char options[MAX_KEYRING_OPTION_LEN]; /* User provided options string */
} GenericKeyring; } GenericKeyring;
typedef struct FileKeyring typedef struct FileKeyring
{ {
GenericKeyring keyring; /* Must be the first field */ GenericKeyring keyring; /* Must be the first field */
char file_name[MAXPGPATH]; char file_name[MAXPGPATH];
} FileKeyring; } FileKeyring;
typedef struct VaultV2Keyring typedef struct VaultV2Keyring
{ {
GenericKeyring keyring; /* Must be the first field */ GenericKeyring keyring; /* Must be the first field */
char vault_token[MAX_VAULT_V2_KEY_LEN]; char vault_token[MAX_VAULT_V2_KEY_LEN];
char vault_url[MAXPGPATH]; char vault_url[MAXPGPATH];
char vault_ca_path[MAXPGPATH]; char vault_ca_path[MAXPGPATH];
@ -59,15 +60,15 @@ typedef struct VaultV2Keyring
/* This record goes into key provider info file */ /* This record goes into key provider info file */
typedef struct KeyringProvideRecord typedef struct KeyringProvideRecord
{ {
int provider_id; int provider_id;
char provider_name[MAX_PROVIDER_NAME_LEN]; char provider_name[MAX_PROVIDER_NAME_LEN];
char options[MAX_KEYRING_OPTION_LEN]; char options[MAX_KEYRING_OPTION_LEN];
ProviderType provider_type; ProviderType provider_type;
} KeyringProvideRecord; } KeyringProvideRecord;
typedef struct KeyringProviderXLRecord typedef struct KeyringProviderXLRecord
{ {
Oid database_id; Oid database_id;
Oid tablespace_id; Oid tablespace_id;
off_t offset_in_file; off_t offset_in_file;
KeyringProvideRecord provider; KeyringProvideRecord provider;
} KeyringProviderXLRecord; } KeyringProviderXLRecord;
@ -87,5 +88,5 @@ extern uint32 copy_key_provider_info(KeyringProvideRecord* provider,
extern uint32 redo_key_provider_info(KeyringProviderXLRecord *xlrec); extern uint32 redo_key_provider_info(KeyringProviderXLRecord *xlrec);
extern bool ParseKeyringJSONOptions(ProviderType provider_type, void *out_opts, extern bool ParseKeyringJSONOptions(ProviderType provider_type, void *out_opts,
char *in_buf, int buf_len); char *in_buf, int buf_len);
#endif /*TDE_KEYRING_H*/ #endif /* TDE_KEYRING_H */

@ -19,23 +19,23 @@
#include "storage/lwlock.h" #include "storage/lwlock.h"
#endif #endif
#define DEFAULT_PRINCIPAL_KEY_VERSION 1 #define DEFAULT_PRINCIPAL_KEY_VERSION 1
#define PRINCIPAL_KEY_NAME_LEN TDE_KEY_NAME_LEN #define PRINCIPAL_KEY_NAME_LEN TDE_KEY_NAME_LEN
#define MAX_PRINCIPAL_KEY_VERSION_NUM 100000 #define MAX_PRINCIPAL_KEY_VERSION_NUM 100000
typedef struct TDEPrincipalKeyId typedef struct TDEPrincipalKeyId
{ {
uint32 version; uint32 version;
char name[PRINCIPAL_KEY_NAME_LEN]; char name[PRINCIPAL_KEY_NAME_LEN];
char versioned_name[PRINCIPAL_KEY_NAME_LEN + 4]; char versioned_name[PRINCIPAL_KEY_NAME_LEN + 4];
} TDEPrincipalKeyId; } TDEPrincipalKeyId;
typedef struct TDEPrincipalKeyInfo typedef struct TDEPrincipalKeyInfo
{ {
Oid databaseId; Oid databaseId;
Oid tablespaceId; Oid tablespaceId;
Oid userId; Oid userId;
Oid keyringId; Oid keyringId;
struct timeval creationTime; struct timeval creationTime;
TDEPrincipalKeyId keyId; TDEPrincipalKeyId keyId;
} TDEPrincipalKeyInfo; } TDEPrincipalKeyInfo;
@ -52,7 +52,7 @@ typedef struct XLogPrincipalKeyRotate
Oid databaseId; Oid databaseId;
off_t map_size; off_t map_size;
off_t keydata_size; off_t keydata_size;
char buff[FLEXIBLE_ARRAY_MEMBER]; char buff[FLEXIBLE_ARRAY_MEMBER];
} XLogPrincipalKeyRotate; } XLogPrincipalKeyRotate;
#define SizeoOfXLogPrincipalKeyRotate offsetof(XLogPrincipalKeyRotate, buff) #define SizeoOfXLogPrincipalKeyRotate offsetof(XLogPrincipalKeyRotate, buff)
@ -62,16 +62,16 @@ extern void cleanup_principal_key_info(Oid databaseId, Oid tablespaceId);
#ifndef FRONTEND #ifndef FRONTEND
extern LWLock *tde_lwlock_enc_keys(void); extern LWLock *tde_lwlock_enc_keys(void);
extern TDEPrincipalKey* GetPrincipalKey(Oid dbOid, Oid spcOid, LWLockMode lockMode); extern TDEPrincipalKey *GetPrincipalKey(Oid dbOid, Oid spcOid, LWLockMode lockMode);
#else #else
extern TDEPrincipalKey* GetPrincipalKey(Oid dbOid, Oid spcOid, void *lockMode); extern TDEPrincipalKey *GetPrincipalKey(Oid dbOid, Oid spcOid, void *lockMode);
#endif #endif
extern bool save_principal_key_info(TDEPrincipalKeyInfo *principalKeyInfo); extern bool save_principal_key_info(TDEPrincipalKeyInfo *principalKeyInfo);
extern Oid GetPrincipalKeyProviderId(void); extern Oid GetPrincipalKeyProviderId(void);
extern bool SetPrincipalKey(const char *key_name, const char *provider_name, bool ensure_new_key); extern bool SetPrincipalKey(const char *key_name, const char *provider_name, bool ensure_new_key);
extern bool RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const char *new_provider_name, bool ensure_new_key); extern bool RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const char *new_provider_name, bool ensure_new_key);
extern bool xl_tde_perform_rotate_key(XLogPrincipalKeyRotate *xlrec); extern bool xl_tde_perform_rotate_key(XLogPrincipalKeyRotate *xlrec);
#endif /*PG_TDE_PRINCIPAL_KEY_H*/ #endif /* PG_TDE_PRINCIPAL_KEY_H */

@ -18,43 +18,46 @@
typedef enum typedef enum
{ {
TDE_LWLOCK_ENC_KEY, TDE_LWLOCK_ENC_KEY,
TDE_LWLOCK_PI_FILES, TDE_LWLOCK_PI_FILES,
/* Must be the last entry in the enum */ /* Must be the last entry in the enum */
TDE_LWLOCK_COUNT TDE_LWLOCK_COUNT
} TDELockTypes; } TDELockTypes;
typedef struct TDEShmemSetupRoutine typedef struct TDEShmemSetupRoutine
{ {
/* init_shared_state gets called at the time of extension load /*
* you can initialize the data structures required to be placed in * init_shared_state gets called at the time of extension load you can
* shared memory in this callback * initialize the data structures required to be placed in shared memory
* The callback must return the size of the shared memory area acquired. * in this callback The callback must return the size of the shared memory
* The argument to the function is the start of the shared memory address * area acquired. The argument to the function is the start of the shared
* that can be used to store the shared data structures. * memory address that can be used to store the shared data structures.
*/ */
Size (*init_shared_state)(void *raw_dsa_area); Size (*init_shared_state) (void *raw_dsa_area);
/*
* shmem_startup gets called at the time of postmaster shutdown /*
*/ * shmem_startup gets called at the time of postmaster shutdown
void (*shmem_kill)(int code, Datum arg); */
/* void (*shmem_kill) (int code, Datum arg);
* The callback must return the size of the shared memory acquired.
*/ /*
Size (*required_shared_mem_size)(void); * The callback must return the size of the shared memory acquired.
/* */
* Gets called after all shared memory structures are initialized and Size (*required_shared_mem_size) (void);
* here you can create shared memory hash tables or any other shared
* objects that needs to live in DSA area. /*
*/ * Gets called after all shared memory structures are initialized and here
void (*init_dsa_area_objects)(dsa_area *dsa, void *raw_dsa_area); * you can create shared memory hash tables or any other shared objects
* that needs to live in DSA area.
*/
void (*init_dsa_area_objects) (dsa_area *dsa, void *raw_dsa_area);
} TDEShmemSetupRoutine; } TDEShmemSetupRoutine;
/* Interface to register the shared memory requests */ /* Interface to register the shared memory requests */
extern void RegisterShmemRequest(const TDEShmemSetupRoutine *routine); extern void RegisterShmemRequest(const TDEShmemSetupRoutine *routine);
extern void TdeShmemInit(void); extern void TdeShmemInit(void);
extern Size TdeRequiredSharedMemorySize(void); extern Size TdeRequiredSharedMemorySize(void);
extern int TdeRequiredLocksCount(void); extern int TdeRequiredLocksCount(void);
#endif /*PG_TDE_SHMEM_H*/ #endif /* PG_TDE_SHMEM_H */

@ -13,12 +13,12 @@
#ifndef FRONTEND #ifndef FRONTEND
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
extern Oid get_tde_basic_table_am_oid(void); extern Oid get_tde_basic_table_am_oid(void);
extern Oid get_tde_table_am_oid(void); extern Oid get_tde_table_am_oid(void);
extern List *get_all_tde_tables(void); extern List *get_all_tde_tables(void);
extern int get_tde_tables_count(void); extern int get_tde_tables_count(void);
#endif /* !FRONTEND */ #endif /* !FRONTEND */
extern char *pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid); extern char *pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid);
extern void pg_tde_set_globalspace_dir(const char *dir); extern void pg_tde_set_globalspace_dir(const char *dir);
#endif /*PG_TDE_UTILS_H*/ #endif /* PG_TDE_UTILS_H */

@ -17,10 +17,10 @@
#define DATA_BYTES_PER_AES_BATCH (NUM_AES_BLOCKS_IN_BATCH * AES_BLOCK_SIZE) #define DATA_BYTES_PER_AES_BATCH (NUM_AES_BLOCKS_IN_BATCH * AES_BLOCK_SIZE)
void AesInit(void); void AesInit(void);
extern void Aes128EncryptedZeroBlocks(void* ctxPtr, const unsigned char* key, const char* iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char* out); extern void Aes128EncryptedZeroBlocks(void *ctxPtr, const unsigned char *key, const char *iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char *out);
/* Only used for testing */ /* Only used for testing */
extern void AesEncrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len); extern void AesEncrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len);
extern void AesDecrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len); extern void AesDecrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len);
#endif /*ENC_AES_H*/ #endif /* ENC_AES_H */

@ -18,17 +18,17 @@
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
extern void extern void
pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint32 data_len, char* out, RelKeyData* key, const char* context); pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, const char *context);
extern void extern void
pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData* key, const char* context); pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData *key, const char *context);
/* A wrapper to encrypt a tuple before adding it to the buffer */ /* A wrapper to encrypt a tuple before adding it to the buffer */
extern OffsetNumber extern OffsetNumber
PGTdePageAddItemExtended(RelFileLocator rel, Oid oid, BlockNumber bn, Page page, PGTdePageAddItemExtended(RelFileLocator rel, Oid oid, BlockNumber bn, Page page,
Item item, Item item,
Size size, Size size,
OffsetNumber offsetNumber, OffsetNumber offsetNumber,
int flags); int flags);
/* Function Macros over crypt */ /* Function Macros over crypt */
@ -55,4 +55,4 @@ PGTdePageAddItemExtended(RelFileLocator rel, Oid oid, BlockNumber bn, Page page,
extern void AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData *rel_key_data, RelKeyData **p_enc_rel_key_data, size_t *enc_key_bytes); extern void AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData *rel_key_data, RelKeyData **p_enc_rel_key_data, size_t *enc_key_bytes);
extern void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes); extern void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes);
#endif /*ENC_TDE_H*/ #endif /* ENC_TDE_H */

@ -12,7 +12,7 @@
#include "catalog/tde_keyring.h" #include "catalog/tde_keyring.h"
#define TDE_KEY_NAME_LEN 256 #define TDE_KEY_NAME_LEN 256
#define MAX_KEY_DATA_SIZE 32 /* maximum 256 bit encryption */ #define MAX_KEY_DATA_SIZE 32 /* maximum 256 bit encryption */
#define INTERNAL_KEY_LEN 16 #define INTERNAL_KEY_LEN 16
typedef struct keyName typedef struct keyName
@ -28,8 +28,8 @@ typedef struct keyData
typedef struct keyInfo typedef struct keyInfo
{ {
keyName name; keyName name;
keyData data; keyData data;
} keyInfo; } keyInfo;
typedef enum KeyringReturnCodes typedef enum KeyringReturnCodes
@ -46,14 +46,14 @@ typedef enum KeyringReturnCodes
typedef struct TDEKeyringRoutine typedef struct TDEKeyringRoutine
{ {
keyInfo *(*keyring_get_key)(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *returnCode); keyInfo *(*keyring_get_key) (GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode);
KeyringReturnCodes (*keyring_store_key)(GenericKeyring *keyring, keyInfo *key, bool throw_error); KeyringReturnCodes(*keyring_store_key) (GenericKeyring *keyring, keyInfo *key, bool throw_error);
} TDEKeyringRoutine; } TDEKeyringRoutine;
extern bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type); extern bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type);
extern KeyringReturnCodes KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error); extern KeyringReturnCodes KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error);
extern keyInfo *KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *returnCode); extern keyInfo *KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode);
extern keyInfo *KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error); extern keyInfo *KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error);
extern keyInfo *KeyringGenerateNewKey(const char *key_name, unsigned key_len); extern keyInfo *KeyringGenerateNewKey(const char *key_name, unsigned key_len);

@ -19,13 +19,14 @@
#include <stdbool.h> #include <stdbool.h>
#include <curl/curl.h> #include <curl/curl.h>
typedef struct CurlString { typedef struct CurlString
char *ptr; {
size_t len; char *ptr;
size_t len;
} CurlString; } CurlString;
extern CURL* keyringCurl; extern CURL * keyringCurl;
bool curlSetupSession(const char* url, const char* caFile, CurlString* outStr); bool curlSetupSession(const char *url, const char *caFile, CurlString *outStr);
#endif //KEYRING_CURL_H #endif /* //KEYRING_CURL_H */

@ -14,4 +14,4 @@
extern bool InstallFileKeyring(void); extern bool InstallFileKeyring(void);
#endif /*KEYRING_FILE_H*/ #endif /* KEYRING_FILE_H */

@ -14,4 +14,4 @@
extern bool InstallVaultV2Keyring(void); extern bool InstallVaultV2Keyring(void);
#endif // KEYRING_FILE_H #endif /* KEYRING_FILE_H */

@ -10,13 +10,13 @@
typedef struct XLogExtensionInstall typedef struct XLogExtensionInstall
{ {
Oid database_id; Oid database_id;
Oid tablespace_id; Oid tablespace_id;
} XLogExtensionInstall; } XLogExtensionInstall;
typedef void (*pg_tde_on_ext_install_callback)(int tde_tbl_count, XLogExtensionInstall* ext_info, bool redo, void *arg); typedef void (*pg_tde_on_ext_install_callback) (int tde_tbl_count, XLogExtensionInstall *ext_info, bool redo, void *arg);
extern void on_ext_install(pg_tde_on_ext_install_callback function, void* arg); extern void on_ext_install(pg_tde_on_ext_install_callback function, void *arg);
extern void extension_install_redo(XLogExtensionInstall *xlrec); extern void extension_install_redo(XLogExtensionInstall *xlrec);
#endif /*PG_TDE_H*/ #endif /* PG_TDE_H */

@ -19,10 +19,10 @@
* ---------- * ----------
*/ */
//#define ENCRYPTION_DEBUG 1 /* #define ENCRYPTION_DEBUG 1 */
//#define KEYRING_DEBUG 1 /* #define KEYRING_DEBUG 1 */
//#define TDE_FORK_DEBUG 1 /* #define TDE_FORK_DEBUG 1 */
// #define TDE_XLOG_DEBUG 1 /* #define TDE_XLOG_DEBUG 1 */
#define tdeheap_fill_tuple heap_fill_tuple #define tdeheap_fill_tuple heap_fill_tuple
#define tdeheap_form_tuple heap_form_tuple #define tdeheap_form_tuple heap_form_tuple
@ -47,4 +47,4 @@
/* ---------- */ /* ---------- */
#endif /* PG_TDE_DEFINES_H */ #endif /* PG_TDE_DEFINES_H */

@ -13,4 +13,4 @@ extern const char *pg_tde_package_string(void);
extern const char *pg_tde_package_name(void); extern const char *pg_tde_package_name(void);
extern const char *pg_tde_package_version(void); extern const char *pg_tde_package_version(void);
#endif /*PG_TDE_DEFS_H*/ #endif /* PG_TDE_DEFS_H */

@ -15,19 +15,19 @@ typedef enum TdeCreateEventType
TDE_UNKNOWN_CREATE_EVENT, TDE_UNKNOWN_CREATE_EVENT,
TDE_TABLE_CREATE_EVENT, TDE_TABLE_CREATE_EVENT,
TDE_INDEX_CREATE_EVENT TDE_INDEX_CREATE_EVENT
} TdeCreateEventType; } TdeCreateEventType;
typedef struct TdeCreateEvent typedef struct TdeCreateEvent
{ {
TdeCreateEventType eventType; /* DDL statement type */ TdeCreateEventType eventType; /* DDL statement type */
bool encryptMode; /* true when the table uses encryption */ bool encryptMode; /* true when the table uses encryption */
Oid baseTableOid; /* Oid of table on which index is being Oid baseTableOid; /* Oid of table on which index is being
* created on. For create table statement this * created on. For create table statement this
* contains InvalidOid */ * contains InvalidOid */
RangeVar *relation; /* Reference to the parsed relation from RangeVar *relation; /* Reference to the parsed relation from
* create statement */ * create statement */
} TdeCreateEvent; } TdeCreateEvent;
extern TdeCreateEvent * GetCurrentTdeCreateEvent(void); extern TdeCreateEvent *GetCurrentTdeCreateEvent(void);
#endif #endif

@ -12,4 +12,4 @@
extern void RegisterStorageMgr(void); extern void RegisterStorageMgr(void);
#endif /* PG_TDE_SMGR_H */ #endif /* PG_TDE_SMGR_H */

@ -13,9 +13,9 @@
extern void pg_tde_xact_callback(XactEvent event, void *arg); extern void pg_tde_xact_callback(XactEvent event, void *arg);
extern void pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid, extern void pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
SubTransactionId parentSubid, void *arg); SubTransactionId parentSubid, void *arg);
extern void RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit); extern void RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit);
#endif /* PG_TDE_XACT_HANDLER_H */ #endif /* PG_TDE_XACT_HANDLER_H */

@ -34,9 +34,11 @@ static KeyProviders *
find_key_provider(ProviderType type) find_key_provider(ProviderType type)
{ {
ListCell *lc; ListCell *lc;
foreach (lc, registeredKeyProviders)
foreach(lc, registeredKeyProviders)
{ {
KeyProviders *kp = (KeyProviders *)lfirst(lc); KeyProviders *kp = (KeyProviders *) lfirst(lc);
if (kp->type == type) if (kp->type == type)
{ {
return kp; return kp;
@ -49,9 +51,11 @@ static KeyProviders *
find_key_provider(ProviderType type) find_key_provider(ProviderType type)
{ {
SimplePtrListCell *lc; SimplePtrListCell *lc;
for (lc = registeredKeyProviders.head; lc; lc = lc->next) for (lc = registeredKeyProviders.head; lc; lc = lc->next)
{ {
KeyProviders *kp = (KeyProviders *) lc->ptr; KeyProviders *kp = (KeyProviders *) lc->ptr;
if (kp->type == type) if (kp->type == type)
{ {
return kp; return kp;
@ -59,9 +63,10 @@ find_key_provider(ProviderType type)
} }
return NULL; return NULL;
} }
#endif /* !FRONTEND */ #endif /* !FRONTEND */
bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type) bool
RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
{ {
KeyProviders *kp; KeyProviders *kp;
@ -79,10 +84,11 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
#ifndef FRONTEND #ifndef FRONTEND
MemoryContext oldcontext; MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(TopMemoryContext); oldcontext = MemoryContextSwitchTo(TopMemoryContext);
#endif #endif
kp = palloc(sizeof(KeyProviders)); kp = palloc(sizeof(KeyProviders));
kp->routine = (TDEKeyringRoutine *)routine; kp->routine = (TDEKeyringRoutine *) routine;
kp->type = type; kp->type = type;
#ifndef FRONTEND #ifndef FRONTEND
registeredKeyProviders = lappend(registeredKeyProviders, kp); registeredKeyProviders = lappend(registeredKeyProviders, kp);
@ -95,9 +101,10 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
} }
keyInfo * keyInfo *
KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *returnCode) KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode)
{ {
KeyProviders *kp = find_key_provider(keyring->type); KeyProviders *kp = find_key_provider(keyring->type);
if (kp == NULL) if (kp == NULL)
{ {
ereport(throw_error ? ERROR : WARNING, ereport(throw_error ? ERROR : WARNING,
@ -112,6 +119,7 @@ KeyringReturnCodes
KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error) KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{ {
KeyProviders *kp = find_key_provider(keyring->type); KeyProviders *kp = find_key_provider(keyring->type);
if (kp == NULL) if (kp == NULL)
{ {
ereport(throw_error ? ERROR : WARNING, ereport(throw_error ? ERROR : WARNING,
@ -125,13 +133,14 @@ keyInfo *
KeyringGenerateNewKey(const char *key_name, unsigned key_len) KeyringGenerateNewKey(const char *key_name, unsigned key_len)
{ {
keyInfo *key; keyInfo *key;
Assert(key_len <= 32); Assert(key_len <= 32);
key = palloc(sizeof(keyInfo)); key = palloc(sizeof(keyInfo));
key->data.len = key_len; key->data.len = key_len;
if (!RAND_bytes(key->data.data, key_len)) if (!RAND_bytes(key->data.data, key_len))
{ {
pfree(key); pfree(key);
return NULL; /*openssl error*/ return NULL; /* openssl error */
} }
strncpy(key->name.name, key_name, sizeof(key->name.name)); strncpy(key->name.name, key_name, sizeof(key->name.name));
return key; return key;
@ -141,6 +150,7 @@ keyInfo *
KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error) KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error)
{ {
keyInfo *key = KeyringGenerateNewKey(key_name, key_len); keyInfo *key = KeyringGenerateNewKey(key_name, key_len);
if (key == NULL) if (key == NULL)
{ {
ereport(throw_error ? ERROR : WARNING, ereport(throw_error ? ERROR : WARNING,

@ -14,50 +14,69 @@
#include "keyring/keyring_curl.h" #include "keyring/keyring_curl.h"
#include "pg_tde_defines.h" #include "pg_tde_defines.h"
CURL* keyringCurl = NULL; CURL *keyringCurl = NULL;
static static
size_t write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s) size_t
write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s)
{ {
size_t new_len = s->len + size*nmemb; size_t new_len = s->len + size * nmemb;
s->ptr = repalloc(s->ptr, new_len+1);
if (s->ptr == NULL) { s->ptr = repalloc(s->ptr, new_len + 1);
if (s->ptr == NULL)
{
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
memcpy(s->ptr+s->len, ptr, size*nmemb); memcpy(s->ptr + s->len, ptr, size * nmemb);
s->ptr[new_len] = '\0'; s->ptr[new_len] = '\0';
s->len = new_len; s->len = new_len;
return size*nmemb; return size * nmemb;
} }
bool curlSetupSession(const char* url, const char* caFile, CurlString* outStr) bool
curlSetupSession(const char *url, const char *caFile, CurlString *outStr)
{ {
if(keyringCurl == NULL) if (keyringCurl == NULL)
{ {
keyringCurl = curl_easy_init(); keyringCurl = curl_easy_init();
if(keyringCurl == NULL) return 0; if (keyringCurl == NULL)
} else { return 0;
curl_easy_reset(keyringCurl); }
} else
{
curl_easy_reset(keyringCurl);
}
if(curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK) return 0; return 0;
if(caFile != NULL && strlen(caFile) != 0) if (curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK)
return 0;
if (caFile != NULL && strlen(caFile) != 0)
{ {
if(curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK)
return 0;
} }
if(curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK) return 0; return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION,(long)CURL_HTTP_VERSION_1_1) != CURLE_OK) return 0; return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION,write_func) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA,outStr) != CURLE_OK) return 0; return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_1_1) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION, write_func) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA, outStr) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK)
return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK) return 0; return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK)
return 0;
return 1; return 1;
} }

@ -26,8 +26,8 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static keyInfo* get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error, KeyringReturnCodes *return_code); static keyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code);
static KeyringReturnCodes set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error); static KeyringReturnCodes set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error);
const TDEKeyringRoutine keyringFileRoutine = { const TDEKeyringRoutine keyringFileRoutine = {
.keyring_get_key = get_key_by_name, .keyring_get_key = get_key_by_name,
@ -41,12 +41,12 @@ InstallFileKeyring(void)
} }
static keyInfo* static keyInfo *
get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error, KeyringReturnCodes *return_code) get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code)
{ {
keyInfo* key = NULL; keyInfo *key = NULL;
int fd = -1; int fd = -1;
FileKeyring* file_keyring = (FileKeyring*)keyring; FileKeyring *file_keyring = (FileKeyring *) keyring;
off_t bytes_read = 0; off_t bytes_read = 0;
off_t curr_pos = 0; off_t curr_pos = 0;
@ -57,15 +57,16 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
return NULL; return NULL;
key = palloc(sizeof(keyInfo)); key = palloc(sizeof(keyInfo));
while(true) while (true)
{ {
bytes_read = pg_pread(fd, key, sizeof(keyInfo), curr_pos); bytes_read = pg_pread(fd, key, sizeof(keyInfo), curr_pos);
curr_pos += bytes_read; curr_pos += bytes_read;
if (bytes_read == 0 ) if (bytes_read == 0)
{ {
/* /*
* Empty keyring file is considered as a valid keyring file that has no keys * Empty keyring file is considered as a valid keyring file that
* has no keys
*/ */
close(fd); close(fd);
pfree(key); pfree(key);
@ -77,11 +78,11 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
pfree(key); pfree(key);
/* Corrupt file */ /* Corrupt file */
*return_code = KEYRING_CODE_DATA_CORRUPTED; *return_code = KEYRING_CODE_DATA_CORRUPTED;
ereport(throw_error?ERROR:WARNING, ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("keyring file \"%s\" is corrupted: %m", errmsg("keyring file \"%s\" is corrupted: %m",
file_keyring->file_name), file_keyring->file_name),
errdetail("invalid key size %llu expected %lu", bytes_read, sizeof(keyInfo)))); errdetail("invalid key size %llu expected %lu", bytes_read, sizeof(keyInfo))));
return NULL; return NULL;
} }
if (strncasecmp(key->name.name, key_name, sizeof(key->name.name)) == 0) if (strncasecmp(key->name.name, key_name, sizeof(key->name.name)) == 0)
@ -96,13 +97,13 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
} }
static KeyringReturnCodes static KeyringReturnCodes
set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error) set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{ {
off_t bytes_written = 0; off_t bytes_written = 0;
off_t curr_pos = 0; off_t curr_pos = 0;
int fd; int fd;
FileKeyring* file_keyring = (FileKeyring*)keyring; FileKeyring *file_keyring = (FileKeyring *) keyring;
keyInfo *existing_key; keyInfo *existing_key;
KeyringReturnCodes return_code = KEYRING_CODE_SUCCESS; KeyringReturnCodes return_code = KEYRING_CODE_SUCCESS;
Assert(key != NULL); Assert(key != NULL);
@ -119,9 +120,9 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
fd = BasicOpenFile(file_keyring->file_name, O_CREAT | O_RDWR | PG_BINARY); fd = BasicOpenFile(file_keyring->file_name, O_CREAT | O_RDWR | PG_BINARY);
if (fd < 0) if (fd < 0)
{ {
ereport(throw_error?ERROR:WARNING, ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("Failed to open keyring file %s :%m", file_keyring->file_name))); errmsg("Failed to open keyring file %s :%m", file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE; return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
} }
/* Write key to the end of file */ /* Write key to the end of file */
@ -130,20 +131,20 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
if (bytes_written != sizeof(keyInfo)) if (bytes_written != sizeof(keyInfo))
{ {
close(fd); close(fd);
ereport(throw_error?ERROR:WARNING, ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("keyring file \"%s\" can't be written: %m", errmsg("keyring file \"%s\" can't be written: %m",
file_keyring->file_name))); file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE; return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
} }
if (pg_fsync(fd) != 0) if (pg_fsync(fd) != 0)
{ {
close(fd); close(fd);
ereport(throw_error?ERROR:WARNING, ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", errmsg("could not fsync file \"%s\": %m",
file_keyring->file_name))); file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE; return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
} }
close(fd); close(fd);

@ -18,7 +18,7 @@
#include "common/jsonapi.h" #include "common/jsonapi.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include <stdio.h> #include <stdio.h>
#include <curl/curl.h> #include <curl/curl.h>
@ -49,18 +49,18 @@ typedef enum
typedef struct JsonVaultRespState typedef struct JsonVaultRespState
{ {
JsonVaultRespSemState state; JsonVaultRespSemState state;
JsonVaultRespField field; JsonVaultRespField field;
int level; int level;
char *key; char *key;
} JsonVaultRespState; } JsonVaultRespState;
static JsonParseErrorType json_resp_object_start(void *state); static JsonParseErrorType json_resp_object_start(void *state);
static JsonParseErrorType json_resp_object_end(void *state); static JsonParseErrorType json_resp_object_end(void *state);
static JsonParseErrorType json_resp_scalar(void *state, char *token, JsonTokenType tokentype); static JsonParseErrorType json_resp_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType json_resp_object_field_start(void *state, char *fname, bool isnull); static JsonParseErrorType json_resp_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex); static JsonParseErrorType parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex);
struct curl_slist *curlList = NULL; struct curl_slist *curlList = NULL;
@ -69,7 +69,7 @@ static char *get_keyring_vault_url(VaultV2Keyring *keyring, const char *key_name
static bool curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long *httpCode, const char *postData); static bool curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long *httpCode, const char *postData);
static KeyringReturnCodes set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error); static KeyringReturnCodes set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error);
static keyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *return_code); static keyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code);
const TDEKeyringRoutine keyringVaultV2Routine = { const TDEKeyringRoutine keyringVaultV2Routine = {
.keyring_get_key = get_key_by_name, .keyring_get_key = get_key_by_name,
@ -77,7 +77,8 @@ const TDEKeyringRoutine keyringVaultV2Routine = {
}; };
bool InstallVaultV2Keyring(void) bool
InstallVaultV2Keyring(void)
{ {
return RegisterKeyProvider(&keyringVaultV2Routine, VAULT_V2_KEY_PROVIDER); return RegisterKeyProvider(&keyringVaultV2Routine, VAULT_V2_KEY_PROVIDER);
} }
@ -85,20 +86,24 @@ bool InstallVaultV2Keyring(void)
static bool static bool
curl_setup_token(VaultV2Keyring *keyring) curl_setup_token(VaultV2Keyring *keyring)
{ {
if(curlList == NULL) if (curlList == NULL)
{ {
char tokenHeader[256]; char tokenHeader[256];
strcpy(tokenHeader, "X-Vault-Token:"); strcpy(tokenHeader, "X-Vault-Token:");
strcat(tokenHeader, keyring->vault_token); strcat(tokenHeader, keyring->vault_token);
curlList = curl_slist_append(curlList, tokenHeader); curlList = curl_slist_append(curlList, tokenHeader);
if(curlList == NULL) return 0; if (curlList == NULL)
return 0;
curlList = curl_slist_append(curlList, "Content-Type: application/json"); curlList = curl_slist_append(curlList, "Content-Type: application/json");
if(curlList == NULL) return 0; if (curlList == NULL)
return 0;
} }
if(curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK)
return 0;
return 1; return 1;
} }
@ -106,10 +111,10 @@ curl_setup_token(VaultV2Keyring *keyring)
static bool static bool
curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long *httpCode, const char *postData) curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long *httpCode, const char *postData)
{ {
CURLcode ret; CURLcode ret;
#if KEYRING_DEBUG #if KEYRING_DEBUG
elog(DEBUG1, "Performing Vault HTTP [%s] request to '%s'", postData != NULL ? "POST" : "GET", url); elog(DEBUG1, "Performing Vault HTTP [%s] request to '%s'", postData != NULL ? "POST" : "GET", url);
if(postData != NULL) if (postData != NULL)
{ {
elog(DEBUG2, "Postdata: '%s'", postData); elog(DEBUG2, "Postdata: '%s'", postData);
} }
@ -123,9 +128,10 @@ curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long
if (!curl_setup_token(keyring)) if (!curl_setup_token(keyring))
return 0; return 0;
if(postData != NULL) if (postData != NULL)
{ {
if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK)
return 0;
} }
ret = curl_easy_perform(keyringCurl); ret = curl_easy_perform(keyringCurl);
@ -135,7 +141,8 @@ curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long
return 0; return 0;
} }
if(curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK) return 0; if (curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK)
return 0;
#if KEYRING_DEBUG #if KEYRING_DEBUG
elog(DEBUG2, "Vault response [%li] '%s'", *httpCode, outStr->ptr != NULL ? outStr->ptr : ""); elog(DEBUG2, "Vault response [%li] '%s'", *httpCode, outStr->ptr != NULL ? outStr->ptr : "");
@ -160,23 +167,26 @@ get_keyring_vault_url(VaultV2Keyring *keyring, const char *key_name, char *out,
} }
static KeyringReturnCodes static KeyringReturnCodes
set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error) set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{ {
VaultV2Keyring *vault_keyring = (VaultV2Keyring *)keyring; VaultV2Keyring *vault_keyring = (VaultV2Keyring *) keyring;
char url[VAULT_URL_MAX_LEN]; char url[VAULT_URL_MAX_LEN];
CurlString str; CurlString str;
long httpCode = 0; long httpCode = 0;
char jsonText[512]; char jsonText[512];
char keyData[64]; char keyData[64];
int keyLen = 0; int keyLen = 0;
Assert(key != NULL); Assert(key != NULL);
// Since we are only building a very limited JSON with a single base64 string, we build it by hand /*
// Simpler than using the limited pg json api * Since we are only building a very limited JSON with a single base64
keyLen = pg_b64_encode((char *)key->data.data, key->data.len, keyData, 64); * string, we build it by hand
*/
/* Simpler than using the limited pg json api */
keyLen = pg_b64_encode((char *) key->data.data, key->data.len, keyData, 64);
keyData[keyLen] = 0; keyData[keyLen] = 0;
snprintf(jsonText, 512, "{\"data\":{\"key\":\"%s\"}}", keyData); snprintf(jsonText, 512, "{\"data\":{\"key\":\"%s\"}}", keyData);
#if KEYRING_DEBUG #if KEYRING_DEBUG
@ -207,18 +217,18 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
} }
static keyInfo * static keyInfo *
get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *return_code) get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code)
{ {
VaultV2Keyring *vault_keyring = (VaultV2Keyring *)keyring; VaultV2Keyring *vault_keyring = (VaultV2Keyring *) keyring;
keyInfo* key = NULL; keyInfo *key = NULL;
char url[VAULT_URL_MAX_LEN]; char url[VAULT_URL_MAX_LEN];
CurlString str; CurlString str;
long httpCode = 0; long httpCode = 0;
JsonParseErrorType json_error; JsonParseErrorType json_error;
JsonLexContext *jlex = NULL; JsonLexContext *jlex = NULL;
JsonVaultRespState parse; JsonVaultRespState parse;
const char* responseKey; const char *responseKey;
*return_code = KEYRING_CODE_SUCCESS; *return_code = KEYRING_CODE_SUCCESS;
@ -271,7 +281,7 @@ get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error,
#endif #endif
key = palloc(sizeof(keyInfo)); key = palloc(sizeof(keyInfo));
key->data.len = pg_b64_decode(responseKey, strlen(responseKey), (char *)key->data.data, MAX_KEY_DATA_SIZE); key->data.len = pg_b64_decode(responseKey, strlen(responseKey), (char *) key->data.data, MAX_KEY_DATA_SIZE);
if (key->data.len > MAX_KEY_DATA_SIZE) if (key->data.len > MAX_KEY_DATA_SIZE)
{ {
@ -285,7 +295,7 @@ get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error,
} }
cleanup: cleanup:
if(str.ptr != NULL) if (str.ptr != NULL)
pfree(str.ptr); pfree(str.ptr);
#if PG_VERSION_NUM >= 170000 #if PG_VERSION_NUM >= 170000
if (jlex != NULL) if (jlex != NULL)
@ -296,7 +306,7 @@ cleanup:
/* /*
* JSON parser routines * JSON parser routines
* *
* We expect the response in the form of: * We expect the response in the form of:
* { * {
* ... * ...
@ -307,14 +317,14 @@ cleanup:
* } * }
* ... * ...
* } * }
* *
* the rest fields are ignored * the rest fields are ignored
*/ */
static JsonParseErrorType static JsonParseErrorType
parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex) parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex)
{ {
JsonSemAction sem; JsonSemAction sem;
parse->state = JRESP_EXPECT_TOP_DATA; parse->state = JRESP_EXPECT_TOP_DATA;
parse->level = -1; parse->level = -1;
@ -408,6 +418,6 @@ json_resp_object_field_start(void *state, char *fname, bool isnull)
parse->field = JRESP_F_KEY; parse->field = JRESP_F_KEY;
break; break;
} }
return JSON_SUCCESS; return JSON_SUCCESS;
} }

@ -45,11 +45,11 @@ PG_MODULE_MAGIC;
struct OnExtInstall struct OnExtInstall
{ {
pg_tde_on_ext_install_callback function; pg_tde_on_ext_install_callback function;
void* arg; void *arg;
}; };
static struct OnExtInstall on_ext_install_list[MAX_ON_INSTALLS]; static struct OnExtInstall on_ext_install_list[MAX_ON_INSTALLS];
static int on_ext_install_index = 0; static int on_ext_install_index = 0;
static void run_extension_install_callbacks(XLogExtensionInstall *xlrec, bool redo); static void run_extension_install_callbacks(XLogExtensionInstall *xlrec, bool redo);
void _PG_init(void); void _PG_init(void);
Datum pg_tde_extension_initialize(PG_FUNCTION_ARGS); Datum pg_tde_extension_initialize(PG_FUNCTION_ARGS);
@ -63,8 +63,8 @@ PG_FUNCTION_INFO_V1(pg_tde_version);
static void static void
tde_shmem_request(void) tde_shmem_request(void)
{ {
Size sz = TdeRequiredSharedMemorySize(); Size sz = TdeRequiredSharedMemorySize();
int required_locks = TdeRequiredLocksCount(); int required_locks = TdeRequiredLocksCount();
#ifdef PERCONA_EXT #ifdef PERCONA_EXT
sz = add_size(sz, XLOG_TDE_ENC_BUFF_ALIGNED_SIZE); sz = add_size(sz, XLOG_TDE_ENC_BUFF_ALIGNED_SIZE);
@ -122,16 +122,22 @@ _PG_init(void)
RegisterStorageMgr(); RegisterStorageMgr();
} }
Datum pg_tde_extension_initialize(PG_FUNCTION_ARGS) Datum
pg_tde_extension_initialize(PG_FUNCTION_ARGS)
{ {
/* Initialize the TDE map */ /* Initialize the TDE map */
XLogExtensionInstall xlrec; XLogExtensionInstall xlrec;
xlrec.database_id = MyDatabaseId; xlrec.database_id = MyDatabaseId;
xlrec.tablespace_id = MyDatabaseTableSpace; xlrec.tablespace_id = MyDatabaseTableSpace;
run_extension_install_callbacks(&xlrec, false); run_extension_install_callbacks(&xlrec, false);
/* Also put this info in xlog, so we can replicate the same on the other side */
/*
* Also put this info in xlog, so we can replicate the same on the other
* side
*/
XLogBeginInsert(); XLogBeginInsert();
XLogRegisterData((char *)&xlrec, sizeof(XLogExtensionInstall)); XLogRegisterData((char *) &xlrec, sizeof(XLogExtensionInstall));
XLogInsert(RM_TDERMGR_ID, XLOG_TDE_EXTENSION_INSTALL_KEY); XLogInsert(RM_TDERMGR_ID, XLOG_TDE_EXTENSION_INSTALL_KEY);
PG_RETURN_NULL(); PG_RETURN_NULL();
@ -149,12 +155,13 @@ extension_install_redo(XLogExtensionInstall *xlrec)
* run at the time of pg_tde extension installs. * run at the time of pg_tde extension installs.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void on_ext_install(pg_tde_on_ext_install_callback function, void *arg) void
on_ext_install(pg_tde_on_ext_install_callback function, void *arg)
{ {
if (on_ext_install_index >= MAX_ON_INSTALLS) if (on_ext_install_index >= MAX_ON_INSTALLS)
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg_internal("out of on extension install slots"))); errmsg_internal("out of on extension install slots")));
on_ext_install_list[on_ext_install_index].function = function; on_ext_install_list[on_ext_install_index].function = function;
on_ext_install_list[on_ext_install_index].arg = arg; on_ext_install_list[on_ext_install_index].arg = arg;
@ -167,14 +174,14 @@ void on_ext_install(pg_tde_on_ext_install_callback function, void *arg)
* ------------------ * ------------------
*/ */
static void static void
run_extension_install_callbacks(XLogExtensionInstall* xlrec , bool redo) run_extension_install_callbacks(XLogExtensionInstall *xlrec, bool redo)
{ {
int i; int i;
int tde_table_count =0; int tde_table_count = 0;
/* /*
* Get the number of tde tables in this database * Get the number of tde tables in this database should always be zero.
* should always be zero. But still, it prevents * But still, it prevents the cleanup if someone explicitly calls this
* the cleanup if someone explicitly calls this
* function. * function.
*/ */
if (!redo) if (!redo)

@ -18,7 +18,7 @@
/* Returns package version */ /* Returns package version */
const char* const char *
pg_tde_package_string(void) pg_tde_package_string(void)
{ {
return PACKAGE_STRING; return PACKAGE_STRING;
@ -29,7 +29,7 @@ pg_tde_package_name(void)
{ {
return PACKAGE_NAME; return PACKAGE_NAME;
} }
const char* const char *
pg_tde_package_version(void) pg_tde_package_version(void)
{ {
return PACKAGE_VERSION; return PACKAGE_VERSION;

@ -101,8 +101,8 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
else if (IsA(parsetree, CreateStmt)) else if (IsA(parsetree, CreateStmt))
{ {
CreateStmt *stmt = (CreateStmt *) parsetree; CreateStmt *stmt = (CreateStmt *) parsetree;
TDEPrincipalKey * principal_key; TDEPrincipalKey *principal_key;
Oid tablespace_oid; Oid tablespace_oid;
tdeCurrentCreateEvent.eventType = TDE_TABLE_CREATE_EVENT; tdeCurrentCreateEvent.eventType = TDE_TABLE_CREATE_EVENT;
tdeCurrentCreateEvent.relation = stmt->relation; tdeCurrentCreateEvent.relation = stmt->relation;
@ -110,15 +110,16 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
if (stmt->accessMethod && strcmp(stmt->accessMethod, "tde_heap") == 0) if (stmt->accessMethod && strcmp(stmt->accessMethod, "tde_heap") == 0)
{ {
tdeCurrentCreateEvent.encryptMode = true; tdeCurrentCreateEvent.encryptMode = true;
} else if ((stmt->accessMethod == NULL || stmt->accessMethod[0] ==0) && strcmp(default_table_access_method, "tde_heap") == 0) }
else if ((stmt->accessMethod == NULL || stmt->accessMethod[0] == 0) && strcmp(default_table_access_method, "tde_heap") == 0)
{ {
tdeCurrentCreateEvent.encryptMode = true; tdeCurrentCreateEvent.encryptMode = true;
} }
if(tdeCurrentCreateEvent.encryptMode) if (tdeCurrentCreateEvent.encryptMode)
{ {
tablespace_oid = stmt->tablespacename != NULL ? get_tablespace_oid(stmt->tablespacename, false) tablespace_oid = stmt->tablespacename != NULL ? get_tablespace_oid(stmt->tablespacename, false)
: MyDatabaseTableSpace; : MyDatabaseTableSpace;
LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED); LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);
principal_key = GetPrincipalKey(MyDatabaseId, tablespace_oid, LW_SHARED); principal_key = GetPrincipalKey(MyDatabaseId, tablespace_oid, LW_SHARED);
LWLockRelease(tde_lwlock_enc_keys()); LWLockRelease(tde_lwlock_enc_keys());
@ -151,7 +152,10 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
} }
} }
// TODO: also check for tablespace change, if current or new AM is tde_heap! /*
* TODO: also check for tablespace change, if current or new AM is
* tde_heap!
*/
if (tdeCurrentCreateEvent.encryptMode) if (tdeCurrentCreateEvent.encryptMode)
{ {

@ -14,18 +14,19 @@ typedef struct TDESMgrRelationData
{ {
/* parent data */ /* parent data */
SMgrRelationData reln; SMgrRelationData reln;
/* /*
* for md.c; per-fork arrays of the number of open segments * for md.c; per-fork arrays of the number of open segments
* (md_num_open_segs) and the segments themselves (md_seg_fds). * (md_num_open_segs) and the segments themselves (md_seg_fds).
*/ */
int md_num_open_segs[MAX_FORKNUM + 1]; int md_num_open_segs[MAX_FORKNUM + 1];
struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1]; struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1];
bool encrypted_relation; bool encrypted_relation;
RelKeyData relKey; RelKeyData relKey;
} TDESMgrRelationData; } TDESMgrRelationData;
typedef TDESMgrRelationData *TDESMgrRelation; typedef TDESMgrRelationData * TDESMgrRelation;
/* /*
* we only encrypt main and init forks * we only encrypt main and init forks
@ -36,48 +37,51 @@ tde_is_encryption_required(TDESMgrRelation tdereln, ForkNumber forknum)
return (tdereln->encrypted_relation && (forknum == MAIN_FORKNUM || forknum == INIT_FORKNUM)); return (tdereln->encrypted_relation && (forknum == MAIN_FORKNUM || forknum == INIT_FORKNUM));
} }
static RelKeyData* static RelKeyData *
tde_smgr_get_key(SMgrRelation reln) tde_smgr_get_key(SMgrRelation reln)
{ {
TdeCreateEvent *event; TdeCreateEvent *event;
RelKeyData *rkd; RelKeyData *rkd;
TDEPrincipalKey *pk; TDEPrincipalKey *pk;
if(IsCatalogRelationOid(reln->smgr_rlocator.locator.relNumber)) if (IsCatalogRelationOid(reln->smgr_rlocator.locator.relNumber))
{ {
// do not try to encrypt/decrypt catalog tables /* do not try to encrypt/decrypt catalog tables */
return NULL; return NULL;
} }
LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED); LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);
pk = GetPrincipalKey(reln->smgr_rlocator.locator.dbOid, reln->smgr_rlocator.locator.spcOid, LW_SHARED); pk = GetPrincipalKey(reln->smgr_rlocator.locator.dbOid, reln->smgr_rlocator.locator.spcOid, LW_SHARED);
LWLockRelease(tde_lwlock_enc_keys()); LWLockRelease(tde_lwlock_enc_keys());
if(pk == NULL) if (pk == NULL)
{ {
return NULL; return NULL;
} }
event = GetCurrentTdeCreateEvent(); event = GetCurrentTdeCreateEvent();
// see if we have a key for the relation, and return if yes /* see if we have a key for the relation, and return if yes */
rkd = GetSMGRRelationKey(reln->smgr_rlocator.locator); rkd = GetSMGRRelationKey(reln->smgr_rlocator.locator);
if(rkd != NULL) if (rkd != NULL)
{ {
return rkd; return rkd;
} }
// if this is a CREATE TABLE, we have to generate the key /* if this is a CREATE TABLE, we have to generate the key */
if(event->encryptMode == true && event->eventType == TDE_TABLE_CREATE_EVENT) if (event->encryptMode == true && event->eventType == TDE_TABLE_CREATE_EVENT)
{ {
return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator); return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator);
} }
// if this is a CREATE INDEX, we have to load the key based on the table /* if this is a CREATE INDEX, we have to load the key based on the table */
if(event->encryptMode == true && event->eventType == TDE_INDEX_CREATE_EVENT) if (event->encryptMode == true && event->eventType == TDE_INDEX_CREATE_EVENT)
{ {
// For now keep it simple and create separate key for indexes /* For now keep it simple and create separate key for indexes */
// Later we might modify the map infrastructure to support the same keys /*
* Later we might modify the map infrastructure to support the same
* keys
*/
return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator); return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator);
} }
@ -86,9 +90,9 @@ tde_smgr_get_key(SMgrRelation reln)
static void static void
tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
const void **buffers, BlockNumber nblocks, bool skipFsync) const void **buffers, BlockNumber nblocks, bool skipFsync)
{ {
TDESMgrRelation tdereln = (TDESMgrRelation)reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *rkd = &tdereln->relKey; RelKeyData *rkd = &tdereln->relKey;
if (!tde_is_encryption_required(tdereln, forknum)) if (!tde_is_encryption_required(tdereln, forknum))
@ -97,26 +101,28 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
} }
else else
{ {
char *local_blocks = palloc(BLCKSZ * (nblocks + 1)); char *local_blocks = palloc(BLCKSZ * (nblocks + 1));
char *local_blocks_aligned = (char *)TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks); char *local_blocks_aligned = (char *) TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
const void **local_buffers = palloc(sizeof(void *) * nblocks); const void **local_buffers = palloc(sizeof(void *) * nblocks);
AesInit(); AesInit();
for(int i = 0; i < nblocks; ++i ) for (int i = 0; i < nblocks; ++i)
{ {
int out_len = BLCKSZ; int out_len = BLCKSZ;
local_buffers[i] = &local_blocks_aligned[i * BLCKSZ]; local_buffers[i] = &local_blocks_aligned[i * BLCKSZ];
BlockNumber bn = blocknum + i; BlockNumber bn = blocknum + i;
unsigned char iv[16] = {0,}; unsigned char iv[16] = {0,};
memcpy(iv+4, &bn, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char**)buffers)[i], BLCKSZ, local_buffers[i], &out_len); memcpy(iv + 4, &bn, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char **) buffers)[i], BLCKSZ, local_buffers[i], &out_len);
} }
mdwritev(reln, forknum, blocknum, mdwritev(reln, forknum, blocknum,
local_buffers, nblocks, skipFsync); local_buffers, nblocks, skipFsync);
pfree(local_blocks); pfree(local_blocks);
pfree(local_buffers); pfree(local_buffers);
@ -125,9 +131,9 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
static void static void
tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
const void *buffer, bool skipFsync) const void *buffer, bool skipFsync)
{ {
TDESMgrRelation tdereln = (TDESMgrRelation)reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *rkd = &tdereln->relKey; RelKeyData *rkd = &tdereln->relKey;
if (!tde_is_encryption_required(tdereln, forknum)) if (!tde_is_encryption_required(tdereln, forknum))
@ -137,8 +143,8 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
else else
{ {
char *local_blocks = palloc(BLCKSZ * (1 + 1)); char *local_blocks = palloc(BLCKSZ * (1 + 1));
char *local_blocks_aligned = (char *)TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks); char *local_blocks_aligned = (char *) TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
int out_len = BLCKSZ; int out_len = BLCKSZ;
unsigned char iv[16] = { unsigned char iv[16] = {
0, 0,
}; };
@ -146,7 +152,7 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
AesInit(); AesInit();
memcpy(iv + 4, &blocknum, sizeof(BlockNumber)); memcpy(iv + 4, &blocknum, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char *)buffer), BLCKSZ, local_blocks_aligned, &out_len); AesEncrypt(rkd->internal_key.key, iv, ((char *) buffer), BLCKSZ, local_blocks_aligned, &out_len);
mdextend(reln, forknum, blocknum, local_blocks_aligned, skipFsync); mdextend(reln, forknum, blocknum, local_blocks_aligned, skipFsync);
@ -156,10 +162,10 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
static void static void
tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
void **buffers, BlockNumber nblocks) void **buffers, BlockNumber nblocks)
{ {
int out_len = BLCKSZ; int out_len = BLCKSZ;
TDESMgrRelation tdereln = (TDESMgrRelation)reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *rkd = &tdereln->relKey; RelKeyData *rkd = &tdereln->relKey;
mdreadv(reln, forknum, blocknum, buffers, nblocks); mdreadv(reln, forknum, blocknum, buffers, nblocks);
@ -169,42 +175,60 @@ tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
AesInit(); AesInit();
for(int i = 0; i < nblocks; ++i) for (int i = 0; i < nblocks; ++i)
{ {
bool allZero = true; bool allZero = true;
BlockNumber bn = blocknum + i; BlockNumber bn = blocknum + i;
unsigned char iv[16] = {0,}; unsigned char iv[16] = {0,};
for(int j = 0; j < 32; ++j) for (int j = 0; j < 32; ++j)
{ {
if(((char**)buffers)[i][j] != 0) if (((char **) buffers)[i][j] != 0)
{ {
// Postgres creates all zero blocks in an optimized route, which we do not try /*
// to encrypt. * Postgres creates all zero blocks in an optimized route,
// Instead we detect if a block is all zero at decryption time, and * which we do not try
// leave it as is. */
// This could be a security issue later, but it is a good first prototype /* to encrypt. */
/*
* Instead we detect if a block is all zero at decryption
* time, and
*/
/* leave it as is. */
/*
* This could be a security issue later, but it is a good
* first prototype
*/
allZero = false; allZero = false;
break; break;
} }
} }
if(allZero) if (allZero)
continue; continue;
memcpy(iv+4, &bn, sizeof(BlockNumber)); memcpy(iv + 4, &bn, sizeof(BlockNumber));
AesDecrypt(rkd->internal_key.key, iv, ((char **)buffers)[i], BLCKSZ, ((char **)buffers)[i], &out_len); AesDecrypt(rkd->internal_key.key, iv, ((char **) buffers)[i], BLCKSZ, ((char **) buffers)[i], &out_len);
} }
} }
static void static void
tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
{ {
TDESMgrRelation tdereln = (TDESMgrRelation)reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
// This is the only function that gets called during actual CREATE TABLE/INDEX (EVENT TRIGGER)
// so we create the key here by loading it /*
// Later calls then decide to encrypt or not based on the existence of the key * This is the only function that gets called during actual CREATE
RelKeyData* key = tde_smgr_get_key(reln); * TABLE/INDEX (EVENT TRIGGER)
*/
/* so we create the key here by loading it */
/*
* Later calls then decide to encrypt or not based on the existence of the
* key
*/
RelKeyData *key = tde_smgr_get_key(reln);
if (key) if (key)
{ {
tdereln->encrypted_relation = true; tdereln->encrypted_relation = true;
@ -224,8 +248,9 @@ tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
static void static void
tde_mdopen(SMgrRelation reln) tde_mdopen(SMgrRelation reln)
{ {
TDESMgrRelation tdereln = (TDESMgrRelation)reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *key = tde_smgr_get_key(reln); RelKeyData *key = tde_smgr_get_key(reln);
if (key) if (key)
{ {
tdereln->encrypted_relation = true; tdereln->encrypted_relation = true;
@ -260,16 +285,18 @@ static const struct f_smgr tde_smgr = {
.smgr_registersync = mdregistersync, .smgr_registersync = mdregistersync,
}; };
void RegisterStorageMgr(void) void
RegisterStorageMgr(void)
{ {
tde_smgr_id = smgr_register(&tde_smgr, sizeof(TDESMgrRelationData)); tde_smgr_id = smgr_register(&tde_smgr, sizeof(TDESMgrRelationData));
// TODO: figure out how this part should work in a real extension /* TODO: figure out how this part should work in a real extension */
storage_manager_id = tde_smgr_id; storage_manager_id = tde_smgr_id;
} }
#else #else
void RegisterStorageMgr(void) void
RegisterStorageMgr(void)
{ {
} }
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */

@ -20,14 +20,14 @@
typedef struct PendingMapEntryDelete typedef struct PendingMapEntryDelete
{ {
off_t map_entry_offset; /* map entry offset */ off_t map_entry_offset; /* map entry offset */
RelFileLocator rlocator; /* main for use as relation OID */ RelFileLocator rlocator; /* main for use as relation OID */
bool atCommit; /* T=delete at commit; F=delete at abort */ bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */ int nestLevel; /* xact nesting level of request */
struct PendingMapEntryDelete *next; /* linked-list link */ struct PendingMapEntryDelete *next; /* linked-list link */
} PendingMapEntryDelete; } PendingMapEntryDelete;
static PendingMapEntryDelete *pendingDeletes = NULL; /* head of linked list */ static PendingMapEntryDelete *pendingDeletes = NULL; /* head of linked list */
static void do_pending_deletes(bool isCommit); static void do_pending_deletes(bool isCommit);
static void reassign_pending_deletes_to_parent_xact(void); static void reassign_pending_deletes_to_parent_xact(void);
@ -37,53 +37,55 @@ static void pending_delete_cleanup(void);
void void
pg_tde_xact_callback(XactEvent event, void *arg) pg_tde_xact_callback(XactEvent event, void *arg)
{ {
if (event == XACT_EVENT_PARALLEL_ABORT || if (event == XACT_EVENT_PARALLEL_ABORT ||
event == XACT_EVENT_ABORT) event == XACT_EVENT_ABORT)
{ {
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("pg_tde_xact_callback: aborting transaction"))); (errmsg("pg_tde_xact_callback: aborting transaction")));
do_pending_deletes(false); do_pending_deletes(false);
} }
else if (event == XACT_EVENT_COMMIT) else if (event == XACT_EVENT_COMMIT)
{ {
do_pending_deletes(true); do_pending_deletes(true);
pending_delete_cleanup(); pending_delete_cleanup();
} }
else if (event == XACT_EVENT_PREPARE) else if (event == XACT_EVENT_PREPARE)
{ {
pending_delete_cleanup(); pending_delete_cleanup();
} }
} }
void void
pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid, pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
SubTransactionId parentSubid, void *arg) SubTransactionId parentSubid, void *arg)
{ {
/* TODO: takle all possible transaction states */ /* TODO: takle all possible transaction states */
if (event == SUBXACT_EVENT_ABORT_SUB) if (event == SUBXACT_EVENT_ABORT_SUB)
{ {
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: aborting subtransaction"))); (errmsg("pg_tde_subxact_callback: aborting subtransaction")));
do_pending_deletes(false); do_pending_deletes(false);
} else if (event == SUBXACT_EVENT_COMMIT_SUB) }
{ else if (event == SUBXACT_EVENT_COMMIT_SUB)
ereport(DEBUG2, {
(errmsg("pg_tde_subxact_callback: committing subtransaction"))); ereport(DEBUG2,
reassign_pending_deletes_to_parent_xact(); (errmsg("pg_tde_subxact_callback: committing subtransaction")));
} reassign_pending_deletes_to_parent_xact();
}
} }
void void
RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit) RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit)
{ {
PendingMapEntryDelete *pending; PendingMapEntryDelete *pending;
pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete));
pending->map_entry_offset = map_entry_offset; pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete));
memcpy(&pending->rlocator, rlocator, sizeof(RelFileLocator)); pending->map_entry_offset = map_entry_offset;
pending->atCommit = atCommit; /* delete if abort */ memcpy(&pending->rlocator, rlocator, sizeof(RelFileLocator));
pending->nestLevel = GetCurrentTransactionNestLevel(); pending->atCommit = atCommit; /* delete if abort */
pending->next = pendingDeletes; pending->nestLevel = GetCurrentTransactionNestLevel();
pendingDeletes = pending; pending->next = pendingDeletes;
pendingDeletes = pending;
} }
/* /*
@ -91,15 +93,15 @@ RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset,
* *
* This also runs when aborting a subxact; we want to clean up a failed * This also runs when aborting a subxact; we want to clean up a failed
* subxact immediately. * subxact immediately.
* *
*/ */
static void static void
do_pending_deletes(bool isCommit) do_pending_deletes(bool isCommit)
{ {
int nestLevel = GetCurrentTransactionNestLevel(); int nestLevel = GetCurrentTransactionNestLevel();
PendingMapEntryDelete *pending; PendingMapEntryDelete *pending;
PendingMapEntryDelete *prev; PendingMapEntryDelete *prev;
PendingMapEntryDelete *next; PendingMapEntryDelete *next;
LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE); LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
@ -114,21 +116,21 @@ do_pending_deletes(bool isCommit)
continue; continue;
} }
/* unlink list entry first, so we don't retry on failure */ /* unlink list entry first, so we don't retry on failure */
if (prev) if (prev)
prev->next = next; prev->next = next;
else else
pendingDeletes = next; pendingDeletes = next;
/* do deletion if called for */ /* do deletion if called for */
if (pending->atCommit == isCommit) if (pending->atCommit == isCommit)
{ {
ereport(LOG, ereport(LOG,
(errmsg("pg_tde_xact_callback: deleting entry at offset %d", (errmsg("pg_tde_xact_callback: deleting entry at offset %d",
(int)(pending->map_entry_offset)))); (int) (pending->map_entry_offset))));
pg_tde_free_key_map_entry(&pending->rlocator, MAP_ENTRY_VALID, pending->map_entry_offset); pg_tde_free_key_map_entry(&pending->rlocator, MAP_ENTRY_VALID, pending->map_entry_offset);
} }
pfree(pending); pfree(pending);
/* prev does not change */ /* prev does not change */
} }
@ -143,20 +145,20 @@ do_pending_deletes(bool isCommit)
* 1. Only top level transaction can perform on-commit deletes. * 1. Only top level transaction can perform on-commit deletes.
* 2. Subtransaction and top level transaction can perform on-abort deletes. * 2. Subtransaction and top level transaction can perform on-abort deletes.
* So we have to decrement the nesting level of pending deletes to reassing them to the parent transaction * So we have to decrement the nesting level of pending deletes to reassing them to the parent transaction
* if subtransaction was not self aborted. In other words if subtransaction state is commited all its pending * if subtransaction was not self aborted. In other words if subtransaction state is commited all its pending
* deletes are reassigned to the parent transaction. * deletes are reassigned to the parent transaction.
*/ */
static void static void
reassign_pending_deletes_to_parent_xact(void) reassign_pending_deletes_to_parent_xact(void)
{ {
PendingMapEntryDelete *pending; PendingMapEntryDelete *pending;
int nestLevel = GetCurrentTransactionNestLevel(); int nestLevel = GetCurrentTransactionNestLevel();
for (pending = pendingDeletes; pending != NULL; pending = pending->next) for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{ {
if (pending->nestLevel == nestLevel) if (pending->nestLevel == nestLevel)
pending->nestLevel--; pending->nestLevel--;
} }
} }
/* /*
@ -169,13 +171,13 @@ reassign_pending_deletes_to_parent_xact(void)
static void static void
pending_delete_cleanup(void) pending_delete_cleanup(void)
{ {
PendingMapEntryDelete *pending; PendingMapEntryDelete *pending;
PendingMapEntryDelete *next; PendingMapEntryDelete *next;
for (pending = pendingDeletes; pending != NULL; pending = next) for (pending = pendingDeletes; pending != NULL; pending = next)
{ {
next = pending->next; next = pending->next;
pendingDeletes = next; pendingDeletes = next;
pfree(pending); pfree(pending);
} }
} }

@ -0,0 +1,113 @@
BulkInsertStateData
BulkInsertStateData
BulkInsertStateData
BulkInsertStateData
CurlString
FileKeyring
GenericKeyring
HeapPageFreeze
HeapPageFreeze
HeapScanDescData
HeapScanDescData
HeapScanDescData
HeapScanDescData
HeapTupleFreeze
HeapTupleFreeze
IndexDeleteCounts
IndexDeleteCounts
IndexFetchHeapData
IndexFetchHeapData
InternalKey
JsonKeringSemState
JsonKeyringField
JsonKeyringState
JsonVaultRespField
JsonVaultRespSemState
JsonVaultRespState
KeyProviders
KeyringProvideRecord
KeyringProviderXLRecord
KeyringReturnCode
LVPagePruneState
LVRelState
LVRelState
LVSavedErrInfo
LVSavedErrInfo
LogicalRewriteMappingData
LogicalRewriteMappingData
PendingMapEntryDelete
ProviderScanType
PruneFreezeResult
RelKeyCache
RelKeyCacheRec
RelKeyData
RewriteMappingDataEntry
RewriteMappingDataEntry
RewriteMappingFile
RewriteMappingFile
RewriteStateData
RewriteStateData
RewriteStateData
RewriteStateData *RewriteState;
TDEBufferHeapTupleTableSlot
TDEFileHeader
TDEKeyringRoutine
TDELocalState
TDELockTypes
TDEMapEntry
TDEMapFilePath
TDEPrincipalKey
TDEPrincipalKeyId
TDEPrincipalKeyInfo
TDEShmemSetupRoutine
TdeCreateEvent
TdeCreateEventType
TdeKeyProviderInfoSharedState
TdePrincipalKeySharedState
TdePrincipalKeylocalState
TdeSharedState
VaultV2Keyring
XLogExtensionInstall
XLogPrincipalKeyRotate
XLogRelKey
itemIdCompactData
itemIdCompactData
keyData
keyInfo
keyName
xl_multi_insert_tuple
xl_multi_insert_tuple
xl_tdeheap_confirm
xl_tdeheap_confirm
xl_tdeheap_delete
xl_tdeheap_delete
xl_tdeheap_freeze_page
xl_tdeheap_freeze_plan
xl_tdeheap_header
xl_tdeheap_header
xl_tdeheap_inplace
xl_tdeheap_inplace
xl_tdeheap_insert
xl_tdeheap_insert
xl_tdeheap_lock
xl_tdeheap_lock
xl_tdeheap_lock_updated
xl_tdeheap_lock_updated
xl_tdeheap_multi_insert
xl_tdeheap_multi_insert
xl_tdeheap_new_cid
xl_tdeheap_new_cid
xl_tdeheap_prune
xl_tdeheap_prune
xl_tdeheap_rewrite_mapping
xl_tdeheap_rewrite_mapping
xl_tdeheap_truncate
xl_tdeheap_truncate
xl_tdeheap_update
xl_tdeheap_update
xl_tdeheap_vacuum
xl_tdeheap_visible
xl_tdeheap_visible
xlhp_freeze_plan
xlhp_freeze_plans
xlhp_prune_items
Loading…
Cancel
Save