@@ -3697,7 +3697,10 @@ RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup)
3697
3697
* record (other than to the minimal extent of computing the amount of
3698
3698
* data to read in) until we've checked the CRCs.
3699
3699
*
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.
3701
3704
*/
3702
3705
static bool
3703
3706
RecordIsValid (XLogRecord * record , XLogRecPtr recptr , int emode )
@@ -3707,17 +3710,18 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
3707
3710
uint32 len = record -> xl_len ;
3708
3711
BkpBlock bkpb ;
3709
3712
char * blk ;
3710
- char * recend = ( char * ) record + record -> xl_tot_len ;
3713
+ size_t remaining = record -> xl_tot_len ;
3711
3714
3712
3715
/* First the rmgr data */
3713
- if (XLogRecGetData ( record ) + len > recend )
3716
+ if (remaining < SizeOfXLogRecord + len )
3714
3717
{
3715
3718
/* ValidXLogRecordHeader() should've caught this already... */
3716
3719
ereport (emode_for_corrupt_record (emode , recptr ),
3717
3720
(errmsg ("invalid record length at %X/%X" ,
3718
3721
(uint32 ) (recptr >> 32 ), (uint32 ) recptr )));
3719
3722
return false;
3720
3723
}
3724
+ remaining -= SizeOfXLogRecord + len ;
3721
3725
INIT_CRC32 (crc );
3722
3726
COMP_CRC32 (crc , XLogRecGetData (record ), len );
3723
3727
@@ -3730,10 +3734,10 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
3730
3734
if (!(record -> xl_info & XLR_SET_BKP_BLOCK (i )))
3731
3735
continue ;
3732
3736
3733
- if (blk + sizeof (BkpBlock ) > recend )
3737
+ if (remaining < sizeof (BkpBlock ))
3734
3738
{
3735
3739
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" ,
3737
3741
(uint32 ) (recptr >> 32 ), (uint32 ) recptr )));
3738
3742
return false;
3739
3743
}
@@ -3748,19 +3752,20 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
3748
3752
}
3749
3753
blen = sizeof (BkpBlock ) + BLCKSZ - bkpb .hole_length ;
3750
3754
3751
- if (blk + blen > recend )
3755
+ if (remaining < blen )
3752
3756
{
3753
3757
ereport (emode_for_corrupt_record (emode , recptr ),
3754
3758
(errmsg ("invalid backup block size in record at %X/%X" ,
3755
3759
(uint32 ) (recptr >> 32 ), (uint32 ) recptr )));
3756
3760
return false;
3757
3761
}
3762
+ remaining -= blen ;
3758
3763
COMP_CRC32 (crc , blk , blen );
3759
3764
blk += blen ;
3760
3765
}
3761
3766
3762
3767
/* Check that xl_tot_len agrees with our calculation */
3763
- if (blk != ( char * ) record + record -> xl_tot_len )
3768
+ if (remaining != 0 )
3764
3769
{
3765
3770
ereport (emode_for_corrupt_record (emode , recptr ),
3766
3771
(errmsg ("incorrect total length in record at %X/%X" ,
@@ -3904,8 +3909,11 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
3904
3909
3905
3910
/*
3906
3911
* 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.
3909
3917
*/
3910
3918
if (targetRecOff <= XLOG_BLCKSZ - SizeOfXLogRecord )
3911
3919
{
0 commit comments