Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Heap-Use-After-Free in TCPBase::CloseActiveConnections During Shutdown #36731

Closed
BoB13-Matter opened this issue Dec 5, 2024 · 0 comments · Fixed by #36880
Closed

[BUG] Heap-Use-After-Free in TCPBase::CloseActiveConnections During Shutdown #36731

BoB13-Matter opened this issue Dec 5, 2024 · 0 comments · Fixed by #36880
Assignees
Labels
bug Something isn't working needs triage

Comments

@BoB13-Matter
Copy link
Contributor

Reproduction steps

  1. Build chip-all-clusters-app with AddressSanitizer (ASAN) enabled.

  2. Open Terminal 1 and start the chip-all-clusters-app:

    $ ./chip-all-clusters-app
  3. 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
  4. After the TCP session is established, terminate chip-all-clusters-app in Terminal 1 with Ctrl+C.

  5. 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:

  1. Allocation and Initialization:

    • A TCPEndPoint object is created and assigned to the mEndPoint member of an ActiveTCPConnectionState object during the TCP connection establishment process.
  2. Deallocation:

    • During shutdown, the HeapObjectPool destructor deallocates all TCPEndPoint objects via ReleaseAll(). However, the ActiveTCPConnectionState objects retain dangling pointers to these deallocated TCPEndPoint objects.
    HeapObjectPool::~HeapObjectPool()
    {
        ReleaseAll();
    }
    
    void ReleaseAll()
    {
        mObjects.ForEachNode(this, ReleaseObject);
    }
    
  3. Access to Freed Memory:

    • 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.
    void TCPBase::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);
            }
        }
    }
    
  4. 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:
    void TCPEndPoint::Close()
    {
        mRcvQueue = nullptr; // Accesses freed memory
    }
    

Proposed Solution

The following solutions are proposed to address this issue:

  1. Synchronize Lifecycles:

    • Ensure that TCPEndPoint objects are not deallocated while ActiveTCPConnectionState references them.
  2. 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;
  3. 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.

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

@BoB13-Matter BoB13-Matter added bug Something isn't working needs triage labels Dec 5, 2024
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.
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.
mergify bot pushed a commit 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs triage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants