4 years, 10 months ago.

How do I close a socket?

I coded a forking server using mbedtls. When a client connects the server should fork, the parent should close the new connection and go back to accepting new clients while the child should close the listening socket and go handling the client socket. The only way to do this seems to be the following contrived example:

Forking server

while (1) {
  mbedtls_net_accept(&listening, &client, NULL, 0, NULL);
  if (fork()) {
    close(client.fd);
  } else {
    close(listening.fd);
    handle_client(&client);
  }
}

However I feel that I should not know the content of the mbedtls_net_context structure as this could potentially break portability.

I looked into how the ssl_fork_server.c is doing things and I think it is wrong! In short, this is what it does:

ssl_fork_server.c shortened

while (1) {
    mbedtls_net_init(&client);
    mbedtls_ssl_init(&ssl);
    mbedtls_net_accept(&listening, &client, NULL, 0, NULL);
    if (fork()) {
        mbedtls_ctr_drbg_reseed(&ctr_dbt, "parent", 6);
    } else {
        mbed_net_init(&listening);
        /* handle client */
       ....;
    }
}

This is bad! mbedtls_net_init simply sets the fd member of the mbedtls_net_context structure to -1. That's it.

That means that when the first client arrives, the server forks and both parent and child will have two open sockets, the listening one and the client one.

When the next client arrives the server forks again. Now this child have both a listening socket, his own socket AND the first clients socket open.

That's bad! If client two gets code execution through a vulnerability he will be able to read/write client one or he could accept new clients.

Using mbedtls_net_free will not work since it first shuts the socket down for both read and write. If the parent frees the client socket this way, then the child will no longer be able to read or write. If the child frees the listening socket, then the parent will no longer be able to accept.

So, we need a mbedtls_net_close function.

1 Answer

4 years, 8 months ago.

Hi Robert,

Thank you for your report.

What fd do you think we should close?

I may be missing something, but as you can see in the implementation of mbedtls_net_accept(), it will override client_ctx->fd , so the child process should not have the fd of the previous socket, only the binding socket, and the accepted socket that it should read \ write data.

Will you be willing to make a PR in the Mbed TLS repository with your suggested fix and explanation? Regards,

Mbed Support

Ron

You've got pull request 2803 where I also show the problem.

posted by Robert Larsen 23 Aug 2019