From e6b5e8b73f50ab43f1d370f1b908eeb2b90fbcf1 Mon Sep 17 00:00:00 2001
From: Ian Ilyasov <ianilyasov@outlook.com>
Date: Tue, 29 Oct 2024 17:59:29 +0300
Subject: [PATCH v2] Fix possible pg_control_data errors on corrupted
 pg_control

Protect against malformed timestamps.  Also protect against negative WalSegSz
as it triggers division by zero:

((0x100000000UL) / (WalSegSz)) can turn into zero in

XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
				 segno, WalSegSz);

because if WalSegSz is -1 then by arithmetic rules in C we get
0x100000000UL / 0xFFFFFFFFFFFFFFFFUL == 0.

Author: Ilyasov Ian <ianilyasov@outlook.com>
Author: Anton Voloshin <a.voloshin@postgrespro.ru>
---
 src/bin/pg_controldata/pg_controldata.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 93a05d80ca7..cf11ab3f2ee 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -97,6 +97,7 @@ main(int argc, char *argv[])
 	bool		crc_ok;
 	char	   *DataDir = NULL;
 	time_t		time_tmp;
+	struct tm  *tm_tmp;
 	char		pgctime_str[128];
 	char		ckpttime_str[128];
 	char		mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1];
@@ -196,20 +197,30 @@ main(int argc, char *argv[])
 	 * about %c
 	 */
 	time_tmp = (time_t) ControlFile->time;
-	strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt,
-			 localtime(&time_tmp));
+	tm_tmp = localtime(&time_tmp);
+
+	if (tm_tmp != NULL)
+		strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, tm_tmp);
+	else
+		snprintf(pgctime_str, sizeof(pgctime_str), _("???"));
+
 	time_tmp = (time_t) ControlFile->checkPointCopy.time;
-	strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt,
-			 localtime(&time_tmp));
+	tm_tmp = localtime(&time_tmp);
+
+	if (tm_tmp != NULL)
+		strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, tm_tmp);
+	else
+		snprintf(ckpttime_str, sizeof(ckpttime_str), _("???"));
 
 	/*
 	 * Calculate name of the WAL file containing the latest checkpoint's REDO
 	 * start point.
 	 *
-	 * A corrupted control file could report a WAL segment size of 0, and to
-	 * guard against division by zero, we need to treat that specially.
+	 * A corrupted control file could report a WAL segment size of 0 or
+	 * negative value, and to guard against division by zero, we need to treat
+	 * that specially.
 	 */
-	if (WalSegSz != 0)
+	if (WalSegSz > 0)
 	{
 		XLogSegNo	segno;
 
-- 
2.39.5 (Apple Git-154)

