From 09634c2b3f63e5afb12d5d65c39d063098873cd2 Mon Sep 17 00:00:00 2001
From: Ranier Vilela <ranier.vf@gmail.com>
Date: Sun, 11 Jul 2021 20:25:59 -0300
Subject: [PATCH v1] _bt_restore_page have issues can lead a memory corrupt.

When recovery tries restore index tuples to a page.

The maximum index tuples per page varies that system to system.
at Windows 64 bits, the MaxIndexTuplesPerPage is 408.
The int *len* parameter allows an unknown number of index tuples,
that can write go beyond array boundaries.

So if _bt_restore_page tries restore a file corrupted or maliciously created,
can write after array bounds.

Fix by checking the upper limit.

Another issue is that _bt_restore_page can increment the pointer *from*,
to after bounds that can point.

Fix by removing the unnecessary increment.

While there, reduce scope of two variables.

Author: Ranier Vilela (ranier.vf@gmail.com)
---
 src/backend/access/nbtree/nbtxlog.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index c2e920f159..27282e9c8f 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -35,11 +35,9 @@ static MemoryContext opCtx;		/* working memory for operations */
  * the one with highest item number appears first (lowest on the page).
  */
 static void
-_bt_restore_page(Page page, char *from, int len)
+_bt_restore_page(Page page, char *from, Size len)
 {
-	IndexTupleData itupdata;
-	Size		itemsz;
-	char	   *end = from + len;
+	const char *end = from + len;
 	Item		items[MaxIndexTuplesPerPage];
 	uint16		itemsizes[MaxIndexTuplesPerPage];
 	int			i;
@@ -49,10 +47,14 @@ _bt_restore_page(Page page, char *from, int len)
 	 * To get the items back in the original order, we add them to the page in
 	 * reverse.  To figure out where one tuple ends and another begins, we
 	 * have to scan them in forward order first.
+	 * Check the array upper limit to not overtake him.
 	 */
 	i = 0;
-	while (from < end)
+	while (from < end && i <= MaxIndexTuplesPerPage)
 	{
+		IndexTupleData itupdata;
+		Size		itemsz;
+
 		/*
 		 * As we step through the items, 'from' won't always be properly
 		 * aligned, so we need to use memcpy().  Further, we use Item (which
@@ -77,7 +79,6 @@ _bt_restore_page(Page page, char *from, int len)
 		if (PageAddItem(page, items[i], itemsizes[i], nitems - i,
 						false, false) == InvalidOffsetNumber)
 			elog(PANIC, "_bt_restore_page: cannot add item to page");
-		from += itemsz;
 	}
 }
 
-- 
2.32.0.windows.1

