commit 60024bbd1180e938c44a10753d53d79a6b6affd0
parent 93a1a1cdae66ab06c0fa3f23332f6faada936e27
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Sun, 19 Jul 2026 15:15:06 +0200
guard against large chunked uploads
Diffstat:
4 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/src/challenger/challenger-httpd_challenge.c b/src/challenger/challenger-httpd_challenge.c
@@ -183,6 +183,11 @@ struct ChallengeContext
* Is the upload in JSON?
*/
bool is_json;
+
+ /**
+ * Set to true if the upload is too big.
+ */
+ bool too_big;
};
@@ -539,6 +544,15 @@ post_iter (void *cls,
{
bc->last_key = GNUNET_strdup (key);
}
+ /* Hard cap independent of Content-Length: TALER_MHD_check_content_length()
+ does not reject requests that omit Content-Length (e.g. chunked uploads),
+ so without this guard an attacker could stream an unbounded field value. */
+ if (bc->data_len + size > 1024)
+ {
+ GNUNET_break_op (0);
+ bc->too_big = true;
+ return MHD_NO;
+ }
bc->data = GNUNET_realloc (bc->data,
bc->data_len + size + 1);
memcpy (bc->data + bc->data_len,
@@ -764,6 +778,15 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
GNUNET_break (0);
return MHD_NO;
}
+ if (bc->too_big)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ hc->connection,
+ MHD_HTTP_CONTENT_TOO_LARGE,
+ TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT,
+ NULL);
+ }
if (NULL != bc->last_key)
{
GNUNET_assert (0 ==
diff --git a/src/challenger/challenger-httpd_solve.c b/src/challenger/challenger-httpd_solve.c
@@ -92,6 +92,10 @@ struct SolveContext
*/
uint32_t pin_transmissions_left;
+ /**
+ * Set to true if the upload is too big.
+ */
+ bool too_big;
};
@@ -157,6 +161,15 @@ post_iter (void *cls,
return MHD_YES;
if (MHD_POSTDATA_KIND != kind)
return MHD_YES;
+ /* Hard cap independent of Content-Length: TALER_MHD_check_content_length()
+ does not reject requests that omit Content-Length (e.g. chunked uploads),
+ so without this guard an attacker could stream an unbounded 'pin' value. */
+ if (bc->pin_len + size > 1024)
+ {
+ bc->too_big = true;
+ GNUNET_break_op (0);
+ return MHD_NO;
+ }
bc->pin = GNUNET_realloc (bc->pin,
bc->pin_len + size + 1);
memcpy (bc->pin + bc->pin_len,
@@ -225,6 +238,15 @@ CH_handler_solve (struct CH_HandlerContext *hc,
return MHD_YES;
return MHD_NO;
}
+ if (bc->too_big)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ hc->connection,
+ MHD_HTTP_CONTENT_TOO_LARGE,
+ TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT,
+ NULL);
+ }
if (NULL == bc->pin)
{
GNUNET_break_op (0);
diff --git a/src/challenger/challenger-httpd_token.c b/src/challenger/challenger-httpd_token.c
@@ -79,6 +79,11 @@ struct TokenContext
* Uploaded 'code_verifier' field from POST data.
*/
char *code_verifier;
+
+ /**
+ * Set to true if the upload was too big.
+ */
+ bool too_big;
};
@@ -189,6 +194,15 @@ post_iter (void *cls,
slen = 0;
else
slen = strlen (*ptr);
+ /* Hard cap independent of Content-Length: TALER_MHD_check_content_length()
+ does not reject requests that omit Content-Length (e.g. chunked uploads),
+ so without this guard an attacker could stream an unbounded field value. */
+ if (slen + size > 2 * 1024)
+ {
+ GNUNET_break_op (0);
+ bc->too_big = true;
+ return MHD_NO;
+ }
if (NULL == *ptr)
*ptr = GNUNET_malloc (size + 1);
else
@@ -246,6 +260,15 @@ CH_handler_token (struct CH_HandlerContext *hc,
return MHD_YES;
return MHD_NO;
}
+ if (bc->too_big)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ hc->connection,
+ MHD_HTTP_CONTENT_TOO_LARGE,
+ TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT,
+ NULL);
+ }
if (NULL == bc->grant_type)
{
/* RFC 6749 5.2: a missing required parameter is 'invalid_request', not
diff --git a/src/challengerdb/token_add_token.c b/src/challengerdb/token_add_token.c
@@ -63,7 +63,10 @@ CHALLENGERDB_token_add_token (struct CHALLENGERDB_PostgresContext *ctx,
" ,token_expiration_time"
" ,address_expiration_time"
") SELECT"
- " $2, address, $3, $4 + last_tx_time"
+ " $2"
+ " ,address"
+ " ,$3"
+ " ,LEAST($4, 9223372036854775807::BIGINT - last_tx_time) + last_tx_time"
" FROM consumed;");
return GNUNET_PQ_eval_prepared_non_select (ctx->conn,
"token_add_token",