Skip to content

Commit bf71119

Browse files
committed
Fix broken reuse of deleted entries in key map file
Since we tried to check if flags & MAP_ENTRY_EMPTY was true when searching for empty entries the code was broken since x & 0 always is false. We fix this by refactoring pg_tde_read_one_map_entry() so the filtering of the entries is done outside the function. This make implementing search for empty entries much easier.
1 parent 35c97ee commit bf71119

File tree

2 files changed

+26
-70
lines changed

2 files changed

+26
-70
lines changed

contrib/pg_tde/src/access/pg_tde_tdemap.c

+26-69
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static TDEMapEntry *pg_tde_find_map_entry(const RelFileLocator *rlocator, uint32
114114
static InternalKey *tde_decrypt_rel_key(TDEPrincipalKey *principal_key, TDEMapEntry *map_entry);
115115
static int pg_tde_open_file_basic(const char *tde_filename, int fileFlags, bool ignore_missing);
116116
static void pg_tde_file_header_read(const char *tde_filename, int fd, TDEFileHeader *fheader, off_t *bytes_read);
117-
static bool pg_tde_read_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset);
117+
static bool pg_tde_read_one_map_entry(int fd, TDEMapEntry *map_entry, off_t *offset);
118118
static void pg_tde_read_one_map_entry2(int keydata_fd, int32 key_index, TDEMapEntry *map_entry, Oid databaseId);
119119
static int pg_tde_open_file_read(const char *tde_filename, off_t *curr_pos);
120120
static InternalKey *pg_tde_get_key_from_cache(const RelFileLocator *rlocator, uint32 key_type);
@@ -449,16 +449,12 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_
449449
while (1)
450450
{
451451
TDEMapEntry read_map_entry;
452-
bool found;
453452

454453
prev_pos = curr_pos;
455-
found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &read_map_entry, &curr_pos);
454+
if (!pg_tde_read_one_map_entry(map_fd, &read_map_entry, &curr_pos))
455+
break;
456456

457-
/*
458-
* We either reach EOF or found an empty slot in the middle of the
459-
* file
460-
*/
461-
if (prev_pos == curr_pos || found)
457+
if (read_map_entry.flags == MAP_ENTRY_EMPTY)
462458
break;
463459
}
464460

@@ -522,16 +518,12 @@ pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDESignedPri
522518
while (1)
523519
{
524520
TDEMapEntry read_map_entry;
525-
bool found;
526521

527522
prev_pos = curr_pos;
528-
found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &read_map_entry, &curr_pos);
523+
if (!pg_tde_read_one_map_entry(map_fd, &read_map_entry, &curr_pos))
524+
break;
529525

530-
/*
531-
* We either reach EOF or found an empty slot in the middle of the
532-
* file
533-
*/
534-
if (prev_pos == curr_pos || found)
526+
if (read_map_entry.flags == MAP_ENTRY_EMPTY)
535527
break;
536528
}
537529

@@ -583,17 +575,13 @@ pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t
583575
*/
584576
while (1)
585577
{
586-
TDEMapEntry read_map_entry;
578+
TDEMapEntry map_entry;
587579
off_t prev_pos = curr_pos;
588580

589-
found = pg_tde_read_one_map_entry(map_fd, rlocator, MAP_ENTRY_VALID, &read_map_entry, &curr_pos);
590-
591-
/* We've reached EOF */
592-
if (curr_pos == prev_pos)
581+
if (!pg_tde_read_one_map_entry(map_fd, &map_entry, &curr_pos))
593582
break;
594583

595-
/* We found a valid entry for the relation */
596-
if (found)
584+
if (map_entry.flags != MAP_ENTRY_EMPTY && map_entry.spcOid == rlocator->spcOid && map_entry.relNumber == rlocator->relNumber)
597585
{
598586
TDEMapEntry empty_map_entry = {
599587
.flags = MAP_ENTRY_EMPTY,
@@ -603,6 +591,7 @@ pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t
603591
};
604592

605593
pg_tde_write_one_map_entry(map_fd, &empty_map_entry, &prev_pos, db_map_path);
594+
found = true;
606595
break;
607596
}
608597
}
@@ -616,7 +605,7 @@ pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t
616605

617606
/*
618607
* Called when transaction is being completed; either committed or aborted.
619-
* By default, when a transaction creates an entry, we mark it as MAP_ENTRY_VALID.
608+
* By default, when a transaction creates an entry, we mark it with the type.
620609
* Only during the abort phase of the transaction that we are proceed on with
621610
* marking the entry as MAP_ENTRY_FREE. This optimistic strategy that assumes
622611
* that transaction will commit more often then getting aborted avoids
@@ -712,22 +701,15 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
712701
while (1)
713702
{
714703
InternalKey *rel_key_data;
715-
off_t old_prev_pos,
716-
new_prev_pos;
704+
off_t new_prev_pos;
717705
TDEMapEntry read_map_entry,
718706
write_map_entry;
719707
RelFileLocator rloc;
720-
bool found;
721-
722-
old_prev_pos = old_curr_pos;
723-
found = pg_tde_read_one_map_entry(old_fd, NULL, MAP_ENTRY_VALID, &read_map_entry, &old_curr_pos);
724708

725-
/* We either reach EOF */
726-
if (old_prev_pos == old_curr_pos)
709+
if (!pg_tde_read_one_map_entry(old_fd, &read_map_entry, &old_curr_pos))
727710
break;
728711

