From 8db922e3d1ebccdc53dd6b82e49fe94916f6556e Mon Sep 17 00:00:00 2001 From: hanjinpeng Date: Mon, 14 Sep 2026 09:11:38 -0400 Subject: [PATCH] tokener: validate depth and printbuf, guard key strdup - fjson_tokener_new_ex() rejected no depth check: depth <= 0 called calloc(0, ...) and fjson_tokener_reset() then wrote stack[0], a heap buffer overflow. Reject depth < 1 up front. - fjson_tokener_new_ex() ignored a printbuf_new() failure, leaving tok->pb == NULL to be dereferenced during parsing. Check it and clean up on failure. - the object-key strdup() failure was unchecked; a NULL key is later treated as an empty slot and also passed to strcmp(). Bail out with an error instead. --- json_tokener.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/json_tokener.c b/json_tokener.c index 48d4109..73cb6d9 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -107,6 +107,11 @@ struct fjson_tokener *fjson_tokener_new_ex(int depth) { struct fjson_tokener *tok; + /* depth must be at least 1: fjson_tokener_reset() writes stack[0]. + * A non-positive depth would calloc(0, ...) and then overflow. */ + if (depth < 1) + return NULL; + tok = (struct fjson_tokener *)calloc(1, sizeof(struct fjson_tokener)); if (!tok) return NULL; @@ -116,6 +121,11 @@ struct fjson_tokener *fjson_tokener_new_ex(int depth) return NULL; } tok->pb = printbuf_new(); + if (!tok->pb) { + free(tok->stack); + free(tok); + return NULL; + } tok->max_depth = depth; fjson_tokener_reset(tok); return tok; @@ -857,6 +867,13 @@ struct fjson_object *fjson_tokener_parse_ex(struct fjson_tokener *tok, const cha if (c == tok->quote_char) { printbuf_memappend_fast(tok->pb, case_start, str - case_start); obj_field_name = strdup(tok->pb->buf); + if (obj_field_name == NULL) { + /* out of memory: a NULL key would be + * interpreted as an empty slot, so we + * must not continue. */ + tok->err = fjson_tokener_error_parse_eof; + goto out; + } saved_state = fjson_tokener_state_object_field_end; state = fjson_tokener_state_eatws; break;