From 5d7eb3cc2e0fb36bc731dfe08b68068389cef4d5 Mon Sep 17 00:00:00 2001
From: Sehrope Sarkuni <sehrope@jackdb.com>
Date: Sun, 27 Sep 2026 12:48:04 +0000
Subject: [PATCH v1 1/7] gin: bound decode_varbyte() against the segment end

decode_varbyte() had no end pointer and stopped only on a byte without the
continuation bit set, so a corrupt stream ran past the segment.  Pass the
segment end in and stop at it, treating a truncated integer or one longer than
the encoding can produce as corruption.  The seven-way nesting becomes a loop.
---
 src/backend/access/gin/ginpostinglist.c | 56 +++++++------------------
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c
index 07656574029..89da084bbe8 100644
--- a/src/backend/access/gin/ginpostinglist.c
+++ b/src/backend/access/gin/ginpostinglist.c
@@ -130,51 +130,25 @@ encode_varbyte(uint64 val, unsigned char **ptr)
  * Decode varbyte-encoded integer at *ptr. *ptr is incremented to next integer.
  */
 static uint64
-decode_varbyte(unsigned char **ptr)
+decode_varbyte(unsigned char **ptr, unsigned char *endptr)
 {
-	uint64		val;
+	uint64		val = 0;
 	unsigned char *p = *ptr;
-	uint64		c;
 
-	/* 1st byte */
-	c = *(p++);
-	val = c & 0x7F;
-	if (c & 0x80)
+	for (int i = 0;; i++)
 	{
-		/* 2nd byte */
+		uint64		c;
+
+		if (p >= endptr || i >= MaxBytesPerInteger)
+			ereport(ERROR,
+					(errcode(ERRCODE_DATA_CORRUPTED),
+					 errmsg("corrupted GIN posting list")));
+
 		c = *(p++);
-		val |= (c & 0x7F) << 7;
-		if (c & 0x80)
-		{
-			/* 3rd byte */
-			c = *(p++);
-			val |= (c & 0x7F) << 14;
-			if (c & 0x80)
-			{
-				/* 4th byte */
-				c = *(p++);
-				val |= (c & 0x7F) << 21;
-				if (c & 0x80)
-				{
-					/* 5th byte */
-					c = *(p++);
-					val |= (c & 0x7F) << 28;
-					if (c & 0x80)
-					{
-						/* 6th byte */
-						c = *(p++);
-						val |= (c & 0x7F) << 35;
-						if (c & 0x80)
-						{
-							/* 7th byte, should not have continuation bit */
-							c = *(p++);
-							val |= c << 42;
-							Assert((c & 0x80) == 0);
-						}
-					}
-				}
-			}
-		}
+		val |= (c & 0x7F) << (7 * i);
+
+		if ((c & 0x80) == 0)
+			break;
 	}
 
 	*ptr = p;
@@ -338,7 +312,7 @@ ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_
 				result = repalloc_array(result, ItemPointerData, nallocated);
 			}
 
-			val += decode_varbyte(&ptr);
+			val += decode_varbyte(&ptr, endptr);
 
 			uint64_to_itemptr(val, &result[ndecoded]);
 			ndecoded++;
-- 
2.17.1

