aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-auth-oauth.c
diff options
context:
space:
mode:
authorJacob Champion <jchampion@postgresql.org>2025-05-23 13:05:33 -0700
committerJacob Champion <jchampion@postgresql.org>2025-05-23 13:05:33 -0700
commitcbc8fd0c9aec01f451af5e4eeb0eb2c5d5e47eb2 (patch)
tree643d5d4f0f6c129b81b0647f4531251cd95e66a7 /src/interfaces/libpq/fe-auth-oauth.c
parent1ca583f6c0f9c178dd2721886c723791ced65520 (diff)
downloadpostgresql-cbc8fd0c9aec01f451af5e4eeb0eb2c5d5e47eb2.tar.gz
postgresql-cbc8fd0c9aec01f451af5e4eeb0eb2c5d5e47eb2.zip
oauth: Limit JSON parsing depth in the client
Check the ctx->nested level as we go, to prevent a server from running the client out of stack space. The limit we choose when communicating with authorization servers can't be overly strict, since those servers will continue to add extensions in their JSON documents which we need to correctly ignore. For the SASL communication, we can be more conservative, since there are no defined extensions (and the peer is probably more Postgres code). Reviewed-by: Aleksander Alekseev <aleksander@timescale.com> Discussion: https://postgr.es/m/CAOYmi%2Bm71aRUEi0oQE9ciBnBS8xVtMn3CifaPu2kmJzUfhOZgA%40mail.gmail.com
Diffstat (limited to 'src/interfaces/libpq/fe-auth-oauth.c')
-rw-r--r--src/interfaces/libpq/fe-auth-oauth.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/interfaces/libpq/fe-auth-oauth.c b/src/interfaces/libpq/fe-auth-oauth.c
index 9fbff89a21d..d146c5f567c 100644
--- a/src/interfaces/libpq/fe-auth-oauth.c
+++ b/src/interfaces/libpq/fe-auth-oauth.c
@@ -157,6 +157,14 @@ client_initial_response(PGconn *conn, bool discover)
#define ERROR_SCOPE_FIELD "scope"
#define ERROR_OPENID_CONFIGURATION_FIELD "openid-configuration"
+/*
+ * Limit the maximum number of nested objects/arrays. Because OAUTHBEARER
+ * doesn't have any defined extensions for its JSON yet, we can be much more
+ * conservative here than with libpq-oauth's MAX_OAUTH_NESTING_LEVEL; we expect
+ * a nesting level of 1 in practice.
+ */
+#define MAX_SASL_NESTING_LEVEL 8
+
struct json_ctx
{
char *errmsg; /* any non-NULL value stops all processing */
@@ -196,6 +204,9 @@ oauth_json_object_start(void *state)
}
++ctx->nested;
+ if (ctx->nested > MAX_SASL_NESTING_LEVEL)
+ oauth_json_set_error(ctx, libpq_gettext("JSON is too deeply nested"));
+
return oauth_json_has_error(ctx) ? JSON_SEM_ACTION_FAILED : JSON_SUCCESS;
}
@@ -254,10 +265,23 @@ oauth_json_array_start(void *state)
ctx->target_field_name);
}
+ ++ctx->nested;
+ if (ctx->nested > MAX_SASL_NESTING_LEVEL)
+ oauth_json_set_error(ctx, libpq_gettext("JSON is too deeply nested"));
+
return oauth_json_has_error(ctx) ? JSON_SEM_ACTION_FAILED : JSON_SUCCESS;
}
static JsonParseErrorType
+oauth_json_array_end(void *state)
+{
+ struct json_ctx *ctx = state;
+
+ --ctx->nested;
+ return JSON_SUCCESS;
+}
+
+static JsonParseErrorType
oauth_json_scalar(void *state, char *token, JsonTokenType type)
{
struct json_ctx *ctx = state;
@@ -519,6 +543,7 @@ handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
sem.object_end = oauth_json_object_end;
sem.object_field_start = oauth_json_object_field_start;
sem.array_start = oauth_json_array_start;
+ sem.array_end = oauth_json_array_end;
sem.scalar = oauth_json_scalar;
err = pg_parse_json(lex, &sem);