Skip to content

Fix use-after-free race in socket driver close#2156

Open
petermm wants to merge 1 commit intoatomvm:mainfrom
petermm:fix-unix-socket_driver
Open

Fix use-after-free race in socket driver close#2156
petermm wants to merge 1 commit intoatomvm:mainfrom
petermm:fix-unix-socket_driver

Conversation

@petermm
Copy link
Contributor

@petermm petermm commented Mar 4, 2026

https://ampcode.com/threads/T-019cb8b8-9e4c-7316-9566-c7e3f5f2b6db

Claims to fix #2155

Fix a use-after-free race condition in the generic_unix socket driver's close handler, detected by Valgrind during CI gen_tcp tests.

The close handler in socket_consume_mailbox used a two-phase locking pattern: it acquired the glb->listeners lock to NULL-out the socket_data listener pointers, released it, then called sys_unregister_listener (which re-acquires the lock) to remove the listener from the linked list. Between the unlock and re-lock, the event loop thread could also unlink the same listener node via process_listener_handler after the callback returned NULL. The subsequent list_remove in sys_unregister_listener then operated on stale prev/next pointers, corrupting the list or writing to freed memory.

The fix makes the pointer detach and list unlink atomic under a single lock hold by introducing sys_unregister_listener_nolock — a variant that assumes the caller already holds the glb->listeners write lock. The close handler now NULLs the pointers, unlinks the listeners, and releases the lock before freeing the memory.

This pattern is specific to generic_unix; ESP32 and RP2 use a single global listener for the socket driver subsystem and are not affected.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later

@petermm petermm force-pushed the fix-unix-socket_driver branch from 2cf6c19 to 9a9cf07 Compare March 8, 2026 20:00
https://ampcode.com/threads/T-019cb8b8-9e4c-7316-9566-c7e3f5f2b6db

Fix a use-after-free race condition in the generic_unix socket driver's close
handler, detected by Valgrind during CI gen_tcp tests.

The close handler in socket_consume_mailbox used a two-phase locking pattern:
it acquired the glb->listeners lock to NULL-out the socket_data listener
pointers, released it, then called sys_unregister_listener (which re-acquires
the lock) to remove the listener from the linked list. Between the unlock and
re-lock, the event loop thread could also unlink the same listener node via
process_listener_handler after the callback returned NULL. The subsequent
list_remove in sys_unregister_listener then operated on stale prev/next
pointers, corrupting the list or writing to freed memory.

The fix makes the pointer detach and list unlink atomic under a single lock hold
by introducing sys_unregister_listener_nolock — a variant that assumes the
caller already holds the glb->listeners write lock. The close handler now
NULLs the pointers, unlinks the listeners, and releases the lock before freeing
the memory.

This pattern is specific to generic_unix; ESP32 and RP2 use a single global
listener for the socket driver subsystem and are not affected.

Signed-off-by: Peter M <petermm@gmail.com>
@petermm petermm force-pushed the fix-unix-socket_driver branch from 9a9cf07 to 4a45ffe Compare March 9, 2026 18:09
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.

"Invalid write" in socket_consume_mailbox / sys_unregister_listener / sys_register_listener

1 participant