From 567787f216da750b3805aea6fd8aef19e8b882a1 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Sat, 30 Jun 2012 23:08:34 +0300 Subject: [PATCH] Validate xlog record header before enlarging the work area to store it. If the record header is garbled, we're now quite likely to notice it before we try to make a bogus memory allocation and run out of memory. That can still happen, if the xlog record is split across pages (we cannot verify the record header until reading the next page in that scenario), but this reduces the chances. An out-of-memory is treated as a corrupt record anyway, so this isn't a correctness issue, just a case of giving a better error message. Per Amit Kapila's suggestion. --- src/backend/access/transam/xlog.c | 36 +++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index a1215a0b8c..cbfa68a4e7 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -3829,14 +3829,31 @@ retry: } /* + * Read the record length. + * * NB: Even though we use an XLogRecord pointer here, the whole record - * header might not fit on this page. xl_tot_len is the first field in - * struct, so it must be on this page, but we cannot safely access any - * other fields yet. + * header might not fit on this page. xl_tot_len is the first field of + * the struct, so it must be on this page (the records are MAXALIGNed), + * but we cannot access any other fields until we've verified that we + * got the whole header. */ record = (XLogRecord *) (readBuf + (*RecPtr) % XLOG_BLCKSZ); total_len = record->xl_tot_len; + /* + * If the whole record header is on this page, validate it immediately. + * Otherwise validate it after reading the rest of the header from next + * page. + */ + if (targetRecOff <= XLOG_BLCKSZ - SizeOfXLogRecord) + { + if (!ValidXLogRecordHeader(RecPtr, record, emode, randAccess)) + goto next_record_is_invalid; + gotheader = true; + } + else + gotheader = false; + /* * Allocate or enlarge readRecordBuf as needed. To avoid useless small * increases, round its size to a multiple of XLOG_BLCKSZ, and make sure @@ -3865,19 +3882,6 @@ retry: readRecordBufSize = newSize; } - /* - * If we got the whole header already, validate it immediately. Otherwise - * we validate it after reading the rest of the header from the next page. - */ - if (targetRecOff <= XLOG_BLCKSZ - SizeOfXLogRecord) - { - if (!ValidXLogRecordHeader(RecPtr, record, emode, randAccess)) - goto next_record_is_invalid; - gotheader = true; - } - else - gotheader = false; - len = XLOG_BLCKSZ - (*RecPtr) % XLOG_BLCKSZ; if (total_len > len) {