Skip to content

Potential race condition on socket open/send (discovered on M1) #325

@n-hutton

Description

@n-hutton

Hello,

I am finding that I have the following race condition:

in server/connectors/unixdomainsocketserver.cpp we have:

bool UnixDomainSocketServer::InitializeListener() {
...
  // Set to non-blocking mode
  fcntl(this->socket_fd, F_SETFL, FNDELAY);

So a non blocking socket is created.

Later, a connection is opened when I send data to it, and this function is called:

void UnixDomainSocketServer::HandleConnection(int connection) {
  string request, response;
  StreamReader reader(DEFAULT_BUFFER_SIZE);
  reader.Read(request, connection, DEFAULT_DELIMITER_CHAR);
...
  close(connection);

The read is as following:

bool StreamReader::Read(std::string &target, int fd, char delimiter) {
  ssize_t bytesRead;
  do {
    bytesRead = read(fd, this->buffer, buffersize);
    if (bytesRead < 0) {
      return false;
    } else {
      target.append(buffer, static_cast<size_t>(bytesRead));
    }
  } while (memchr(buffer, delimiter, bytesRead) ==
           NULL); //(target.find(delimiter) == string::npos && bytesRead > 0);

  target.pop_back();
  return true;
}

So what happens is that if the HandleConnection call is executed fast enough, the client has not yet sent any data. Since the socket is non-blocking, the streamreader read returns -1, and the request string will be an empty string. The method then closes the connection, causing an error for the client who is trying to send data.

The current best solution I have to this is to increase the timeout in the handler dispatch. However, it would be better I think if either the socket was blocking, or the return value from the stream reader was utilized in order to detect this case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions