From 317c5d7e7ac0877120142e720bc540c355e12b52 Mon Sep 17 00:00:00 2001 From: sherlock2010 <15151851377@163.com> Date: Thu, 9 Jul 2020 21:49:17 +0800 Subject: [PATCH] Fix CVE-2019-20892 --- CVE-2019-20892-1.patch | 363 +++++++++++++++++++++++++++++++++++++++++ CVE-2019-20892-2.patch | 89 ++++++++++ CVE-2019-20892-3.patch | 25 +++ CVE-2019-20892-4.patch | 68 ++++++++ CVE-2019-20892-5.patch | 161 ++++++++++++++++++ CVE-2019-20892-6.patch | 106 ++++++++++++ net-snmp.spec | 20 ++- 7 files changed, 828 insertions(+), 4 deletions(-) create mode 100644 CVE-2019-20892-1.patch create mode 100644 CVE-2019-20892-2.patch create mode 100644 CVE-2019-20892-3.patch create mode 100644 CVE-2019-20892-4.patch create mode 100644 CVE-2019-20892-5.patch create mode 100644 CVE-2019-20892-6.patch diff --git a/CVE-2019-20892-1.patch b/CVE-2019-20892-1.patch new file mode 100644 index 0000000..8762caa --- /dev/null +++ b/CVE-2019-20892-1.patch @@ -0,0 +1,363 @@ +From adc9b71aba9168ec64149345ea37a1acc11875c6 Mon Sep 17 00:00:00 2001 +From: Sam Tannous +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() */ diff --git a/CVE-2019-20892-2.patch b/CVE-2019-20892-2.patch new file mode 100644 index 0000000..113444e --- /dev/null +++ b/CVE-2019-20892-2.patch @@ -0,0 +1,89 @@ +From 92ccd5a82a019fbfa835cc8ab2294cf0ca48c8f2 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +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) { diff --git a/CVE-2019-20892-3.patch b/CVE-2019-20892-3.patch new file mode 100644 index 0000000..ce0403f --- /dev/null +++ b/CVE-2019-20892-3.patch @@ -0,0 +1,25 @@ +From 7384a8b550d4ed4a00e41b72229cfcc124926b06 Mon Sep 17 00:00:00 2001 +From: Ming Chen +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) { diff --git a/CVE-2019-20892-4.patch b/CVE-2019-20892-4.patch new file mode 100644 index 0000000..68d8707 --- /dev/null +++ b/CVE-2019-20892-4.patch @@ -0,0 +1,68 @@ +From 39381c4d20dd8042870c28ae3b0c16291e50b705 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +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 diff --git a/CVE-2019-20892-5.patch b/CVE-2019-20892-5.patch new file mode 100644 index 0000000..4789a90 --- /dev/null +++ b/CVE-2019-20892-5.patch @@ -0,0 +1,161 @@ +From 5f881d3bf24599b90d67a45cae7a3eb099cd71c9 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +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 + diff --git a/CVE-2019-20892-6.patch b/CVE-2019-20892-6.patch new file mode 100644 index 0000000..6a74709 --- /dev/null +++ b/CVE-2019-20892-6.patch @@ -0,0 +1,106 @@ +From 87bd90d04f20dd3f73e3e7e631a442ccd419b9d3 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +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 diff --git a/net-snmp.spec b/net-snmp.spec index 64e2a92..f83e1d4 100644 --- a/net-snmp.spec +++ b/net-snmp.spec @@ -3,7 +3,7 @@ Name: net-snmp Version: 5.8 -Release: 9 +Release: 10 Epoch: 1 Summary: SNMP Daemon 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 Patch11: net-snmp-5.7.3-iterator-fix.patch Patch12: net-snmp-5.8-autofs-skip.patch -Patch101: net-snmp-5.8-modern-rpm-api.patch -Patch102: net-snmp-5.8-python3.patch +Patch13: net-snmp-5.8-modern-rpm-api.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} 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* %changelog +* Thu Jul 09 2020 zhouyihang - 5.8-10 +- Type:cves +- ID:CVE-2019-20892 +- SUG:NA +- DESC: Fix CVE-2019-20892 + * Fri May 29 2020 Buildteam - 5.8-9 - rebuild for lm_sensors version update -- Gitee