Commit 9a27e66
committed
menu/xmb: fix five heap-safety issues found during an audit pass
Five independent issues found during a focused audit of menu/drivers/
xmb.c. Two are real corruption vectors driven by uninitialized memory
and a stale-pointer free ordering; two are size_t underflows in the
ticker helpers that don't fire on the current XMB call sites but
violate the contract a future caller could plausibly hit; and one is
an unused heap allocation on every main-menu init. Grouped together
because they share an audit context and none is large enough to stand
alone.
* xmb_alloc_node: uninitialized gfx_thumbnail_t fields
(menu/drivers/xmb.c)
The comment above xmb_alloc_node deliberately uses malloc instead
of calloc to avoid zeroing the multi-KB thumbnail_path_data char
arrays on every node alloc on big lists (MAME, FBA). Per-field
init only sets node->thumbnail_icon.icon.texture = 0, leaving the
rest of the gfx_thumbnail_t substruct (status, flags, alpha,
delay_timer, width, height) and all of thumbnail_path_data
uninitialized.
When a node is later freed without its thumbnail ever having been
loaded -- the common case for the line-edit path at the bottom of
the file (xmb_list_init -> xmb_alloc_node, allocated and stored
into list->list[i].userdata) -- xmb_free_node calls
gfx_thumbnail_reset, which reads `thumbnail->flags &
GFX_THUMB_FLAG_FADE_ACTIVE` and `thumbnail->texture` before
initializing them. Uninit `flags` may match the bit and trigger
gfx_animation_kill_by_tag against arbitrary state; uninit
`texture != 0` feeds a garbage handle to
video_driver_texture_unload. The latter is the actual heap
corruption vector -- driver-side texture maps treat the handle as
an index/key into their own allocations.
Separately, the lazy thumbnail-path resolution in the render path
reads `thumbnail_icon->thumbnail_path_data.icon_path[0]` to decide
whether resolution is needed; on a freshly-allocated node that
byte is uninitialized.
Zero the small gfx_thumbnail_t substruct (~32 bytes) and clear
icon_path[0] only. This preserves the original optimization that
kept thumbnail_path_data's PATH_MAX/NAME_MAX char arrays unzeroed,
since the path-data fields are written via fill_pathname/strlcpy
before any read of those fields.
* playlist_db_node_map freed after the nodes it borrows from
(menu/drivers/xmb.c)
The map's values are non-owning xmb_node_t* pointers into
xmb->horizontal_list[i].userdata, populated in
xmb_context_reset_horizontal_list. In xmb_refresh_horizontal_list,
xmb_free, and the xmb_init error path the order was: free nodes
via xmb_free_list_nodes, then RHMAP_FREE the map. Between those
two calls the map holds dangling pointers.
No re-entry path I could trace would actually read the map during
that window today (the menu is single-threaded and
xmb_free_list_nodes calls only gfx_thumbnail_reset and free), but
the invariant isn't enforced and the fix is a one-line reorder.
Free the map first at all three sites.
* xmb_animation_line_ticker_smooth: size_t underflow in fade-string
copy length (menu/drivers/xmb.c)
At the two fade-string memcpy sites:
if (copy_len >= line_ticker->top_fade_str_len)
copy_len = line_ticker->top_fade_str_len - 1;
if top_fade_str_len == 0 the comparison is true, copy_len
underflows to SIZE_MAX, the memcpy writes effectively unbounded
bytes, and the trailing NUL store at line_ticker->top_fade_str
[copy_len] writes at SIZE_MAX offset. Same pattern for
bottom_fade_str_len.
XMB's only caller passes sizeof(stack_array) so the live path is
safe today, but xmb_animation_line_ticker_smooth takes the public
gfx_animation_ctx_line_ticker_smooth_t shape. Add the missing
`_str_len > 0` guard to each branch.
* xmb_animation_line_ticker: same underflow on line_ticker->len
(menu/drivers/xmb.c)
max_copy = line_ticker->len - 1 underflows when len == 0, then
copy_len > max_copy is false and the memcpy at line ~4566 writes
the full block size. The early sanity check guards line_len < 1
and max_lines < 1 but not len < 1. Add it for symmetry with the
smooth variant; same caller-contract argument.
* xmb_menu_init_list: dead heap allocation
(menu/drivers/xmb.c)
info.exts = strldup("lpl", sizeof("lpl")) has been allocated on
every main-menu init since the function was introduced.
DISPLAYLIST_MAIN_MENU never reads info->exts (only
directory-scanning displaylists like
DISPLAYLIST_DATABASE_PLAYLISTS_HORIZONTAL do, where the same line
legitimately filters .lpl files); the buffer is allocated, never
read, then freed by menu_displaylist_info_free. Almost certainly
copy-pasted from xmb_init_horizontal_list at line ~2927. Drop it.1 parent fae20db commit 9a27e66
1 file changed
Lines changed: 36 additions & 9 deletions
File tree
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
640 | 640 | | |
641 | 641 | | |
642 | 642 | | |
643 | | - | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
644 | 657 | | |
645 | 658 | | |
646 | 659 | | |
| |||
651 | 664 | | |
652 | 665 | | |
653 | 666 | | |
654 | | - | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
655 | 670 | | |
656 | 671 | | |
657 | 672 | | |
| |||
3153 | 3168 | | |
3154 | 3169 | | |
3155 | 3170 | | |
| 3171 | + | |
| 3172 | + | |
| 3173 | + | |
| 3174 | + | |
| 3175 | + | |
| 3176 | + | |
3156 | 3177 | | |
3157 | 3178 | | |
3158 | | - | |
3159 | 3179 | | |
3160 | 3180 | | |
3161 | 3181 | | |
| |||
4445 | 4465 | | |
4446 | 4466 | | |
4447 | 4467 | | |
4448 | | - | |
| 4468 | + | |
| 4469 | + | |
4449 | 4470 | | |
4450 | 4471 | | |
4451 | 4472 | | |
| |||
5023 | 5044 | | |
5024 | 5045 | | |
5025 | 5046 | | |
5026 | | - | |
| 5047 | + | |
| 5048 | + | |
5027 | 5049 | | |
5028 | 5050 | | |
5029 | 5051 | | |
| |||
5033 | 5055 | | |
5034 | 5056 | | |
5035 | 5057 | | |
5036 | | - | |
| 5058 | + | |
| 5059 | + | |
5037 | 5060 | | |
5038 | 5061 | | |
5039 | 5062 | | |
| |||
9534 | 9557 | | |
9535 | 9558 | | |
9536 | 9559 | | |
| 9560 | + | |
| 9561 | + | |
| 9562 | + | |
| 9563 | + | |
9537 | 9564 | | |
9538 | 9565 | | |
9539 | | - | |
9540 | 9566 | | |
9541 | 9567 | | |
9542 | 9568 | | |
| |||
9551 | 9577 | | |
9552 | 9578 | | |
9553 | 9579 | | |
| 9580 | + | |
| 9581 | + | |
| 9582 | + | |
9554 | 9583 | | |
9555 | 9584 | | |
9556 | | - | |
9557 | 9585 | | |
9558 | 9586 | | |
9559 | 9587 | | |
| |||
10038 | 10066 | | |
10039 | 10067 | | |
10040 | 10068 | | |
10041 | | - | |
10042 | 10069 | | |
10043 | 10070 | | |
10044 | 10071 | | |
| |||
0 commit comments