You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After the TCP session is established, terminate chip-all-clusters-app in Terminal 1 with Ctrl+C.
Observe the ASAN output of chip-all-clusters-app indicating a heap-use-after-free issue. ASAN Log.txt
Summary
A heap-use-after-free (UAF) issue occurs during the cleanup phase in the Matter protocol's TCP transport layer. When a TCPEndPoint object is deallocated, its reference remains in the ActiveTCPConnectionState object. This dangling pointer leads to undefined behavior when the TCP connection termination logic accesses the invalid memory.
Analysis and Description
The root cause of this issue lies in the mismatch between the lifecycle management of TCPEndPoint objects and their references in ActiveTCPConnectionState. The following sequence of events explains the issue:
Allocation and Initialization:
A TCPEndPoint object is created and assigned to the mEndPoint member of an ActiveTCPConnectionState object during the TCP connection establishment process.
Deallocation:
During shutdown, the HeapObjectPool destructor deallocates all TCPEndPoint objects via ReleaseAll(). However, the ActiveTCPConnectionState objects retain dangling pointers to these deallocated TCPEndPoint objects.
When TCPBase::CloseActiveConnections() is called, it iterates over the ActiveTCPConnectionState array. The mEndPoint pointer in these objects is used to call the Close() method, resulting in a UAF error.
voidTCPBase::CloseActiveConnections()
{
for (size_t i = 0; i < mActiveConnectionsSize; ++i)
{
ActiveTCPConnectionState * connection = &mActiveConnections[i];
if (connection->InUse()) // mEndPoint is dangling
{
CloseConnectionInternal(connection, CHIP_NO_ERROR, SuppressCallback::kNo);
}
}
}
ASAN Error:
The error occurs in the TCPEndPoint::Close() method when the code tries to clear the receive queue (mRcvQueue), as shown in the ASAN log:
The following solutions are proposed to address this issue:
Synchronize Lifecycles:
Ensure that TCPEndPoint objects are not deallocated while ActiveTCPConnectionState references them.
Use Smart Pointers:
Replace raw pointers with smart pointers (e.g., std::shared_ptr) in ActiveTCPConnectionState. This would allow the object to manage the lifetime of the TCPEndPoint safely:
std::shared_ptr<Inet::TCPEndPoint> mEndPoint;
Refactor Object Management:
Decouple the lifecycle of ActiveTCPConnectionState from TCPEndPoint objects. Use proxy objects or implement weak references to manage the dependency.
By addressing this issue, the framework can prevent undefined behavior and potential security vulnerabilities. The proposed solutions not only resolve the immediate problem but also enhance the robustness and maintainability of the code.
If further information is needed, please do not hesitate to reach out.
Add CloseActiveConnections() call in TCPBase::Close(), which
is called as part of Server::Shutdown().
Active connections should be closed as part of Server shutdown.
This allows the TCPConnectionState to also close the associated
TCPEndpoint object as part of this shutdown flow.
Previously, the CloseActiveConnections() call was present in the
TCPBase destructor alone.
pidarped
added a commit
to pidarped/connectedhomeip
that referenced
this issue
Dec 18, 2024
Add CloseActiveConnections() call in TCPBase::Close(), which
is called as part of Server::Shutdown().
Active connections should be closed as part of Server shutdown.
This allows the TCPConnectionState to also close the associated
TCPEndpoint object as part of this shutdown flow.
Previously, the CloseActiveConnections() call was present in the
TCPBase destructor alone.
Add test for Connection Close() and checking for TCPEndPoint.
pidarped
added a commit
to pidarped/connectedhomeip
that referenced
this issue
Dec 19, 2024
Add CloseActiveConnections() call in TCPBase::Close(), which
is called as part of Server::Shutdown().
Active connections should be closed as part of Server shutdown.
This allows the TCPConnectionState to also close the associated
TCPEndpoint object as part of this shutdown flow.
Previously, the CloseActiveConnections() call was present in the
TCPBase destructor alone.
Add test for Connection Close() and checking for TCPEndPoint.
Add CloseActiveConnections() call in TCPBase::Close(), which
is called as part of Server::Shutdown().
Active connections should be closed as part of Server shutdown.
This allows the TCPConnectionState to also close the associated
TCPEndpoint object as part of this shutdown flow.
Previously, the CloseActiveConnections() call was present in the
TCPBase destructor alone.
Add test for Connection Close() and checking for TCPEndPoint.
Reproduction steps
Build
chip-all-clusters-app
with AddressSanitizer (ASAN) enabled.Open Terminal 1 and start the
chip-all-clusters-app
:Open Terminal 2 and run the following commands in
chip-tool
:$ ./chip-tool interactive start $ pairing onnetwork-long 1 20202021 3840 $ basicinformation read vendor-name 1 0 --allow-large-payload 1
After the TCP session is established, terminate
chip-all-clusters-app
in Terminal 1 withCtrl+C
.Observe the ASAN output of chip-all-clusters-app indicating a heap-use-after-free issue.
ASAN Log.txt
Summary
A heap-use-after-free (UAF) issue occurs during the cleanup phase in the Matter protocol's TCP transport layer. When a
TCPEndPoint
object is deallocated, its reference remains in theActiveTCPConnectionState
object. This dangling pointer leads to undefined behavior when the TCP connection termination logic accesses the invalid memory.Analysis and Description
The root cause of this issue lies in the mismatch between the lifecycle management of
TCPEndPoint
objects and their references inActiveTCPConnectionState
. The following sequence of events explains the issue:Allocation and Initialization:
TCPEndPoint
object is created and assigned to themEndPoint
member of anActiveTCPConnectionState
object during the TCP connection establishment process.Deallocation:
HeapObjectPool
destructor deallocates allTCPEndPoint
objects viaReleaseAll()
. However, theActiveTCPConnectionState
objects retain dangling pointers to these deallocatedTCPEndPoint
objects.Access to Freed Memory:
TCPBase::CloseActiveConnections()
is called, it iterates over theActiveTCPConnectionState
array. ThemEndPoint
pointer in these objects is used to call theClose()
method, resulting in a UAF error.ASAN Error:
TCPEndPoint::Close()
method when the code tries to clear the receive queue (mRcvQueue
), as shown in the ASAN log:Proposed Solution
The following solutions are proposed to address this issue:
Synchronize Lifecycles:
TCPEndPoint
objects are not deallocated whileActiveTCPConnectionState
references them.Use Smart Pointers:
std::shared_ptr
) inActiveTCPConnectionState
. This would allow the object to manage the lifetime of theTCPEndPoint
safely:std::shared_ptr<Inet::TCPEndPoint> mEndPoint;
Refactor Object Management:
ActiveTCPConnectionState
fromTCPEndPoint
objects. Use proxy objects or implement weak references to manage the dependency.By addressing this issue, the framework can prevent undefined behavior and potential security vulnerabilities. The proposed solutions not only resolve the immediate problem but also enhance the robustness and maintainability of the code.
If further information is needed, please do not hesitate to reach out.
Bug prevalence
always
GitHub hash of the SDK that was being used
ffbc362
Platform
core
Platform Version(s)
all versions with TCP support
Anything else?
No response
The text was updated successfully, but these errors were encountered: