From 27de39f667ab12b78778142fe60e6376f4d49ec3 Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Thu, 23 Apr 2026 09:46:42 -0700
Subject: [PATCH] libpq-oauth: Avoid overflow for very large intervals

---
 src/interfaces/libpq-oauth/oauth-curl.c | 38 ++++++++++++++++++-------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/src/interfaces/libpq-oauth/oauth-curl.c b/src/interfaces/libpq-oauth/oauth-curl.c
index abbef93f95f..70cc4710b59 100644
--- a/src/interfaces/libpq-oauth/oauth-curl.c
+++ b/src/interfaces/libpq-oauth/oauth-curl.c
@@ -28,6 +28,7 @@
 #error libpq-oauth is not supported on this platform
 #endif
 
+#include "common/int.h"
 #include "common/jsonapi.h"
 #include "mb/pg_wchar.h"
 #include "oauth-curl.h"
@@ -136,7 +137,7 @@ struct device_authz
 
 	/* Fields below are parsed from the corresponding string above. */
 	int			expires_in;
-	int			interval;
+	int32		interval;
 };
 
 static void
@@ -1020,7 +1021,7 @@ parse_json_number(const char *s)
  * expensive network polling loop.) Tests may remove the lower bound with
  * PGOAUTHDEBUG, for improved performance.
  */
-static int
+static int32
 parse_interval(struct async_ctx *actx, const char *interval_str)
 {
 	double		parsed;
@@ -1031,8 +1032,8 @@ parse_interval(struct async_ctx *actx, const char *interval_str)
 	if (parsed < 1)
 		return (actx->debug_flags & OAUTHDEBUG_UNSAFE_DOS_ENDPOINT) ? 0 : 1;
 
-	else if (parsed >= INT_MAX)
-		return INT_MAX;
+	else if (parsed >= INT32_MAX)
+		return INT32_MAX;
 
 	return parsed;
 }
@@ -2620,10 +2621,7 @@ handle_token_response(struct async_ctx *actx, char **token)
 	 */
 	if (strcmp(err->error, "slow_down") == 0)
 	{
-		int			prev_interval = actx->authz.interval;
-
-		actx->authz.interval += 5;
-		if (actx->authz.interval < prev_interval)
+		if (pg_add_s32_overflow(actx->authz.interval, 5, &actx->authz.interval))
 		{
 			actx_error(actx, "slow_down interval overflow");
 			goto token_cleanup;
@@ -2949,8 +2947,28 @@ pg_fe_run_oauth_flow_impl(PGconn *conn, PGoauthBearerRequestV2 *request,
 				 * Wait for the required interval before issuing the next
 				 * request.
 				 */
-				if (!set_timer(actx, actx->authz.interval * 1000))
-					goto error_return;
+				{
+					/*
+					 * LONG_MAX milliseconds is 24 days on 32-bit platforms,
+					 * which for most people is going to be equivalent to a
+					 * disabled timer... but avoid overflow in case the
+					 * compiler does something unintuitive.
+					 */
+					int64		interval_ms;
+
+					/*
+					 * If you trip over this, the multiplication here needs to
+					 * be adjusted for overflow too.
+					 */
+					static_assert(sizeof(actx->authz.interval) <= 4);
+
+					interval_ms = actx->authz.interval * ((int64) 1000);
+					if (interval_ms > LONG_MAX)
+						interval_ms = LONG_MAX;
+
+					if (!set_timer(actx, (long) interval_ms))
+						goto error_return;
+				}
 
 				/*
 				 * No Curl requests are running, so we can simplify by having
-- 
2.34.1

