Commit 55bd49c
committed
libretro-db: fix OOM bugs in rmsgpack_dom reader state and query parser
Five related fixes across libretro-db's runtime code (the subset
linked into RetroArch itself - c_converter.c and similar offline
tools are out of scope for this patch).
=== rmsgpack_dom.c: rmsgpack_dom_reader_state_new unchecked callocs ===
struct rmsgpack_dom_reader_state *s = calloc(1, ...);
s->i = 0; /* NULL-deref on OOM */
s->capacity = 1024;
s->growable = true;
s->stack = calloc(1024, ...);
return s;
Both callocs unchecked. The outer calloc's failure NULL-derefs
on the immediate field writes. The inner (stack) calloc's
failure is caught later when callers iterate - rmsgpack_dom_read
at line ~422 does 's->stack[0] = out' unconditionally.
Fix: NULL-check the outer calloc and return NULL. NULL-check
the inner calloc and free the outer struct + return NULL on
failure. Callers must now tolerate NULL return.
=== rmsgpack_dom.c: rmsgpack_dom_reader_state_free NULL-deref ===
free(state->stack); /* NULL-deref if state is NULL */
free(state);
state could not be NULL pre-patch (construction couldn't fail)
but with reader_state_new now able to return NULL, callers that
defer cleanup (like input/bsv/bsvmovie.c's decompress path)
would hit this free with NULL.
Fix: early return on NULL state.
=== rmsgpack_dom.c: rmsgpack_dom_reader_state_push realloc-assign-self ===
s->capacity *= 2;
s->stack = realloc(s->stack, s->capacity * ...);
if (!s->stack)
return -1;
Two stacked bugs:
1. Classic realloc-assign-self: on OOM s->stack goes NULL,
leaking the old buffer (the only reference).
2. 'capacity *= 2' happens BEFORE the realloc, so on failure
the capacity claimed the new size while the allocation is
still the old size (or NULL). The -1 return is checked by
the direct caller, but the out-of-sync state is a heap-
buffer-overflow trap if anything later ignored the error
return.
Fix: realloc-to-tmp. Compute new_capacity into a local, realloc
into new_stack, commit both only on success. Preserves the -1
OOM signal semantics.
=== query.c: query_parse_method_call zero-arg false-OOM ===
invocation->argv = (argi > 0) ? malloc(...) : NULL;
if (!invocation->argv)
{
/* emit 'OOM' error */
goto clean;
}
argv is legitimately NULL when argi == 0 (a zero-argument
function call like 'foo()') but the next block treated that as
OOM and raised the 'OOM' error string.
This was a pre-existing logic bug tangentially exposed by OOM
auditing. The observable symptom pre-patch was that any
genuinely-zero-argument function call would fail query parsing
with a bogus 'OOM' error.
Fix: gate the OOM branch on 'argi > 0 && !invocation->argv'.
Skip the memcpy when argv is NULL (nothing to copy when argi==0).
=== input/bsv/bsvmovie.c: bsv_movie_read_deduped_state consumer ===
struct rmsgpack_dom_reader_state *reader_state =
rmsgpack_dom_reader_state_new();
...
rmsgpack_dom_read_with(read_mem, &item, reader_state);
With rmsgpack_dom_reader_state_new now able to return NULL, this
caller needs to NULL-check before passing reader_state into
rmsgpack_dom_read_with (which dereferences it freely).
Fix: early bail to the existing 'exit' cleanup label on NULL.
The cleanup already calls rmsgpack_dom_reader_state_free (now
NULL-tolerant), intfstream_close (already NULL-tolerant), and
sets ret=false, so the user-visible outcome on OOM is the same
as the existing 'malformed frame' error paths.
=== Scope notes ===
Other libretro-db files checked during this pass:
* bintree.c - the single alloc site at line 35 is already
NULL-checked.
* libretrodb.c - two sites at lines 771 (buff in create_index)
and 831 (cursor_new) both use the NULL-check idiom.
* rmsgpack.c - zero raw alloc sites.
* Inner callocs in rmsgpack_dom.c:145 (dom_read_map_start) and
:173 (dom_read_array_start) use the 'if (!(items = ...))'
idiom and propagate -1 up the rmsgpack callback chain.
Not in scope (standalone offline utilities, not linked into
RetroArch runtime - see libretro-db/Makefile TARGETS):
* c_converter.c - 7 alloc sites
* libretrodb_tool.c
* rmsgpack_test.c
=== Thread-safety ===
All touched paths run synchronously on whichever thread invoked
the db query. In practice RetroArch accesses libretro-db from
the main thread (menu content scanning, explore-by-metadata)
and from task threads (background scan). No shared-state
changes; no lock discipline changes.
=== Reachability ===
* rmsgpack_dom_reader_state_new/free: the allocating variant
is only called from input/bsv/bsvmovie.c's STATESTREAM
decode path, used during savestate runahead on cores that
support bsv movie recording.
* rmsgpack_dom_reader_state_push: called recursively while
parsing deep msgpack maps/arrays inside a libretrodb .rdb
query result. Capacity doublings trigger on deeply nested
data (the default capacity is 1024 for the allocating
variant, MAX_DEPTH stack-alloca for rmsgpack_dom_read - the
stack variant sets growable=false so never reaches this
realloc path).
* query_parse_method_call: every libretrodb query string
parse - menu-driven 'Explore' category navigation and any
core's database-backed metadata lookup.1 parent 3785495 commit 55bd49c
3 files changed
Lines changed: 57 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1658 | 1658 | | |
1659 | 1659 | | |
1660 | 1660 | | |
| 1661 | + | |
| 1662 | + | |
| 1663 | + | |
| 1664 | + | |
| 1665 | + | |
| 1666 | + | |
| 1667 | + | |
| 1668 | + | |
| 1669 | + | |
| 1670 | + | |
| 1671 | + | |
1661 | 1672 | | |
1662 | 1673 | | |
1663 | 1674 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
943 | 943 | | |
944 | 944 | | |
945 | 945 | | |
946 | | - | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
947 | 951 | | |
948 | 952 | | |
949 | 953 | | |
| |||
952 | 956 | | |
953 | 957 | | |
954 | 958 | | |
955 | | - | |
956 | | - | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
957 | 962 | | |
958 | 963 | | |
959 | 964 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
57 | 60 | | |
58 | 61 | | |
59 | 62 | | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
64 | 76 | | |
| 77 | + | |
| 78 | + | |
65 | 79 | | |
66 | 80 | | |
67 | 81 | | |
| |||
429 | 443 | | |
430 | 444 | | |
431 | 445 | | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
432 | 449 | | |
433 | 450 | | |
434 | 451 | | |
435 | 452 | | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
436 | 463 | | |
437 | 464 | | |
438 | 465 | | |
439 | 466 | | |
440 | 467 | | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
441 | 475 | | |
442 | 476 | | |
443 | 477 | | |
| |||
0 commit comments