openssl memory leak

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

openssl memory leak

dvijayalakshmi
We are using Openssl for FTPS connections. We are facing issues with memory leak.
Kindly let us know if there is sample code.
Reply | Threaded
Open this post in threaded view
|

RE: openssl memory leak

Porter, Andrew
The openssl source package includes a generic server (s_server) and client (s_client).

My first suspect when something has a memory leak with SSL connections only is to check whether SSL contexts returned by SSL_new() always get cleaned up later by calling SSL_free()...

Andrew

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of dvijayalakshmi
Sent: Friday, July 25, 2014 6:37 AM
To: [hidden email]
Subject: openssl memory leak

We are using Openssl for FTPS connections. We are facing issues with memory leak.
Kindly let us know if there is sample code.




--
View this message in context: http://openssl.6102.n7.nabble.com/openssl-memory-leak-tp52311.html
Sent from the OpenSSL - User mailing list archive at Nabble.com.
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [hidden email]
Automated List Manager                           [hidden email]
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [hidden email]
Automated List Manager                           [hidden email]
Reply | Threaded
Open this post in threaded view
|

RE: openssl memory leak

dvijayalakshmi
Thank you fro your reply.
We have already called SSL_free() API.
We are using SSL APIs for FTPS file transfer.
Please find the below sample code .

//The below code is implemented for Control connection.
void LoadSSLModules(void)
{
        SSL_load_error_strings();
        ERR_load_ERR_strings();
        SSLeay_add_ssl_algorithms();
        m_pConnMethod = SSLv23_server_method();
        m_pConnCTX = SSL_CTX_new (m_pConnMethod);
        if (!m_pConnCTX) {
                SendResponse(_T("431 Need some unavailable resource to process security."));
                return;
        }
        SSL_CTX_set_options(m_pConnCTX, SSL_OP_NO_SSLv2);
        if(theApp.m_bLoadedSSLCertificate)
        {
                if (SSL_CTX_use_certificate_file(m_pConnCTX, theApp.m_strCertificate, SSL_FILETYPE_PEM) <= 0) {
                        ERR_print_errors_fp(stderr);
                        return;
                }
        }
        if(theApp.m_bLoadedSSLPrivateKey)
        {
                if (SSL_CTX_use_PrivateKey_file(m_pConnCTX, theApp.m_strPrivFile, SSL_FILETYPE_PEM) <= 0) {
                        ERR_print_errors_fp(stderr);
                        return;
                }
        }
        if (!SSL_CTX_check_private_key(m_pConnCTX)) {
                fprintf(stderr,"Private key does not match the certificate public key\n");
                return;
        }
        if( 1 != (SSL_CTX_set_cipher_list(m_pConnCTX,CIPHER_LIST)) )
        {
                return;
        }
        m_pConnSSL = SSL_new (m_pConnCTX);
        if(!m_pConnSSL)
        {
                SendResponse(_T("431 Need some unavailable resource to process security."));
                return;
        }

        CConnectThread *pThread = (CConnectThread *)m_pThread;
        int iError = SSL_set_fd (m_pConnSSL, (int)pThread->m_hSocket);

        m_pSSLConnBio = BIO_new_socket(m_hSocket, BIO_NOCLOSE);
        SSL_set_bio(m_pConnSSL,m_pSSLConnBio,m_pSSLConnBio);

        CString strResponse;
        strResponse.Format(_T("234 AUTH %s successful and waiting for negotiation."), strArguments);
        SendResponse(strResponse);
}
//Below method is called by framework when receiving data over the control connection.
void CConnectSocket::OnReceive(int nErrorCode)
{
        TCHAR szBuff[BUFFERSIZE];

        //If AUTH command is received, then the successive data must be read in
        //encrypted form.
        int nRead = 0;
        if(m_bAuth)
        {
                if(!m_bSSLAccepted)
                {
                        int iError = SSL_accept (m_pConnSSL);
                        if(1 == iError)
                        {
                                m_bSSLAccepted = true;
                        }
                }

                nRead = SSL_read(m_pConnSSL, szBuff, BUFFERSIZE);
                if(m_bAuth && (nRead > 0))
                {
                        char szBuff1[BUFFERSIZE];
                        int nPeekSize = 0;
                        while((nPeekSize = SSL_peek(m_pConnSSL, szBuff1, BUFFERSIZE)) > 0)
                        {
                                ATLTRACE(_T("SSL_peek has %d number of bytes of data\n"), nPeekSize);
                                //theApp.m_LogFile.Write(_T("SSL_peek has %d number of bytes of data"), nPeekSize);
                                int nRead1;
                                nRead1 = SSL_read(m_pConnSSL, szBuff1, nPeekSize);
                                //theApp.m_LogFile.Write(_T("Command : %s"), szBuff1);
                                ((CConnectThread *)AfxGetThread())->IncReceivedBytes(nRead1);
                                szBuff1[nRead1] = 0;
                                m_RxBuffer += CString(szBuff1);
                                //Process the received data
                                parsecommand();
                        }
                }
        }
        CSocket::OnReceive(nErrorCode);
}
//Calling the below method to shutdown and free the SSL session of control connection
bool FreeSSLModules(void)
{
        __try
        {
                if(m_pConnSSL)
                {
                        SSL_shutdown (m_pConnSSL);
                        SSL_free (m_pConnSSL);
                        SSL_CTX_free (m_pConnCTX);

                        CRYPTO_cleanup_all_ex_data();
                        ERR_free_strings();
                        ERR_remove_thread_state(NULL);
                        EVP_cleanup();
                }
                       
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
                theApp.m_LogFile.Write(_T("CConnectSocket::FreeSSLModules - Exception occurred"));
                //If SSL library is failed to free.
                return false;
        }
        return true;
}

