commit d1aae4b76347b31a72b048fcf31ff82d8012f9ca
parent 053e9d37087c4b51628c69eb703289eb0d6e4a2c
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 6 Aug 2026 08:53:44 +0200
do not die on non-UTF-8 input
Diffstat:
2 files changed, 66 insertions(+), 14 deletions(-)
diff --git a/src/challenger/challenger-httpd_challenge.c b/src/challenger/challenger-httpd_challenge.c
@@ -94,6 +94,13 @@ struct ChallengeContext
char *last_key;
/**
+ * Name of the first uploaded field that could not be represented
+ * in JSON (because the key or the value was not valid UTF-8), or
+ * NULL if all fields were fine.
+ */
+ char *bad_key;
+
+ /**
* Uploaded data during POST processing.
*/
char *data;
@@ -256,6 +263,7 @@ cleanup_ctx (void *cls)
GNUNET_free (bc->data);
GNUNET_free (bc->state);
GNUNET_free (bc->last_key);
+ GNUNET_free (bc->bad_key);
GNUNET_free (bc->client_redirect_uri);
GNUNET_free (bc);
}
@@ -492,6 +500,54 @@ send_tan (struct ChallengeContext *bc)
/**
+ * Store the value accumulated in @a bc->data under @a bc->last_key in
+ * the address object of @a bc, and free both. If the key or the value
+ * is not valid UTF-8 (and thus not representable in JSON), the field is
+ * dropped and its name is remembered in @a bc->bad_key so that the main
+ * handler can fail the request with a 400.
+ *
+ * Both strings are raw bytes from the client, so failure here must
+ * never be fatal to the process.
+ *
+ * @param[in,out] bc context to update
+ */
+static void
+flush_field (struct ChallengeContext *bc)
+{
+ json_t *jkey;
+ json_t *jval;
+
+ /* json_string() returns NULL if the input is not valid UTF-8. */
+ jkey = json_string (bc->last_key);
+ jval = json_string (NULL != bc->data
+ ? bc->data
+ : "");
+ if ( (NULL == jkey) ||
+ (NULL == jval) )
+ {
+ GNUNET_break_op (0);
+ if (NULL == bc->bad_key)
+ bc->bad_key = GNUNET_strdup (
+ (NULL != jkey)
+ ? bc->last_key
+ : "<field name is not valid UTF-8>");
+ }
+ else
+ {
+ GNUNET_assert (0 ==
+ json_object_set (bc->address,
+ bc->last_key,
+ jval));
+ }
+ json_decref (jkey);
+ json_decref (jval);
+ GNUNET_free (bc->last_key);
+ GNUNET_free (bc->data);
+ bc->data_len = 0;
+}
+
+
+/**
* Iterator over key-value pairs where the value may be made available
* in increments and/or may not be zero-terminated. Used for
* processing POST data.
@@ -532,13 +588,7 @@ post_iter (void *cls,
(0 != strcmp (key,
bc->last_key)) )
{
- GNUNET_assert (0 ==
- json_object_set_new (bc->address,
- bc->last_key,
- json_string (bc->data)));
- GNUNET_free (bc->data);
- bc->data_len = 0;
- GNUNET_free (bc->last_key);
+ flush_field (bc);
}
if (NULL == bc->last_key)
{
@@ -818,13 +868,14 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
}
if (NULL != bc->last_key)
{
- GNUNET_assert (0 ==
- json_object_set_new (bc->address,
- bc->last_key,
- json_string (bc->data)));
- GNUNET_free (bc->data);
- bc->data_len = 0;
- GNUNET_free (bc->last_key);
+ flush_field (bc);
+ }
+ if (NULL != bc->bad_key)
+ {
+ return reply_error (bc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ bc->bad_key);
}
#if DEBUG
{
diff --git a/src/challenger/meson.build b/src/challenger/meson.build
@@ -11,6 +11,7 @@ check_SCRIPTS = [
'test-challenger',
'test-challenger-pkce',
'test-challenger-revisit',
+ 'test-challenger-badutf8',
]
test_helper_cat = configure_file(input: 'cat.sh', output: 'cat.sh', copy: true)