Hi hackers, I went looking at the other access methods and found a worse case than the one I first reported, so here is a two-patch series.
0001 is what I sent before, unchanged: GiST, B-tree and hash page_items()
follow a line pointer after only checking ItemIdIsValid(), which just tests
that the pointer isn't NULL -- and it never is.
0002 is the new part. Nothing checks the page header at all, and pd_lower
is what PageGetMaxOffsetNumber() is computed from, so two bytes are enough
to walk off the end of the line pointer array.
That includes heap_page_items() crash on a corrupt page:
CREATE TABLE t AS SELECT i FROM generate_series(1,200) i;
-- pd_lower is at offset 12
SELECT
heap_page_items(set_byte(set_byte(get_raw_page('t',0),12,255),13,255));
==ERROR: AddressSanitizer: heap-buffer-overflow READ of size 4
#0 heap_page_items heapfuncs.c:188
So 0002 adds verify_page_header(), using the same checks PageIsVerified()
makes on the header. I didn't call PageIsVerified() itself because it also
verifies the checksum, and there is no block number for a raw bytea; happy
to factor those checks into a shared helper instead, if that's preferred.
I also kept it out of get_page_from_raw(), so page_header() can still show
you have a damaged header.
While I was there, BRIN and GIN turned out to have the same problem as
0001, so 0002 fixes those too.
Thanks,
Shihao
0002-pageinspect-validate-page-headers-and-BRIN-and-GIN-p.patch
Description: Binary data
0001-pageinspect-validate-line-pointers-before-using-them.patch
Description: Binary data
