From 9a2366d9e8d178acba1c6e1c35446aa3f5508725 Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Thu, 14 May 2026 03:29:11 +0800 Subject: [PATCH] Guard JSON container size with compile-time bound A scanner flagged the count * sizeof(struct json_value) and count * sizeof(struct json_kv) sites in lib/json.c as a heap overflow risk: if count were attacker-controlled and approached SZ_MAX / sizeof(...), the multiplication would wrap, the arena allocation would be undersized, and the following memcpy would overflow the heap. The premise does not actually hold in this code path. Both call sites sit after a loop that bounds count at JSON_CONTAINER_MAX=64 before each increment, so the multiplication is at most 64*sizeof(struct json_value) inside sz. Adding a runtime "count > SZ_MAX / sizeof(...)" guard would produce dead code on every supported platform. Instead, anchor the invariant at the bound itself with 2 static_assert lines next to the #define JSON_CONTAINER_MAX. Any future bump that would break the no-wrap property fails at build time, not at runtime, and the surrounding parser stays free of unreachable branches. Reported-by: orbisai0security --- lib/json.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/json.c b/lib/json.c index 24fbbe4..a4fe51c 100644 --- a/lib/json.c +++ b/lib/json.c @@ -229,6 +229,16 @@ static bool jp_match(struct json_parser *p, const char *s, sz len) #define JSON_CONTAINER_MAX 64 +/* Bound the per-container element count so that 'count * sizeof(element)' + * is provably representable in 'sz' and cannot wrap. Callers further down + * pass 'count' to arena_alloc_array() and memcpy(); without this compile + * time bound the multiplication would need a runtime overflow guard. + */ +static_assert(JSON_CONTAINER_MAX <= SZ_MAX / sizeof(struct json_value), + "JSON_CONTAINER_MAX too large for json_value allocation"); +static_assert(JSON_CONTAINER_MAX <= SZ_MAX / sizeof(struct json_kv), + "JSON_CONTAINER_MAX too large for json_kv allocation"); + static struct json_result jp_parse_array(struct json_parser *p) { if (p->depth >= JSON_MAX_DEPTH)