//The below code is implemented for Data connection.

bool InitialiseSSLForDataConnection()
{
        if(!m_bSSLInitialised)
        {
                SSL_load_error_strings();
                ERR_load_ERR_strings();
                SSLeay_add_ssl_algorithms();
                m_pDataMethod = SSLv23_server_method();

                m_pDataCTX = SSL_CTX_new (m_pDataMethod);
                if (!m_pDataCTX)
                {
                        return m_bSSLInitialised;
                }
                SSL_CTX_set_options(m_pDataCTX, SSL_OP_NO_SSLv2);
                SSL_CTX_set_mode(m_pDataCTX, SSL_MODE_AUTO_RETRY);

                if(theApp.m_bLoadedSSLCertificate)
                {
                        if (SSL_CTX_use_certificate_file(m_pDataCTX, theApp.m_strCertificate, SSL_FILETYPE_PEM) <= 0)
                        {
                                ERR_print_errors_fp(stderr);
                                return bReturnValue;
                        }
                }
                if(theApp.m_bLoadedSSLPrivateKey)
                {
                        if (SSL_CTX_use_PrivateKey_file(m_pDataCTX, theApp.m_strPrivFile, SSL_FILETYPE_PEM) <= 0)
                        {
                                ERR_print_errors_fp(stderr);
                                return bReturnValue;
                        }
                }
                if (!SSL_CTX_check_private_key(m_pDataCTX))
                {
                        fprintf(stderr,"Private key does not match the certificate public key\n");
                        return bReturnValue;
                }
                if( 1 != (SSL_CTX_set_cipher_list(m_pDataCTX,CIPHER_LIST)) )
                {
                        return m_bSSLInitialised;
                }

                m_pDataSSL = SSL_new (m_pDataCTX);
                if(!m_pDataSSL)
                {
                        return m_bSSLInitialised;
                }
        }

        m_bSSLInitialised = true;
        return m_bSSLInitialised;
}

