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

Commit 10685ec

Browse files
committed
Avoid somewhat-theoretical overflow risks in RecordIsValid().
This improves on commit 51fed14 by eliminating the assumption that we can form <some pointer value> + <some offset> without overflow. The entire point of those tests is that we don't trust the offset value, so coding them in a way that could wrap around if the buffer happens to be near the top of memory doesn't seem sound. Instead, track the remaining space as a size_t variable and compare offsets against that. Also, improve comment about why we need the extra early check on xl_tot_len.
1 parent 0f524ea commit 10685ec

File tree

1 file changed

+17
-9
lines changed
  • src/backend/access/transam

1 file changed

+17
-9
lines changed

src/backend/access/transam/xlog.c

+17-9
Original file line numberDiff line numberDiff line change
@@ -3697,7 +3697,10 @@ RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup)
36973697
* record (other than to the minimal extent of computing the amount of
36983698
* data to read in) until we've checked the CRCs.
36993699
*
3700-
* We assume all of the record has been read into memory at *record.
3700+
* We assume all of the record (that is, xl_tot_len bytes) has been read
3701+
* into memory at *record. Also, ValidXLogRecordHeader() has accepted the
3702+
* record's header, which means in particular that xl_tot_len is at least
3703+
* SizeOfXlogRecord, so it is safe to fetch xl_len.
37013704
*/
37023705
static bool
37033706
RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
@@ -3707,17 +3710,18 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
37073710
uint32 len = record->xl_len;
37083711
BkpBlock bkpb;
37093712
char *blk;
3710-
char *recend = (char *) record + record->xl_tot_len;
3713+
size_t remaining = record->xl_tot_len;
37113714

37123715
/* First the rmgr data */
3713-
if (XLogRecGetData(record) + len > recend)
3716+
if (remaining < SizeOfXLogRecord + len)
37143717
{
37153718
/* ValidXLogRecordHeader() should've caught this already... */
37163719
ereport(emode_for_corrupt_record(emode, recptr),
37173720
(errmsg("invalid record length at %X/%X",
37183721
(uint32) (recptr >> 32), (uint32) recptr)));
37193722
return false;
37203723
}
3724+
remaining -= SizeOfXLogRecord + len;
37213725
INIT_CRC32(crc);
37223726
COMP_CRC32(crc, XLogRecGetData(record), len);
37233727

@@ -3730,10 +3734,10 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
37303734
if (!(record->xl_info & XLR_SET_BKP_BLOCK(i)))
37313735
continue;
37323736

3733-
if (blk + sizeof(BkpBlock) > recend)
3737+
if (remaining < sizeof(BkpBlock))
37343738
{
37353739
ereport(emode_for_corrupt_record(emode, recptr),
3736-
(errmsg("incorrect backup block size in record at %X/%X",
3740+
(errmsg("invalid backup block size in record at %X/%X",
37373741
(uint32) (recptr >> 32), (uint32) recptr)));
37383742
return false;
37393743
}
@@ -3748,19 +3752,20 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
37483752
}
37493753
blen = sizeof(BkpBlock) + BLCKSZ - bkpb.hole_length;
37503754

3751-
if (blk + blen > recend)
3755+
if (remaining < blen)
37523756
{
37533757
ereport(emode_for_corrupt_record(emode, recptr),
37543758
(errmsg("invalid backup block size in record at %X/%X",
37553759
(uint32) (recptr >> 32), (uint32) recptr)));
37563760
return false;
37573761
}
3762+
remaining -= blen;
37583763
COMP_CRC32(crc, blk, blen);
37593764
blk += blen;
37603765
}
37613766

37623767
/* Check that xl_tot_len agrees with our calculation */
3763-
if (blk != (char *) record + record->xl_tot_len)
3768+
if (remaining != 0)
37643769
{
37653770
ereport(emode_for_corrupt_record(emode, recptr),
37663771
(errmsg("incorrect total length in record at %X/%X",
@@ -3904,8 +3909,11 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
39043909

39053910
/*
39063911
* If the whole record header is on this page, validate it immediately.
3907-
* Otherwise only do a basic sanity check on xl_tot_len, and validate the
3908-
* rest of the header after reading it from the next page.
3912+
* Otherwise do just a basic sanity check on xl_tot_len, and validate the
3913+
* rest of the header after reading it from the next page. The xl_tot_len
3914+
* check is necessary here to ensure that we enter the "Need to reassemble
3915+
* record" code path below; otherwise we might fail to apply
3916+
* ValidXLogRecordHeader at all.
39093917
*/
39103918
if (targetRecOff <= XLOG_BLCKSZ - SizeOfXLogRecord)
39113919
{

0 commit comments

Comments
 (0)