729-
/* We didn't find a valid entry */
730-
if (found == false)
712+
if (read_map_entry.flags == MAP_ENTRY_EMPTY)
731713
continue;
732714

733715
rloc.spcOid = read_map_entry.spcOid;
@@ -975,8 +957,9 @@ pg_tde_get_key_from_file(const RelFileLocator *rlocator, uint32 key_type)
975957
}
976958

977959
/*
978-
* Returns the index of the read map if we find a valid match; e.g. flags is set to
979-
* MAP_ENTRY_VALID and the relNumber and spcOid matches the one provided in rlocator.
960+
* Returns the entry of the map if we find a valid match; e.g. flags is not
961+
* set to MAP_ENTRY_EMPTY and the relNumber and spcOid matches the one
962+
* provided in rlocator.
980963
*/
981964
static TDEMapEntry *
982965
pg_tde_find_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *db_map_path)
@@ -985,30 +968,20 @@ pg_tde_find_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *db_
985968
TDEMapEntry *map_entry = palloc_object(TDEMapEntry);
986969
off_t curr_pos = 0;
987970

971+
Assert(rlocator != NULL);
972+
988973
map_fd = pg_tde_open_file_read(db_map_path, &curr_pos);
989974

990-
/*
991-
* Read until we find an empty slot. Otherwise, read until end. This seems
992-
* to be less frequent than vacuum. So let's keep this function here
993-
* rather than overloading the vacuum process.
994-
*/
995975
while (1)
996976
{
997-
bool found;
998-
off_t prev_pos = curr_pos;
999-
1000-
found = pg_tde_read_one_map_entry(map_fd, rlocator, key_type, map_entry, &curr_pos);
1001-
1002-
/* We've reached EOF */
1003-
if (curr_pos == prev_pos)
977+
if (!pg_tde_read_one_map_entry(map_fd, map_entry, &curr_pos))
1004978
{
1005979
close(map_fd);
1006980
pfree(map_entry);
1007981
return NULL;
1008982
}
1009983

1010-
/* We found a valid entry for the relation */
1011-
if (found)
984+
if ((map_entry->flags & key_type) && map_entry->spcOid == rlocator->spcOid && map_entry->relNumber == rlocator->relNumber)
1012985
{
1013986
close(map_fd);
1014987
return map_entry;
@@ -1118,26 +1091,17 @@ pg_tde_file_header_read(const char *tde_filename, int fd, TDEFileHeader *fheader
11181091

11191092

11201093
/*
1121-
* Returns true if a valid map entry if found. Otherwise, it only increments
1122-
* the offset and returns false. If the same offset value is set, it indicates
1123-
* to the caller that nothing was read.
1124-
*
1125-
* If a non-NULL rlocator is provided, the function compares the read value
1126-
* against the relNumber of rlocator. It sets found accordingly.
1127-
*
1128-
* The caller is reponsible for identifying that we have reached EOF by
1129-
* comparing old and new value of the offset.
1094+
* Returns true if a map entry if found or false if we have reached the end of
1095+
* the file.
11301096
*/
11311097
static bool
1132-
pg_tde_read_one_map_entry(int map_file, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset)
1098+
pg_tde_read_one_map_entry(int map_file, TDEMapEntry *map_entry, off_t *offset)
11331099
{
1134-
bool found;
11351100
off_t bytes_read = 0;
11361101

11371102
Assert(map_entry);
11381103
Assert(offset);
11391104

1140-
/* Read the entry at the given offset */
11411105
bytes_read = pg_pread(map_file, map_entry, MAP_ENTRY_SIZE, *offset);
11421106

11431107
/* We've reached the end of the file. */
@@ -1146,14 +1110,7 @@ pg_tde_read_one_map_entry(int map_file, const RelFileLocator *rlocator, int flag
11461110

11471111
*offset += bytes_read;
11481112

1149-
/* We found a valid entry */
1150-
found = map_entry->flags & flags;
1151-
1152-
/* If a valid rlocator is provided, let's compare and set found value */
1153-
if (rlocator != NULL)
1154-
found &= map_entry->spcOid == rlocator->spcOid && map_entry->relNumber == rlocator->relNumber;
1155-
1156-
return found;
1113+
return true;
11571114
}
11581115

11591116
/*

contrib/pg_tde/src/include/access/pg_tde_tdemap.h

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#define TDE_KEY_TYPE_GLOBAL 0x04
2020
#define TDE_KEY_TYPE_WAL_UNENCRYPTED 0x08
2121
#define TDE_KEY_TYPE_WAL_ENCRYPTED 0x10
22-
#define MAP_ENTRY_VALID (TDE_KEY_TYPE_SMGR | TDE_KEY_TYPE_GLOBAL)
2322

2423
#define INTERNAL_KEY_LEN 16
2524
#define INTERNAL_KEY_IV_LEN 16

0 commit comments

Comments
 (0)