Fix CVE-2019-20892

This commit is contained in:
sherlock2010 2020-07-09 21:37:26 +08:00
parent 9474bf22ef
commit 51a1764e29
7 changed files with 828 additions and 4 deletions

363
CVE-2019-20892-1.patch Normal file
View File

@ -0,0 +1,363 @@
From adc9b71aba9168ec64149345ea37a1acc11875c6 Mon Sep 17 00:00:00 2001
From: Sam Tannous <stannous@cumulusnetworks.com>
Date: Wed, 10 Apr 2019 06:57:21 -0700
Subject: [PATCH] snmpd: Avoid that snmpv3 bulkget errors result in a double
free
See also https://sourceforge.net/p/net-snmp/bugs/2923/.
See also https://sourceforge.net/p/net-snmp/patches/1388/.
---
agent/snmp_agent.c | 7 ++++++
include/net-snmp/pdu_api.h | 2 ++
snmplib/snmp_api.c | 11 ++++++++
snmplib/snmpusm.c | 51 ++++++++------------------------------
4 files changed, 31 insertions(+), 40 deletions(-)
diff --git a/agent/snmp_agent.c b/agent/snmp_agent.c
index 26653f4e6..100c4d001 100644
--- a/agent/snmp_agent.c
+++ b/agent/snmp_agent.c
@@ -1604,6 +1604,13 @@ 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 && asp->orig_pdu->securityStateRef)
+ snmp_free_securityStateRef(asp->orig_pdu);
+ if (asp->pdu && asp->pdu->securityStateRef)
+ 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 125595d9a..270aff054 100644
--- a/include/net-snmp/pdu_api.h
+++ b/include/net-snmp/pdu_api.h
@@ -19,6 +19,8 @@ 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 554767a83..321a48f1b 100644
--- a/snmplib/snmp_api.c
+++ b/snmplib/snmp_api.c
@@ -4028,6 +4028,17 @@ 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
diff --git a/snmplib/snmpusm.c b/snmplib/snmpusm.c
index 3cfa1267a..873bd890f 100644
--- a/snmplib/snmpusm.c
+++ b/snmplib/snmpusm.c
@@ -299,16 +299,20 @@ usm_free_usmStateReference(void *old)
if (old_ref) {
- SNMP_FREE(old_ref->usr_name);
- SNMP_FREE(old_ref->usr_engine_id);
- SNMP_FREE(old_ref->usr_auth_protocol);
- SNMP_FREE(old_ref->usr_priv_protocol);
-
- if (old_ref->usr_auth_key) {
+ if (old_ref->usr_name_length)
+ SNMP_FREE(old_ref->usr_name);
+ if (old_ref->usr_engine_id_length)
+ SNMP_FREE(old_ref->usr_engine_id);
+ if (old_ref->usr_auth_protocol_length)
+ SNMP_FREE(old_ref->usr_auth_protocol);
+ if (old_ref->usr_auth_protocol_length)
+ SNMP_FREE(old_ref->usr_priv_protocol);
+
+ if (old_ref->usr_auth_key_length && old_ref->usr_auth_key) {
SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
SNMP_FREE(old_ref->usr_auth_key);
}
- if (old_ref->usr_priv_key) {
+ if (old_ref->usr_priv_key_length && old_ref->usr_priv_key) {
SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
SNMP_FREE(old_ref->usr_priv_key);
}
@@ -1039,7 +1043,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
== NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_UNKNOWNSECURITYNAME;
}
@@ -1091,7 +1094,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
thePrivProtocolLength) == 1) {
DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n",
theSecLevel));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
}
@@ -1121,7 +1123,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
&msgAuthParmLen, &msgPrivParmLen, &otstlen,
&seq_len, &msgSecParmLen) == -1) {
DEBUGMSGTL(("usm", "Failed calculating offsets.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
@@ -1143,7 +1144,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
ptr = *wholeMsg = globalData;
if (theTotalLength > *wholeMsgLen) {
DEBUGMSGTL(("usm", "Message won't fit in buffer.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
@@ -1169,7 +1169,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
htonl(boots_uint), htonl(time_uint),
&ptr[privParamsOffset]) == -1) {
DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
}
@@ -1185,7 +1184,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
&ptr[privParamsOffset])
== -1)) {
DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
}
@@ -1198,7 +1196,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
&ptr[dataOffset], &encrypted_length)
!= SNMP_ERR_NOERROR) {
DEBUGMSGTL(("usm", "encryption error.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_ENCRYPTIONERROR;
}
#ifdef NETSNMP_ENABLE_TESTING_CODE
@@ -1226,7 +1223,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
if ((encrypted_length != (theTotalLength - dataOffset))
|| (salt_length != msgPrivParmLen)) {
DEBUGMSGTL(("usm", "encryption length error.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_ENCRYPTIONERROR;
}
@@ -1362,7 +1358,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
if (temp_sig == NULL) {
DEBUGMSGTL(("usm", "Out of memory.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
@@ -1376,7 +1371,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
SNMP_ZERO(temp_sig, temp_sig_len);
SNMP_FREE(temp_sig);
DEBUGMSGTL(("usm", "Signing failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_AUTHENTICATIONFAILURE;
}
@@ -1384,7 +1378,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
SNMP_ZERO(temp_sig, temp_sig_len);
SNMP_FREE(temp_sig);
DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_AUTHENTICATIONFAILURE;
}
@@ -1398,7 +1391,6 @@ usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
/*
* endif -- create keyed hash
*/
- usm_free_usmStateReference(secStateRef);
DEBUGMSGTL(("usm", "USM processing completed.\n"));
@@ -1548,7 +1540,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
== NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
DEBUGMSGTL(("usm", "Unknown User\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_UNKNOWNSECURITYNAME;
}
@@ -1601,7 +1592,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n",
theSecLevel));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
}
@@ -1636,7 +1626,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
DEBUGMSGTL(("usm",
"couldn't malloc %d bytes for encrypted PDU\n",
(int)ciphertextlen));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_MALLOC;
}
@@ -1652,7 +1641,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
htonl(boots_uint), htonl(time_uint),
iv) == -1) {
DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
- usm_free_usmStateReference(secStateRef);
SNMP_FREE(ciphertext);
return SNMPERR_USM_GENERICERROR;
}
@@ -1667,7 +1655,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
thePrivKeyLength - 8,
iv) == -1)) {
DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
- usm_free_usmStateReference(secStateRef);
SNMP_FREE(ciphertext);
return SNMPERR_USM_GENERICERROR;
}
@@ -1686,7 +1673,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
scopedPdu, scopedPduLen,
ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) {
DEBUGMSGTL(("usm", "encryption error.\n"));
- usm_free_usmStateReference(secStateRef);
SNMP_FREE(ciphertext);
return SNMPERR_USM_ENCRYPTIONERROR;
}
@@ -1703,7 +1689,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
ciphertext, ciphertextlen);
if (rc == 0) {
DEBUGMSGTL(("usm", "Encryption failed.\n"));
- usm_free_usmStateReference(secStateRef);
SNMP_FREE(ciphertext);
return SNMPERR_USM_ENCRYPTIONERROR;
}
@@ -1743,7 +1728,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
DEBUGINDENTLESS();
if (rc == 0) {
DEBUGMSGTL(("usm", "building privParams failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1766,7 +1750,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
DEBUGINDENTLESS();
if (rc == 0) {
DEBUGMSGTL(("usm", "building authParams failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1789,7 +1772,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
DEBUGINDENTLESS();
if (rc == 0) {
DEBUGMSGTL(("usm", "building authParams failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1805,7 +1787,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
if (rc == 0) {
DEBUGMSGTL(("usm",
"building msgAuthoritativeEngineTime failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1821,7 +1802,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
if (rc == 0) {
DEBUGMSGTL(("usm",
"building msgAuthoritativeEngineBoots failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1833,7 +1813,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
DEBUGINDENTLESS();
if (rc == 0) {
DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1846,7 +1825,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
*offset - sp_offset);
if (rc == 0) {
DEBUGMSGTL(("usm", "building usm security parameters failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1860,7 +1838,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
if (rc == 0) {
DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1870,7 +1847,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
while ((*wholeMsgLen - *offset) < globalDataLen) {
if (!asn_realloc(wholeMsg, wholeMsgLen)) {
DEBUGMSGTL(("usm", "building global data failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
}
@@ -1886,7 +1862,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
ASN_CONSTRUCTOR), *offset);
if (rc == 0) {
DEBUGMSGTL(("usm", "building master packet sequence failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_TOO_LONG;
}
@@ -1904,7 +1879,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
if (temp_sig == NULL) {
DEBUGMSGTL(("usm", "Out of memory.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
@@ -1915,14 +1889,12 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
!= SNMP_ERR_NOERROR) {
SNMP_FREE(temp_sig);
DEBUGMSGTL(("usm", "Signing failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_AUTHENTICATIONFAILURE;
}
if (temp_sig_len != msgAuthParmLen) {
SNMP_FREE(temp_sig);
DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
- usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_AUTHENTICATIONFAILURE;
}
@@ -1933,7 +1905,6 @@ usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
/*
* endif -- create keyed hash
*/
- usm_free_usmStateReference(secStateRef);
DEBUGMSGTL(("usm", "USM processing completed.\n"));
return SNMPERR_SUCCESS;
} /* end usm_rgenerate_out_msg() */

89
CVE-2019-20892-2.patch Normal file
View File

@ -0,0 +1,89 @@
From 92ccd5a82a019fbfa835cc8ab2294cf0ca48c8f2 Mon Sep 17 00:00:00 2001
From: Bart Van Assche <bvanassche@acm.org>
Date: Sat, 25 May 2019 16:33:31 +0200
Subject: [PATCH] libsnmp: Move the securityStateRef check into
free_securityStateRef()
Instead of making each free_securityStateRef() caller check the
securityStateRef pointer, move that check into free_securityStateRef().
---
agent/snmp_agent.c | 4 ++--
snmplib/snmp_api.c | 21 ++++++++++-----------
2 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/agent/snmp_agent.c b/agent/snmp_agent.c
index 9d2355e33..b1881c96e 100644
--- a/agent/snmp_agent.c
+++ b/agent/snmp_agent.c
@@ -1606,9 +1606,9 @@ free_agent_snmp_session(netsnmp_agent_session *asp)
asp, asp->reqinfo));
/* Clean up securityStateRef here to prevent a double free */
- if (asp->orig_pdu && asp->orig_pdu->securityStateRef)
+ if (asp->orig_pdu)
snmp_free_securityStateRef(asp->orig_pdu);
- if (asp->pdu && asp->pdu->securityStateRef)
+ if (asp->pdu)
snmp_free_securityStateRef(asp->pdu);
if (asp->orig_pdu)
diff --git a/snmplib/snmp_api.c b/snmplib/snmp_api.c
index 36ab2d2d8..7922ea794 100644
--- a/snmplib/snmp_api.c
+++ b/snmplib/snmp_api.c
@@ -4020,7 +4020,12 @@ snmpv3_parse(netsnmp_pdu *pdu,
static void
free_securityStateRef(netsnmp_pdu* pdu)
{
- struct snmp_secmod_def *sptr = find_sec_mod(pdu->securityModel);
+ struct snmp_secmod_def *sptr;
+
+ if (!pdu->securityStateRef)
+ return;
+
+ sptr = find_sec_mod(pdu->securityModel);
if (sptr) {
if (sptr->pdu_free_state_ref) {
(*sptr->pdu_free_state_ref) (pdu->securityStateRef);
@@ -4142,9 +4147,7 @@ snmpv3_make_report(netsnmp_pdu *pdu, int error)
* FIX - yes they should but USM needs to follow new EoP to determine
* which cached values to use
*/
- if (pdu->securityStateRef) {
- free_securityStateRef(pdu);
- }
+ free_securityStateRef(pdu);
if (error == SNMPERR_USM_NOTINTIMEWINDOW) {
pdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
@@ -5658,9 +5661,7 @@ _sess_process_packet_parse_pdu(void *sessp, netsnmp_session * sp,
/*
* Call the security model to free any securityStateRef supplied w/ msg.
*/
- if (pdu->securityStateRef != NULL) {
- free_securityStateRef(pdu);
- }
+ free_securityStateRef(pdu);
snmp_free_pdu(pdu);
return NULL;
}
@@ -5698,9 +5699,7 @@ _sess_process_packet_handle_pdu(void *sessp, netsnmp_session * sp,
/*
* Call USM to free any securityStateRef supplied with the message.
*/
- if (pdu->securityStateRef) {
- free_securityStateRef(pdu);
- }
+ free_securityStateRef(pdu);
for (rp = isp->requests; rp; orp = rp, rp = rp->next_request) {
snmp_callback callback;
@@ -5845,7 +5844,7 @@ _sess_process_packet_handle_pdu(void *sessp, netsnmp_session * sp,
/*
* Call USM to free any securityStateRef supplied with the message.
*/
- if (pdu->securityStateRef && pdu->command == SNMP_MSG_TRAP2)
+ if (pdu->command == SNMP_MSG_TRAP2)
free_securityStateRef(pdu);
if (!handled) {

25
CVE-2019-20892-3.patch Normal file
View File

@ -0,0 +1,25 @@
From 7384a8b550d4ed4a00e41b72229cfcc124926b06 Mon Sep 17 00:00:00 2001
From: Ming Chen <ming0903@users.sourceforge.net>
Date: Wed, 5 Jun 2019 19:58:44 -0700
Subject: [PATCH] libsnmp: Fix usm_free_usmStateReference()
See also https://sourceforge.net/p/net-snmp/bugs/2923/.
Fixes: adc9b71aba91 ("snmpd: Avoid that snmpv3 bulkget errors result in a double free")
---
snmplib/snmpusm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/snmplib/snmpusm.c b/snmplib/snmpusm.c
index ed7dc2e59..90c485c3c 100644
--- a/snmplib/snmpusm.c
+++ b/snmplib/snmpusm.c
@@ -305,7 +305,7 @@ usm_free_usmStateReference(void *old)
SNMP_FREE(old_ref->usr_engine_id);
if (old_ref->usr_auth_protocol_length)
SNMP_FREE(old_ref->usr_auth_protocol);
- if (old_ref->usr_auth_protocol_length)
+ if (old_ref->usr_priv_protocol_length)
SNMP_FREE(old_ref->usr_priv_protocol);
if (old_ref->usr_auth_key_length && old_ref->usr_auth_key) {

68
CVE-2019-20892-4.patch Normal file
View File

@ -0,0 +1,68 @@
From 39381c4d20dd8042870c28ae3b0c16291e50b705 Mon Sep 17 00:00:00 2001
From: Bart Van Assche <bvanassche@acm.org>
Date: Tue, 23 Jul 2019 10:52:28 -0700
Subject: [PATCH] libsnmp: Unexport struct usmStateReference
Certain snmpd crashes can only be fixed by introducing a reference
count in struct usmStateReference. Unexport that structure such that
changing it does not affect the ABI.
---
include/net-snmp/library/snmpusm.h | 17 +----------------
snmplib/snmpusm.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/include/net-snmp/library/snmpusm.h b/include/net-snmp/library/snmpusm.h
index 3f6078799..49061d8b1 100644
--- a/include/net-snmp/library/snmpusm.h
+++ b/include/net-snmp/library/snmpusm.h
@@ -42,22 +42,7 @@ extern "C" {
/*
* Structures.
*/
- struct usmStateReference {
- char *usr_name;
- size_t usr_name_length;
- u_char *usr_engine_id;
- size_t usr_engine_id_length;
- oid *usr_auth_protocol;
- size_t usr_auth_protocol_length;
- u_char *usr_auth_key;
- size_t usr_auth_key_length;
- oid *usr_priv_protocol;
- size_t usr_priv_protocol_length;
- u_char *usr_priv_key;
- size_t usr_priv_key_length;
- u_int usr_sec_level;
- };
-
+ struct usmStateReference;
/*
* struct usmUser: a structure to represent a given user in a list
diff --git a/snmplib/snmpusm.c b/snmplib/snmpusm.c
index ae2d16906..917865267 100644
--- a/snmplib/snmpusm.c
+++ b/snmplib/snmpusm.c
@@ -84,6 +84,22 @@ netsnmp_feature_child_of(usm_support, usm_all)
netsnmp_feature_require(usm_support)
+struct usmStateReference {
+ char *usr_name;
+ size_t usr_name_length;
+ u_char *usr_engine_id;
+ size_t usr_engine_id_length;
+ oid *usr_auth_protocol;
+ size_t usr_auth_protocol_length;
+ u_char *usr_auth_key;
+ size_t usr_auth_key_length;
+ oid *usr_priv_protocol;
+ size_t usr_priv_protocol_length;
+ u_char *usr_priv_key;
+ size_t usr_priv_key_length;
+ u_int usr_sec_level;
+};
+
oid usmNoAuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
NETSNMP_USMAUTH_NOAUTH };
#ifndef NETSNMP_DISABLE_MD5

161
CVE-2019-20892-5.patch Normal file
View File

@ -0,0 +1,161 @@
From 5f881d3bf24599b90d67a45cae7a3eb099cd71c9 Mon Sep 17 00:00:00 2001
From: Bart Van Assche <bvanassche@acm.org>
Date: Sat, 27 Jul 2019 19:34:09 -0700
Subject: [PATCH] libsnmp, USM: Introduce a reference count in struct
usmStateReference
This patch fixes https://sourceforge.net/p/net-snmp/bugs/2956/.
---
snmplib/snmp_client.c | 22 +++----------
snmplib/snmpusm.c | 73 ++++++++++++++++++++++++++++---------------
2 files changed, 53 insertions(+), 42 deletions(-)
diff --git a/snmplib/snmp_client.c b/snmplib/snmp_client.c
index 2a46351..b2ea891 100644
--- a/snmplib/snmp_client.c
+++ b/snmplib/snmp_client.c
@@ -402,27 +402,16 @@ _clone_pdu_header(netsnmp_pdu *pdu)
return NULL;
}
- if (pdu->securityStateRef &&
- pdu->command == SNMP_MSG_TRAP2) {
-
- ret = usm_clone_usmStateReference((struct usmStateReference *) pdu->securityStateRef,
- (struct usmStateReference **) &newpdu->securityStateRef );
-
- if (ret)
- {
+ sptr = find_sec_mod(newpdu->securityModel);
+ if (sptr && sptr->pdu_clone) {
+ /* call security model if it needs to know about this */
+ ret = sptr->pdu_clone(pdu, newpdu);
+ if (ret) {
snmp_free_pdu(newpdu);
return NULL;
}
}
- if ((sptr = find_sec_mod(newpdu->securityModel)) != NULL &&
- sptr->pdu_clone != NULL) {
- /*
- * call security model if it needs to know about this
- */
- (*sptr->pdu_clone) (pdu, newpdu);
- }
-
return newpdu;
}
diff --git a/snmplib/snmpusm.c b/snmplib/snmpusm.c
index c4e11b3..9e912c1 100644
--- a/snmplib/snmpusm.c
+++ b/snmplib/snmpusm.c
@@ -85,6 +85,7 @@ netsnmp_feature_child_of(usm_support, usm_all)
netsnmp_feature_require(usm_support)
struct usmStateReference {
+ int refcnt;
char *usr_name;
size_t usr_name_length;
u_char *usr_engine_id;
@@ -301,43 +302,63 @@ free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg,
struct usmStateReference *
usm_malloc_usmStateReference(void)
{
- struct usmStateReference *retval = (struct usmStateReference *)
- calloc(1, sizeof(struct usmStateReference));
+ struct usmStateReference *retval;
+
+ retval = calloc(1, sizeof(struct usmStateReference));
+ if (retval)
+ retval->refcnt = 1;
return retval;
} /* end usm_malloc_usmStateReference() */
+static int
+usm_clone(netsnmp_pdu *pdu, netsnmp_pdu *new_pdu)
+{
+ struct usmStateReference *ref = pdu->securityStateRef;
+ struct usmStateReference **new_ref =
+ (struct usmStateReference **)&new_pdu->securityStateRef;
+ int ret = 0;
+
+ if (!ref)
+ return ret;
+
+ if (pdu->command == SNMP_MSG_TRAP2) {
+ netsnmp_assert(pdu->securityModel == SNMP_DEFAULT_SECMODEL);
+ ret = usm_clone_usmStateReference(ref, new_ref);
+ } else {
+ netsnmp_assert(ref == *new_ref);
+ ref->refcnt++;
+ }
+
+ return ret;
+}
void
usm_free_usmStateReference(void *old)
{
- struct usmStateReference *old_ref = (struct usmStateReference *) old;
-
- if (old_ref) {
-
- if (old_ref->usr_name_length)
- SNMP_FREE(old_ref->usr_name);
- if (old_ref->usr_engine_id_length)
- SNMP_FREE(old_ref->usr_engine_id);
- if (old_ref->usr_auth_protocol_length)
- SNMP_FREE(old_ref->usr_auth_protocol);
- if (old_ref->usr_priv_protocol_length)
- SNMP_FREE(old_ref->usr_priv_protocol);
-
- if (old_ref->usr_auth_key_length && old_ref->usr_auth_key) {
- SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
- SNMP_FREE(old_ref->usr_auth_key);
- }
- if (old_ref->usr_priv_key_length && old_ref->usr_priv_key) {
- SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
- SNMP_FREE(old_ref->usr_priv_key);
- }
+ struct usmStateReference *ref = old;
+
+ if (!ref)
+ return;
+
+ if (--ref->refcnt > 0)
+ return;
- SNMP_ZERO(old_ref, sizeof(*old_ref));
- SNMP_FREE(old_ref);
+ SNMP_FREE(ref->usr_name);
+ SNMP_FREE(ref->usr_engine_id);
+ SNMP_FREE(ref->usr_auth_protocol);
+ SNMP_FREE(ref->usr_priv_protocol);
+ if (ref->usr_auth_key_length && ref->usr_auth_key) {
+ SNMP_ZERO(ref->usr_auth_key, ref->usr_auth_key_length);
+ SNMP_FREE(ref->usr_auth_key);
+ }
+ if (ref->usr_priv_key_length && ref->usr_priv_key) {
+ SNMP_ZERO(ref->usr_priv_key, ref->usr_priv_key_length);
+ SNMP_FREE(ref->usr_priv_key);
}
+ SNMP_FREE(ref);
} /* end usm_free_usmStateReference() */
struct usmUser *
@@ -3332,6 +3353,7 @@ init_usm(void)
def->encode_reverse = usm_secmod_rgenerate_out_msg;
def->encode_forward = usm_secmod_generate_out_msg;
def->decode = usm_secmod_process_in_msg;
+ def->pdu_clone = usm_clone;
def->pdu_free_state_ref = usm_free_usmStateReference;
def->session_setup = usm_session_init;
def->handle_report = usm_handle_report;
--
1.8.3.1

106
CVE-2019-20892-6.patch Normal file
View File

@ -0,0 +1,106 @@
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

View File

@ -3,7 +3,7 @@
Name: net-snmp Name: net-snmp
Version: 5.8 Version: 5.8
Release: 9 Release: 10
Epoch: 1 Epoch: 1
Summary: SNMP Daemon Summary: SNMP Daemon
License: BSD License: BSD
@ -32,10 +32,16 @@ Patch9: net-snmp-5.8-Remove-U64-typedef.patch
Patch10: net-snmp-5.8-libnetsnmptrapd-against-MYSQL_LIBS.patch Patch10: net-snmp-5.8-libnetsnmptrapd-against-MYSQL_LIBS.patch
Patch11: net-snmp-5.7.3-iterator-fix.patch Patch11: net-snmp-5.7.3-iterator-fix.patch
Patch12: net-snmp-5.8-autofs-skip.patch Patch12: net-snmp-5.8-autofs-skip.patch
Patch101: net-snmp-5.8-modern-rpm-api.patch Patch13: net-snmp-5.8-modern-rpm-api.patch
Patch102: net-snmp-5.8-python3.patch Patch14: net-snmp-5.8-python3.patch
Patch6000: avoid-triggering-undefined-shift-left.patch Patch15: avoid-triggering-undefined-shift-left.patch
Patch16: CVE-2019-20892-1.patch
Patch17: CVE-2019-20892-2.patch
Patch18: CVE-2019-20892-3.patch
Patch19: CVE-2019-20892-4.patch
Patch20: CVE-2019-20892-5.patch
Patch21: CVE-2019-20892-6.patch
%{?systemd_requires} %{?systemd_requires}
BuildRequires: systemd gcc openssl-devel bzip2-devel elfutils-devel libselinux-devel BuildRequires: systemd gcc openssl-devel bzip2-devel elfutils-devel libselinux-devel
@ -315,6 +321,12 @@ LD_LIBRARY_PATH=%{buildroot}/%{_libdir} make test
%{_mandir}/man1/fixproc* %{_mandir}/man1/fixproc*
%changelog %changelog
* Thu Jul 09 2020 zhouyihang <zhouyihang3@huawei.com> - 5.8-10
- Type:cves
- ID:CVE-2019-20892
- SUG:NA
- DESC: Fix CVE-2019-20892
* Fri Jun 19 2020 gaihuiying <gaihuiying1@huawei.com> - 5.8-9 * Fri Jun 19 2020 gaihuiying <gaihuiying1@huawei.com> - 5.8-9
- Type:bugfix - Type:bugfix
- ID:NA - ID:NA