commit 8b9954e2236f05114310154302125698935ee4dd
parent ca44fed55ec43230afc1cc1adeb17d8202b10991
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 10 Oct 2026 23:14:14 +0200
enforce caps on array lengths
Diffstat:
3 files changed, 61 insertions(+), 4 deletions(-)
diff --git a/src/util/order_choice_parse.c b/src/util/order_choice_parse.c
@@ -31,6 +31,15 @@
/**
+ * Maximum number of entries we accept in the @e choices array of a v1
+ * order. The array is grown to its JSON length before any entry is
+ * parsed, so the length must be bounded independently of the maximum
+ * upload size.
+ */
+#define MAX_CHOICES 1024
+
+
+/**
* Parse JSON order choice input.
*
* @param[in] root JSON object containing choice input
@@ -250,6 +259,17 @@ parse_order_choices (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ if (MAX_CHOICES < json_array_size (root))
+ {
+ /* 'choices' is untrusted input; reject rather than abort in
+ GNUNET_xmalloc_() (which asserts above 40 MiB). */
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Too many choices in order (%u, at most %u allowed)\n",
+ (unsigned int) json_array_size (root),
+ (unsigned int) MAX_CHOICES);
+ return GNUNET_SYSERR;
+ }
*choices = NULL;
*choices_len = 0;
GNUNET_array_grow (*choices,
diff --git a/src/util/order_parse.c b/src/util/order_parse.c
@@ -31,6 +31,17 @@
/**
+ * Maximum number of entries we accept in the @e products array of an
+ * order. The array is allocated from its JSON length before any entry
+ * is parsed, and phase_merge_inventory() of POST /private/orders puts
+ * @e products_len + 1 words on the stack, so the length must be bounded
+ * independently of the maximum upload size. Same limit as the
+ * MAX_PRODUCTS that bounds the inventory_products of the same request.
+ */
+#define MAX_PRODUCTS 1024
+
+
+/**
* Parse v0-specific fields of @a input JSON into @a order.
*
* @param[in] input the JSON order terms
@@ -265,6 +276,17 @@ TALER_MERCHANT_order_parse (json_t *input)
if (NULL != products)
{
order->products_len = json_array_size (products);
+ if (MAX_PRODUCTS < order->products_len)
+ {
+ /* 'products' is untrusted input; reject rather than abort in
+ GNUNET_xmalloc_() (which asserts above 40 MiB). */
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Too many products in order (%u, at most %u allowed)\n",
+ (unsigned int) order->products_len,
+ (unsigned int) MAX_PRODUCTS);
+ goto cleanup;
+ }
if (0 != order->products_len)
{
size_t i;
diff --git a/src/util/product_parse.c b/src/util/product_parse.c
@@ -24,6 +24,16 @@
#include <gnunet/gnunet_json_lib.h>
#include <taler/taler_json_lib.h>
+
+/**
+ * Maximum number of entries we accept in the @e prices array of a
+ * product. The array is allocated from its JSON length before any
+ * entry is parsed, so the length must be bounded independently of the
+ * maximum upload size.
+ */
+#define MAX_PRICES 1024
+
+
/**
* Parse the given unit quantity string @a s and store the result in @a q.
*
@@ -253,12 +263,17 @@ TALER_MERCHANT_parse_product_sold (const json_t *pj,
size_t i;
json_t *price_i;
- if (len >= UINT_MAX)
+ if (MAX_PRICES < len)
{
- /* 'prices' is untrusted network input; reject rather than abort.
- (The zero-length case is excluded by the guard above, so we
- never call GNUNET_new_array(0, ...).) */
+ /* 'prices' is untrusted network input; reject rather than abort
+ in GNUNET_xmalloc_() (which asserts above 40 MiB). (The
+ zero-length case is excluded by the guard above, so we never
+ call GNUNET_new_array(0, ...).) */
GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Too many prices for product (%u, at most %u allowed)\n",
+ (unsigned int) len,
+ (unsigned int) MAX_PRICES);
return GNUNET_SYSERR;
}
r->prices_length = (unsigned int) len;