CVE-2022-45474: Use After Free (CWE-416)
value: drachtio-server 0.8.18 has a request-handler.cpp event_cb use-after-free for any request.
CWE description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
CVSS v3 base score: 9.8
Published: 2022-11-18T18:15Z
Repository: https://github.com/drachtio/drachtio-server
Language: C++
Files changed: src/request-handler.cpp
Commit date: 2022-11-23 15:24:44 -0500
Commit message: fix for use-after-free (#240)

Diff: diff --git a/src/request-handler.cpp b/src/request-handler.cpp
index c3314d8957..4514e624f7 100644
--- a/src/request-handler.cpp
+++ b/src/request-handler.cpp
@@ -265,21 +265,22 @@ namespace drachtio {
 
   /* Called by asio when there is an action on a socket */
   void event_cb(drachtio::RequestHandler::GlobalInfo *g, curl_socket_t s,
                        int action, const boost::system::error_code & error,
                        int *fdp) {
+    int f = *fdp;
     std::shared_ptr<RequestHandler> p = RequestHandler::getInstance() ;
     std::map<curl_socket_t, boost::asio::ip::tcp::socket *>& socket_map = p->getSocketMap() ;
     boost::asio::deadline_timer& timer = p->getTimer() ;
 
     if(socket_map.find(s) == socket_map.end()) {
       DR_LOG(log_error) << "event_cb: socket already closed";
       return;
     }
 
     /* make sure the event matches what are wanted */
-    if(*fdp == action || *fdp == CURL_POLL_INOUT) {
+    if(f == action || f == CURL_POLL_INOUT) {
       CURLMcode rc;
       if(error)
         action = CURL_CSELECT_ERR;
       rc = curl_multi_socket_action(g->multi, s, action, &g->still_running);
 
@@ -292,11 +293,11 @@ namespace drachtio {
 
       /* keep on watching.
        * the socket may have been closed and/or fdp may have been changed
        * in curl_multi_socket_action(), so check them both */
       if(!error && socket_map.find(s) != socket_map.end() &&
-         (*fdp == action || *fdp == CURL_POLL_INOUT)) {
+         (f == action || f == CURL_POLL_INOUT)) {
         boost::asio::ip::tcp::socket *tcp_socket = socket_map.find(s)->second;
 
         if(action == CURL_POLL_IN) {
           tcp_socket->async_read_some(boost::asio::null_buffers(),
                                       boost::bind(&event_cb, g, s,
@@ -474,11 +475,10 @@ namespace drachtio {
 
 
     DR_LOG(log_info) << "RequestHandler::startRequest: sending http " << httpMethod << ": " << url ;
 
     conn = m_pool.malloc() ;
-
     CURL* easy = NULL ;
     {
       //alloc and free happen in the same thread
       //std::lock_guard<std::mutex> l( m_lock ) ;
       if( m_cacheEasyHandles.empty() ) {
@@ -496,10 +496,11 @@ namespace drachtio {
     conn->global = &m_g;
     strncpy(conn->url, url.c_str(), URL_LEN) ;
     strncpy(conn->body, body.c_str(), HTTP_BODY_LEN);
     strncpy(conn->transactionId, transactionId.c_str(), TXNID_LEN);
     conn->hdr_list = NULL ;
+    *conn->response = '\0' ;
 
     curl_easy_setopt(easy, CURLOPT_URL, conn->url);
     curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_cb);
     curl_easy_setopt(easy, CURLOPT_WRITEDATA, conn);
     curl_easy_setopt(easy, CURLOPT_ERRORBUFFER, conn->error);

Vulnerable code:     if(*fdp == action || *fdp == CURL_POLL_INOUT) {
         (*fdp == action || *fdp == CURL_POLL_INOUT)) {

Fixed code:     int f = *fdp;
    if(f == action || f == CURL_POLL_INOUT) {
         (f == action || f == CURL_POLL_INOUT)) {
    *conn->response = '\0' ;