From 82942e629508a2f78b19e960e2d8ffaa55152cb1 Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Sun, 27 Sep 2026 12:48:04 +0000 Subject: [PATCH v1 2/7] gin: check each posting list segment fits before decoding it ginPostingListDecodeAllSegments() set endptr from segment->nbytes and stepped to the next segment with GinNextPostingListSegment() without checking either against the end of the posting list, so a corrupt page could be read past its end. Check that each segment header and the nbytes it claims lie within the remaining length first, comparing sizes so no out-of-bounds pointer is formed. --- src/backend/access/gin/ginpostinglist.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c index 89da084bbe8..f7dec6318c9 100644 --- a/src/backend/access/gin/ginpostinglist.c +++ b/src/backend/access/gin/ginpostinglist.c @@ -287,6 +287,19 @@ ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_ ndecoded = 0; while ((char *) segment < endseg) { + /* + * Reject a segment that runs past the end of the posting list. + * Compare sizes rather than forming segment + + * SizeOfGinPostingList(segment), which would be an out-of-bounds + * pointer. The header is tested before nbytes is read, and the loop + * condition keeps endseg - segment positive for the unsigned cast. + */ + if (offsetof(GinPostingList, bytes) > (Size) (endseg - (char *) segment) || + SizeOfGinPostingList(segment) > (Size) (endseg - (char *) segment)) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("corrupted GIN posting list"))); + /* enlarge output array if needed */ if (ndecoded >= nallocated) { -- 2.17.1