Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ccc8194

Browse files
committed
Fix use-after-free in parallel_vacuum_reset_dead_items
parallel_vacuum_reset_dead_items used a local variable to hold a pointer from the passed vacrel, purely as a shorthand. This pointer was later freed and a new allocation was made and stored to the struct. Then the local pointer was mistakenly referenced again. This apparently happened not to break anything since the freed chunk would have been put on the context's freelist, so it was accidentally the same pointer anyway, in which case the DSA handle was correctly updated. The minimal fix is to change two places so they access dead_items through the vacrel. This coding style is a maintenance hazard, so while at it get rid of most other similar usages, which were inconsistently used anyway. Analysis and patch by Vallimaharajan G, with further defensive coding by me Backpath to v17, when TidStore came in Discussion: https://postgr.es/m/1936493cc38.68cb2ef27266.7456585136086197135@zohocorp.com
1 parent 7727049 commit ccc8194

File tree

2 files changed

+9
-15
lines changed

2 files changed

+9
-15
lines changed

src/backend/access/heap/vacuumlazy.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -828,8 +828,6 @@ lazy_scan_heap(LVRelState *vacrel)
828828
next_fsm_block_to_vacuum = 0;
829829
bool all_visible_according_to_vm;
830830

831-
TidStore *dead_items = vacrel->dead_items;
832-
VacDeadItemsInfo *dead_items_info = vacrel->dead_items_info;
833831
Buffer vmbuffer = InvalidBuffer;
834832
const int initprog_index[] = {
835833
PROGRESS_VACUUM_PHASE,
@@ -841,7 +839,7 @@ lazy_scan_heap(LVRelState *vacrel)
841839
/* Report that we're scanning the heap, advertising total # of blocks */
842840
initprog_val[0] = PROGRESS_VACUUM_PHASE_SCAN_HEAP;
843841
initprog_val[1] = rel_pages;
844-
initprog_val[2] = dead_items_info->max_bytes;
842+
initprog_val[2] = vacrel->dead_items_info->max_bytes;
845843
pgstat_progress_update_multi_param(3, initprog_index, initprog_val);
846844

847845
/* Initialize for the first heap_vac_scan_next_block() call */
@@ -884,7 +882,7 @@ lazy_scan_heap(LVRelState *vacrel)
884882
* dead_items TIDs, pause and do a cycle of vacuuming before we tackle
885883
* this page.
886884
*/
887-
if (TidStoreMemoryUsage(dead_items) > dead_items_info->max_bytes)
885+
if (TidStoreMemoryUsage(vacrel->dead_items) > vacrel->dead_items_info->max_bytes)
888886
{
889887
/*
890888
* Before beginning index vacuuming, we release any pin we may
@@ -1054,7 +1052,7 @@ lazy_scan_heap(LVRelState *vacrel)
10541052
* Do index vacuuming (call each index's ambulkdelete routine), then do
10551053
* related heap vacuuming
10561054
*/
1057-
if (dead_items_info->num_items > 0)
1055+
if (vacrel->dead_items_info->num_items > 0)
10581056
lazy_vacuum(vacrel);
10591057

10601058
/*
@@ -2895,19 +2893,18 @@ static void
28952893
dead_items_add(LVRelState *vacrel, BlockNumber blkno, OffsetNumber *offsets,
28962894
int num_offsets)
28972895
{
2898-
TidStore *dead_items = vacrel->dead_items;
28992896
const int prog_index[2] = {
29002897
PROGRESS_VACUUM_NUM_DEAD_ITEM_IDS,
29012898
PROGRESS_VACUUM_DEAD_TUPLE_BYTES
29022899
};
29032900
int64 prog_val[2];
29042901

2905-
TidStoreSetBlockOffsets(dead_items, blkno, offsets, num_offsets);
2902+
TidStoreSetBlockOffsets(vacrel->dead_items, blkno, offsets, num_offsets);
29062903
vacrel->dead_items_info->num_items += num_offsets;
29072904

29082905
/* update the progress information */
29092906
prog_val[0] = vacrel->dead_items_info->num_items;
2910-
prog_val[1] = TidStoreMemoryUsage(dead_items);
2907+
prog_val[1] = TidStoreMemoryUsage(vacrel->dead_items);
29112908
pgstat_progress_update_multi_param(2, prog_index, prog_val);
29122909
}
29132910

@@ -2917,16 +2914,14 @@ dead_items_add(LVRelState *vacrel, BlockNumber blkno, OffsetNumber *offsets,
29172914
static void
29182915
dead_items_reset(LVRelState *vacrel)
29192916
{
2920-
TidStore *dead_items = vacrel->dead_items;
2921-
29222917
if (ParallelVacuumIsActive(vacrel))
29232918
{
29242919
parallel_vacuum_reset_dead_items(vacrel->pvs);
29252920
return;
29262921
}
29272922

29282923
/* Recreate the tidstore with the same max_bytes limitation */
2929-
TidStoreDestroy(dead_items);
2924+
TidStoreDestroy(vacrel->dead_items);
29302925
vacrel->dead_items = TidStoreCreateLocal(vacrel->dead_items_info->max_bytes, true);
29312926

29322927
/* Reset the counter */

src/backend/commands/vacuumparallel.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -474,21 +474,20 @@ parallel_vacuum_get_dead_items(ParallelVacuumState *pvs, VacDeadItemsInfo **dead
474474
void
475475
parallel_vacuum_reset_dead_items(ParallelVacuumState *pvs)
476476
{
477-
TidStore *dead_items = pvs->dead_items;
478477
VacDeadItemsInfo *dead_items_info = &(pvs->shared->dead_items_info);
479478

480479
/*
481480
* Free the current tidstore and return allocated DSA segments to the
482481
* operating system. Then we recreate the tidstore with the same max_bytes
483482
* limitation we just used.
484483
*/
485-
TidStoreDestroy(dead_items);
484+
TidStoreDestroy(pvs->dead_items);
486485
pvs->dead_items = TidStoreCreateShared(dead_items_info->max_bytes,
487486
LWTRANCHE_PARALLEL_VACUUM_DSA);
488487

489488
/* Update the DSA pointer for dead_items to the new one */
490-
pvs->shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(dead_items));
491-
pvs->shared->dead_items_handle = TidStoreGetHandle(dead_items);
489+
pvs->shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(pvs->dead_items));
490+
pvs->shared->dead_items_handle = TidStoreGetHandle(pvs->dead_items);
492491

493492
/* Reset the counter */
494493
dead_items_info->num_items = 0;

0 commit comments

Comments
 (0)