aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces')
-rw-r--r--src/interfaces/libpq-oauth/oauth-curl.c26
-rw-r--r--src/interfaces/libpq/Makefile11
-rw-r--r--src/interfaces/libpq/fe-auth-oauth.c25
3 files changed, 60 insertions, 2 deletions
diff --git a/src/interfaces/libpq-oauth/oauth-curl.c b/src/interfaces/libpq-oauth/oauth-curl.c
index d13b9cbabb4..dba9a684fa8 100644
--- a/src/interfaces/libpq-oauth/oauth-curl.c
+++ b/src/interfaces/libpq-oauth/oauth-curl.c
@@ -83,6 +83,20 @@
#define MAX_OAUTH_RESPONSE_SIZE (256 * 1024)
/*
+ * Similarly, a limit on the maximum JSON nesting level keeps a server from
+ * running us out of stack space. A common nesting level in practice is 2 (for a
+ * top-level object containing arrays of strings). As of May 2025, the maximum
+ * depth for standard server metadata appears to be 6, if the document contains
+ * a full JSON Web Key Set in its "jwks" parameter.
+ *
+ * Since it's easy to nest JSON, and the number of parameters and key types
+ * keeps growing, take a healthy buffer of 16. (If this ever proves to be a
+ * problem in practice, we may want to switch over to the incremental JSON
+ * parser instead of playing with this parameter.)
+ */
+#define MAX_OAUTH_NESTING_LEVEL 16
+
+/*
* Parsed JSON Representations
*
* As a general rule, we parse and cache only the fields we're currently using.
@@ -495,6 +509,12 @@ oauth_json_object_start(void *state)
}
++ctx->nested;
+ if (ctx->nested > MAX_OAUTH_NESTING_LEVEL)
+ {
+ oauth_parse_set_error(ctx, "JSON is too deeply nested");
+ return JSON_SEM_ACTION_FAILED;
+ }
+
return JSON_SUCCESS;
}
@@ -599,6 +619,12 @@ oauth_json_array_start(void *state)
}
++ctx->nested;
+ if (ctx->nested > MAX_OAUTH_NESTING_LEVEL)
+ {
+ oauth_parse_set_error(ctx, "JSON is too deeply nested");
+ return JSON_SEM_ACTION_FAILED;
+ }
+
return JSON_SUCCESS;
}
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index c6fe5fec7f6..853aab4b1b8 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -98,14 +98,21 @@ SHLIB_PREREQS = submake-libpgport
SHLIB_EXPORTS = exports.txt
+# Appends to a comma-separated list.
+comma := ,
+define add_to_list
+$(eval $1 := $(if $($1),$($1)$(comma) $2,$2))
+endef
+
ifeq ($(with_ssl),openssl)
-PKG_CONFIG_REQUIRES_PRIVATE = libssl, libcrypto
+$(call add_to_list,PKG_CONFIG_REQUIRES_PRIVATE,libssl)
+$(call add_to_list,PKG_CONFIG_REQUIRES_PRIVATE,libcrypto)
endif
ifeq ($(with_libcurl),yes)
# libpq.so doesn't link against libcurl, but libpq.a needs libpq-oauth, and
# libpq-oauth needs libcurl. Put both into *.private.
-PKG_CONFIG_REQUIRES_PRIVATE += libcurl
+$(call add_to_list,PKG_CONFIG_REQUIRES_PRIVATE,libcurl)
%.pc: override SHLIB_LINK_INTERNAL += -lpq-oauth
endif
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);