From 27de39f667ab12b78778142fe60e6376f4d49ec3 Mon Sep 17 00:00:00 2001 From: Jacob Champion 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