Seeing issue with BIO_free call

22 views
Skip to first unread message

Samiya Khanum

unread,
Sep 19, 2025, 9:05:22 AM (13 days ago) Sep 19
to openss...@openssl.org, Kamlesh Agrawal
Hi,

I'm encountering an issue with the `BIO_free` call in the following code snippet.

When `sslCleanupTask` is triggered and `BIO_free` is called, we occasionally receive data on `listen_s`. This subsequently causes a hang because `BIO_do_accept` in `sslListenTask` is then called on a file descriptor that has already been freed or closed by `BIO_free`.

Could you please explain why `listen_s` is set in `readfds` when `BIO_free` is called? 
I've attempted to set the `BIO_CLOSE` flag, but the issue persists.

Do we need to set any other APIs or flags to prevent this? Please note that we are not initiating any connections here.

sslListenTask()
{
    BIO *ppBio = NULL;
   
    if ((ppBio = BIO_new_accept("[::]:443")) == NULL)
    {
      BIO_free(ppBio);
      return;
    }
    BIO_set_bind_mode(ppBio, BIO_BIND_REUSEADDR);
    /* First call sets up the BIO listening socket */
    if (BIO_do_accept(ppBio) <= NULL)
    {
      BIO_free(ppBio);
      return;
    }
    if( (listen_s = BIO_get_fd(ppBio,0)) <=0 )
    {
       BIO_free(ppBio);
        return;
    }
   /*
    ** Loop waiting for SSLT connections
    */
    while (1)
    {
      fd_set readfds;
      struct timeval tmout;
      int num,max_fd;

      tmout.tv_sec = 3;
      tmout.tv_usec = 0;
      FD_ZERO(&readfds);
      FD_SET(listen_s,&readfds);
      max_fd = listen_s;

      num = select(max_fd + 1, &readfds, NULL, NULL, &tmout);

      if (num <= 0)
      {
        if (!((num < 0) && (EINTR == errno)))
        {
          /* Set cancellation point for timeout and other errors except EINTR */
          pthread_testcancel();
        }

      continue;
    }
     if (FD_ISSET(listen_s, &readfds))
     {
        if (BIO_do_accept(rdy_acc) <= L7_NULL)
       {
          //err
       }

      client = BIO_pop(rdy_acc);
      //Rest of the program for SSL
   } 
 } /* while */
}

There is one more task doing the BIO_free if the SSL port changes.
sslCleanupTask()
{
   BIO_free(ppBio);
}

Thanks & Regards,
Samiya khanum

Samiya Khanum

unread,
Sep 22, 2025, 8:10:41 AM (10 days ago) Sep 22
to openss...@openssl.org, Kamlesh Agrawal
Hi,
I would be grateful if someone could please provide some assistance or insights into this issue. 

Thanks & Regards,
Samiya khanum

Michael Wojcik

unread,
Sep 22, 2025, 9:30:36 AM (10 days ago) Sep 22
to openss...@openssl.org
> From: 'Samiya Khanum' via openssl-users <openss...@openssl.org>
> Sent: Monday, 22 September, 2025 06:10

> When `sslCleanupTask` is triggered and `BIO_free` is called, we occasionally receive
> data on `listen_s`. This subsequently causes a hang because `BIO_do_accept` in
> `sslListenTask` is then called on a file descriptor that has already been freed or
> closed by `BIO_free`.
>
> Could you please explain why `listen_s` is set in `readfds` when `BIO_free` is called?
> I've attempted to set the `BIO_CLOSE` flag, but the issue persists.

It would help if you provided the OpenSSL version and platform you're using.

The result of closing a descriptor in one thread while another thread has an in-process select on that descriptor is unspecified by SUS (aka "POSIX", though that term is no longer current). If you're on Linux, the Linux select man page says "closing the file descriptor in another thread has no effect on select()", but relying on that behavior is unwise.

In any case, there's an obvious race:
- The listening thread is in select.
- A SYN arrives on port 443. The listening socket becomes readable, and the listening thread is woken. select has not yet returned.
- The socket-closing thread is running, and closes the listening socket.
- select returns to the listening thread with the updated readfds.

You should use some mechanism for communicating between the two threads to tell the thread doing the accept that the listening socket is being closed, and it should stop attempting to call accept() on it. That could be as simple as a global variable.

> Do we need to set any other APIs or flags to prevent this?

No. There's a race condition. Fix the race.

> Please note that we are not initiating any connections here.

In that case the readability of the listening socket isn't immediately obvious to me (unless something else has been opened after the socket was closed, and the descriptor has been reused), but it's irrelevent, because in real use there will always be the race condition with the existing code.

There are some other issues with the code:

> if (BIO_do_accept(ppBio) <= NULL)

This is a nonsensical condition. The C standard allows NULL to be defined as an expression evaluating to a constant integer 0, or such an expression cast to void*. "Less than null" is meaningless. If you mean "less than or equal to 0", write that.

> if( (listen_s = BIO_get_fd(ppBio,0)) <=0 )

0 is a valid descriptor. Do not treat a descriptor value of 0 as an error.

> num = select(max_fd + 1, &readfds, NULL, NULL, &tmout);

Using select() in a modern Linux or UNIX application is discouraged. It's inefficient and the range of descriptors it supports, particularly on Linux, is very limited. At least use poll(2) instead.

--
Michael Wojcik
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 855.577.4323
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
Reply all
Reply to author
Forward
0 new messages