//Below method is called by framework when receiving data over the control connection.
int Receive()
{
        int nRead = 0;
        try
        {
                if (m_nStatus == XFERMODE_RECEIVE)
                {
                        //file to write the received data
                        if (m_oFile.m_hFile == NULL)
                        {
                                theApp.m_LogFile.Write(_T("CDataSocket::Receive() - Invalid file"));
                                return 0;
                        }

                        byte szData[PACKET_SIZE];

                        if(m_pConnectSocket->m_bPROT)
                        {
                                //DoSSLAccept
                                if(!m_bSSLAccepted)
                                {
                                        int iError = SSL_set_fd (m_pDataSSL, (int)m_hSocket);
                                        if(1 != iError)
                                        {
                                                return false;
                                        }

                                        unsigned long lSwitch;
                                        m_pSSLBio = BIO_new_socket(m_hSocket, BIO_NOCLOSE);
                                        BIO_socket_ioctl(m_hSocket,FIONBIO,&lSwitch);
                                        SSL_set_bio(m_pDataSSL,m_pSSLBio,m_pSSLBio);

                                        iError = SSL_accept (m_pDataSSL);
                                        if(1 == iError)
                                        {
                                                m_bSSLAccepted = true;
                                                SSL_SESSION *session = SSL_get_session(m_pDataSSL);
                                                if(NULL != session)
                                                {
                                                        //"SSL session(id=%x) has been initialized for data channel"),
                                                        ATLTRACE(_T("SSL session(id=%x) has been initialized for data channel\n"), session);
                                                }
                                        }
                                        else
                                        {
                                                CString strData;
                                                DWORD dwReturn = GetSSLError(iError, strData);
                                                while((SSL_ERROR_WANT_WRITE == dwReturn) || (SSL_ERROR_WANT_READ == dwReturn))
                                                {
                                                        iError = SSL_accept (m_pDataSSL);
                                                        if(1 == iError)
                                                        {
                                                                m_bSSLAccepted = true;
                                                                SSL_SESSION *session = SSL_get_session(m_pDataSSL);
                                                                if(NULL != session)
                                                                {
                                                                        ATLTRACE(_T("SSL session(id=%x) has been initialized for data channel\n"), session);

                                                                }
                                                                break;
                                                        }
                                                        dwReturn = GetSSLError(iError, strData);
                                                }
                                        }
                                }


                                nRead = SSL_read(m_pDataSSL, szData, PACKET_SIZE);
                                if(nRead > 0)
                                {
                                        RecvdData *structData = new RecvdData(nRead);
                                        memcpy(structData->buffer,szData,nRead);
                                        structData->nRead = nRead;
                                        //Write data received to thread.
                                }
                                else
                                        ProcessReceivedData(nRead, szData);
                        }
                }
        }
        catch(...)
        {
                ATLTRACE("Unhandled exception occurred\n");
                theApp.m_LogFile.Write(_T("CDataSocket::Receive() - Unhandled exception occurred"));
        }

        return nRead;
}
//Free the ssl modules of data connection
bool FreeSSLModules(void)
{
        __try
        {
                if(m_pConnSSL)
                {
                        SSL_shutdown (m_pConnSSL);
                        SSL_free (m_pConnSSL);
                        SSL_CTX_free (m_pConnCTX);

                        CRYPTO_cleanup_all_ex_data();
                        ERR_free_strings();
                        ERR_remove_thread_state(NULL);
                        EVP_cleanup();
                }
                       
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
                theApp.m_LogFile.Write(_T("CConnectSocket::FreeSSLModules - Exception occurred"));
                //If SSL library is failed to free.
                return false;
        }
        return true;
}



Kindly let us know if any other additional APIs need to be called to free the SSL session completely.
We found that SSL session is maintained in the cache after the first upload. i.e about 1000KB of memory is increased after first SSL Session and the memory is not completly deleted.
Kindly let us know if the memory leaks depend on the client (clients using the session).
Reply | Threaded
Open this post in threaded view
|

RE: openssl memory leak

dvijayalakshmi
In reply to this post by Porter, Andrew
We observed that sometimes SSL_Shudown() is not returning success.
If the cache is maintained, will the API fail.
Reply | Threaded
Open this post in threaded view
|

RE: openssl memory leak

dvijayalakshmi
We are testing our application (that uses OpenSSL for FTPS) to check the memory leak over time(continuous FTPS upload is performed for about 12 hours).
We observed that the memory consumed by the process is reduced(about 3MB) after 6 mins.
Kindly let us know if it is related to the SSL session timeout.
Note: We found that a healthy SSL session is retained in the memory until the session timeout occurs.

Awaiting your response.