Skip to content

CConnman::SocketEvents() may poll the wrong socket #21744

@vasild

Description

@vasild

Adverse scenario:

  1. thread "net"
CConnman::ThreadSocketHandler()
  CConnman::SocketHandler()
    CConnman::SocketEvents()
      CConnman::GenerateSelectSet()
        Cycles through CConnman::vNodes and remembers some sockets to
        be polled for readiness later by CConnman::SocketEvents().
        Lets say socket (file descriptor) 10 is remembered.
  1. thread "msghand"
CConnman::ThreadMessageHandler()
  PeerManagerImpl::ProcessMessages()
    PeerManagerImpl::ProcessMessage()
      PeerManagerImpl::PushNodeVersion()
        CConnman::PushMessage()
          CConnman::SocketSendData()
            CNode::CloseSocketDisconnect()
              Closes socket 10.
  1. thread "opencon"
CConnman::ThreadOpenConnections()
  CConnman::OpenNetworkConnection()
    CConnman::ConnectNode()
      CreateSock()
        Creates a new socket, reusing file descriptor 10.
  1. thread "net"
CConnman::ThreadSocketHandler()
  CConnman::SocketHandler()
    CConnman::SocketEvents()
      polls the remembered socket 10, which corresponds to a different
      connection now (bug)

As a result the following logic may not hold:

bitcoin/src/net.cpp

Lines 1306 to 1315 in e16f872

// Implement the following logic:
// * If there is data to send, select() for sending data. As this only
// happens when optimistic write failed, we choose to first drain the
// write buffer in this case before receiving more. This avoids
// needlessly queueing received data, if the remote peer is not themselves
// receiving data. This means properly utilizing TCP flow control signalling.
// * Otherwise, if there is space left in the receive buffer, select() for
// receiving data.
// * Hand off all complete messages to the processor, to be handled without
// blocking here.

I think the severity of this is low and that it has a low chance of happening. However the pattern of "remember a socket by its file descriptor number and use it later, concurrently with other threads that might close it" better be avoided. That pattern could lead to closing or writing to the wrong socket which would be more severe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions