menu: re-fetch the menu handle after menu_entry_action()

generic_menu_iterate()'s ITERATE_TYPE_DEFAULT case runs the selected
entry's action handler and then writes
BIT64_SET(menu->state, MENU_STATE_POST_ITERATE) through the menu
handle it was passed. menu_entry_action() can tear down and recreate
that handle - a menu driver change, or any CMD_EVENT_REINIT
dispatched from an action - leaving the parameter and the cached
entries list stale; the tail of the function then reads and writes
menu->state through freed memory.

Observed as a Play Console SIGSEGV at menu_driver_iterate+4088 on a
32-bit Android 11 TV (1.22.2 / 2026-08-26, armeabi-v7a, BuildId
d75406ff); the faulting instructions are the read-modify-write of
the POST_ITERATE bit through the stale pointer. On 64-bit heaps the
same write usually lands in still-mapped freed memory, so this has
been corrupting quietly rather than crashing.

Re-fetch the handle and the entries list after the action returns;
if the menu is gone, there is nothing to post-iterate.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-08-30 16:20:01 +02:00
1 parent f61012ad1a
commit 38234ab96d
1 file changed
+12
+12
View File
@@ -7816,6 +7816,18 @@ static int generic_menu_iterate(
selection, (enum menu_action)action)))
return -1;
/* menu_entry_action() can tear down and recreate the menu
* (a menu driver change, or any CMD_EVENT_REINIT dispatched
* from an entry's action handler): the handle and the
* entries list cached above are stale once it returns.
* Re-fetch both before writing through them - on 64-bit
* heaps the stale menu->state write lands in freed memory
* silently instead of faulting, so this corrupts quietly
* everywhere the fault does not reproduce. */
if (!(menu = menu_st->driver_data))
return 0;
menu_list = menu_st->entries.list;
BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
/* Have to defer it so we let settings refresh. */