mirror of
https://github.com/esphome/esphome.git
synced 2026-09-13 16:18:41 +00:00
[socket] Null cached_sock_ in close() to prevent post-close UAF
Restore the cached_sock_ = nullptr assignment inside close() on the fast-select path. The lwip slot can be recycled for a new connection as soon as the underlying close() returns, so any dereference of cached_sock_ afterwards would touch an unrelated socket's pcb. No current caller does this — setsockopt(TCP_NODELAY) and ready() are the only consumers and neither is invoked post-close today — but leaving the pointer dangling is a footgun for future changes. The fd_ = -1 sentinel alone would catch the ready() path via closed semantics, but setsockopt() reaches cached_sock_ directly and would not be protected. Null the pointer so the protection is by construction rather than by caller discipline.
This commit is contained in:
@@ -27,9 +27,14 @@ int BSDSocketImpl::close() {
|
||||
// Already closed, or never opened.
|
||||
return 0;
|
||||
}
|
||||
#ifndef USE_LWIP_FAST_SELECT
|
||||
// On the fast-select path there is no per-socket unhook needed — all LwIP sockets
|
||||
// share the same static event_callback.
|
||||
#ifdef USE_LWIP_FAST_SELECT
|
||||
// Null the cached lwip_sock pointer before closing. The underlying lwip slot can be
|
||||
// recycled for a new connection as soon as ::close() returns, so anything that might
|
||||
// dereference cached_sock_ post-close (e.g. setsockopt(TCP_NODELAY)) would otherwise
|
||||
// touch an unrelated socket's pcb. No per-socket callback unhook is needed —
|
||||
// all LwIP sockets share the same static event_callback.
|
||||
this->cached_sock_ = nullptr;
|
||||
#else
|
||||
if (this->loop_monitored_) {
|
||||
App.unregister_socket_fd(this->fd_);
|
||||
}
|
||||
|
||||
@@ -27,9 +27,14 @@ int LwIPSocketImpl::close() {
|
||||
// Already closed, or never opened.
|
||||
return 0;
|
||||
}
|
||||
#ifndef USE_LWIP_FAST_SELECT
|
||||
// On the fast-select path there is no per-socket unhook needed — all LwIP sockets
|
||||
// share the same static event_callback.
|
||||
#ifdef USE_LWIP_FAST_SELECT
|
||||
// Null the cached lwip_sock pointer before closing. The underlying lwip slot can be
|
||||
// recycled for a new connection as soon as lwip_close() returns, so anything that
|
||||
// might dereference cached_sock_ post-close (e.g. setsockopt(TCP_NODELAY)) would
|
||||
// otherwise touch an unrelated socket's pcb. No per-socket callback unhook is needed —
|
||||
// all LwIP sockets share the same static event_callback.
|
||||
this->cached_sock_ = nullptr;
|
||||
#else
|
||||
if (this->loop_monitored_) {
|
||||
App.unregister_socket_fd(this->fd_);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user