Skip to content

Guard JSON container size with compile-time bound#11

Merged
jserv merged 1 commit into
mainfrom
fix-json
May 13, 2026
Merged

Guard JSON container size with compile-time bound#11
jserv merged 1 commit into
mainfrom
fix-json

Conversation

@jserv
Copy link
Copy Markdown
Contributor

@jserv jserv commented May 13, 2026

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.


Summary by cubic

Add compile-time guards in lib/json.c to ensure JSON container counts cannot overflow allocation math. Two static_asserts next to JSON_CONTAINER_MAX guarantee count * sizeof(...) fits in sz, avoiding dead runtime checks and making unsafe bumps fail at build time.

Written for commit 9a2366d. Summary will update on new commits.

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 <mediratta01.pally@gmail.com>
@jserv jserv mentioned this pull request May 13, 2026
3 tasks
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more

@jserv jserv merged commit 9114cf9 into main May 13, 2026
7 checks passed
@jserv jserv deleted the fix-json branch May 13, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant