Skip to content

Commit dac3660

Browse files
committed
Fix out-of-bounds access in autoprewarm worker
The read stream callback apw_read_stream_next_block() advances p->pos through the block_info array. When processing the last block, it increments p->pos to prewarm_stop_idx before returning. The callback itself is safe because it checks bounds before accessing the array. However, the caller assigned blk from block_info[i] at the end of the loop body, before the loop condition was re-evaluated. When i equaled prewarm_stop_idx, this accessed memory beyond the allocated DSM segment, causing a segfault. Restructure the loop to check bounds at the top and assign blk at the beginning of the loop body, where it is always safe. This avoids the need for an explicit bounds check at the end. Backpatch to 18, where the bug was introduced by commit 6acab8b. Author: Matheus Alcantara <mths.dev@pm.me> Reported-by: Glauber Batista <glauberrbatista@gmail.com> Reviewed-by: Melanie Plageman <melanieplageman@gmail.com> Reviewed-by: Tomas Vondra <tomas@vondra.me> Backpatch-through: 18 Discussion: https://www.postgresql.org/message-id/CAO%2B_mTQgQyTYwDh%3DU8iTnsDmOGyWsZJjUV31SmEYwmw6_xY6Bw%40mail.gmail.com
1 parent ed9ec3a commit dac3660

1 file changed

Lines changed: 16 additions & 6 deletions

File tree

contrib/pg_prewarm/autoprewarm.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -572,16 +572,23 @@ autoprewarm_database_main(Datum main_arg)
572572
* valid forks or run out of options, we'll close the relation and
573573
* move on.
574574
*/
575-
while (i < apw_state->prewarm_stop_idx &&
576-
blk.tablespace == tablespace &&
577-
blk.filenumber == filenumber)
575+
while (i < apw_state->prewarm_stop_idx)
578576
{
579-
ForkNumber forknum = blk.forknum;
577+
ForkNumber forknum;
580578
BlockNumber nblocks;
581579
struct AutoPrewarmReadStreamData p;
582580
ReadStream *stream;
583581
Buffer buf;
584582

583+
blk = block_info[i];
584+
585+
/* Stop when we reach a different relation. */
586+
if (blk.tablespace != tablespace ||
587+
blk.filenumber != filenumber)
588+
break;
589+
590+
forknum = blk.forknum;
591+
585592
/*
586593
* smgrexists is not safe for illegal forknum, hence check whether
587594
* the passed forknum is valid before using it in smgrexists.
@@ -643,9 +650,12 @@ autoprewarm_database_main(Datum main_arg)
643650

644651
read_stream_end(stream);
645652

646-
/* Advance i past all the blocks just prewarmed. */
653+
/*
654+
* Advance i past all the blocks just prewarmed. Note that the
655+
* callback might have advanced the index beyond the last valid
656+
* block, so don't access block_info[i] yet.
657+
*/
647658
i = p.pos;
648-
blk = block_info[i];
649659
}
650660

651661
relation_close(rel, AccessShareLock);

0 commit comments

Comments
 (0)