From 87bd90d04f20dd3f73e3e7e631a442ccd419b9d3 Mon Sep 17 00:00:00 2001
From: Bart Van Assche <bvanassche@acm.org>
Date: Tue, 13 Aug 2019 20:54:23 -0700
Subject: [PATCH] libsnmp: Move the free_securityStateRef() call into
 snmp_free_pdu()

This patch fixes a memory leak that was introduced in commit 5f881d3bf245
("libsnmp, USM: Introduce a reference count in struct usmStateReference").

This patch partially reverts commit adc9b71aba91 ("snmpd: Avoid that snmpv3
bulkget errors result in a double free").

See also https://sourceforge.net/p/net-snmp/bugs/2938/.
---
 agent/snmp_agent.c|  6 ------
 include/net-snmp/pdu_api.h |  2 --
 snmplib/snmp_api.c| 23 ++---------------------
 3 files changed, 2 insertions(+), 29 deletions(-)

diff --git a/agent/snmp_agent.c b/agent/snmp_agent.c
index 0a1e263..25350e6 100644
--- a/agent/snmp_agent.c
+++ b/agent/snmp_agent.c
@@ -1605,12 +1605,6 @@ free_agent_snmp_session(netsnmp_agent_session *asp)
     DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n",
                 asp, asp->reqinfo));
 
-    /* Clean up securityStateRef here to prevent a double free */
-    if (asp->orig_pdu)
-	snmp_free_securityStateRef(asp->orig_pdu);
-    if (asp->pdu)
-	snmp_free_securityStateRef(asp->pdu);
-
     if (asp->orig_pdu)
         snmp_free_pdu(asp->orig_pdu);
     if (asp->pdu)
diff --git a/include/net-snmp/pdu_api.h b/include/net-snmp/pdu_api.h
index 270aff0..125595d 100644
--- a/include/net-snmp/pdu_api.h
+++ b/include/net-snmp/pdu_api.h
@@ -19,8 +19,6 @@ NETSNMP_IMPORT
 netsnmp_pdu    *snmp_fix_pdu(  netsnmp_pdu *pdu, int idx);
 NETSNMP_IMPORT
 void            snmp_free_pdu( netsnmp_pdu *pdu);
-NETSNMP_IMPORT
-void            snmp_free_securityStateRef( netsnmp_pdu *pdu);
 
 #ifdef __cplusplus
 }
diff --git a/snmplib/snmp_api.c b/snmplib/snmp_api.c
index e14ae6f..3e57a55 100644
--- a/snmplib/snmp_api.c
+++ b/snmplib/snmp_api.c
@@ -4033,17 +4033,6 @@ free_securityStateRef(netsnmp_pdu* pdu)
     pdu->securityStateRef = NULL;
 }
 
-/*
- * This function is here to provide a separate call to
- * free the securityStateRef memory. This is needed to prevent
- * a double free if this memory is freed in snmp_free_pdu.
- */
-void
-snmp_free_securityStateRef(netsnmp_pdu* pdu)
-{
-   free_securityStateRef(pdu);
-}
-
 #define ERROR_STAT_LENGTH 11
 
 int
@@ -5470,6 +5459,8 @@ snmp_free_pdu(netsnmp_pdu *pdu)
     if (!pdu)
         return;
 
+    free_securityStateRef(pdu);
+
     /*
      * If the command field is empty, that probably indicates
      *   that this PDU structure has already been freed.
@@ -5644,10 +5635,6 @@ _sess_process_packet_parse_pdu(void *sessp, netsnmp_session * sp,
   }
 
   if (ret != SNMP_ERR_NOERROR) {
-    /*
-     * Call the security model to free any securityStateRef supplied w/ msg.  
-     */
-    free_securityStateRef(pdu);
     snmp_free_pdu(pdu);
     return NULL;
   }
@@ -5819,12 +5806,6 @@ _sess_process_packet_handle_pdu(void *sessp, netsnmp_session * sp,
     }
   }
 
-  /*
-   * Call USM to free any securityStateRef supplied with the message.  
-   */
-  if (pdu->command == SNMP_MSG_TRAP2)
-    free_securityStateRef(pdu);
-
   if (!handled) {
     if (sp->flags & SNMP_FLAGS_SHARED_SOCKET)
       return -2;
-- 
1.8.3.1
