Good morning
I'm a developer at Zabbix and we use Net-snmp for implenting snmp monitoring. While establishing a session for performing some snmp checks, the process can crash due to the fact that inside _sess_open() an already freed pointer is re-used. Here is a back trace:
#0 thrkill () at -:3 #1 0x00000c4b902b435d in _libc_abort () at /usr/src/lib/libc/stdlib/abort.c:51 #2 0x00000c4934dc0e28 in log_fatal_signal (sig=11, siginfo=0x7f7fffe7ae80, context=0x7f7fffe7ad90) at sighandler.c:33 #3 0x00000c4934dc09de in fatal_signal_handler (sig=11, siginfo=0x7f7fffe7ae80, context=0x7f7fffe7ad90) at sighandler.c:60 #4 <signal handler called> #5 strlen () at /usr/src/lib/libc/arch/amd64/string/strlen.S:124 #6 0x00000c4b90310f62 in _libc_strdup (str=0xc4c1d74ee00 <Address 0xc4c1d74ee00 out of bounds>) at /usr/src/lib/libc/string/strdup.c:44 #7 0x00000c4b7322f16c in netsnmp_ds_set_string () from /usr/local/lib/libnetsnmp.so.14.0 #8 0x00000c4b731ffeac in snmp_sess_open () from /usr/local/lib/libnetsnmp.so.14.0 #9 0x00000c4b731ffde9 in snmp_open () from /usr/local/lib/libnetsnmp.so.14.0 #10 0x00000c4934d1ea54 in zbx_snmp_open_session (item=0x7f7fffe7ee30, error=0x7f7fffe7b840 "", max_error_len=2048) at checks_snmp.c:630 #11 0x00000c4934d1dbaf in get_values_snmp (items=0x7f7fffe7ee30, results=0x7f7fffe7ce30, errcodes=0x7f7fffe7cc30, num=1) at checks_snmp.c:2097 #12 0x00000c4934d26dbd in get_values (poller_type=0 '\0', nextcheck=0x7f7fffff86ac) at poller.c:571 #13 0x00000c4934d25717 in poller_thread (args=0x7f7fffff8748) at poller.c:778 #14 0x00000c4934dd0f91 in zbx_thread_start (handler=0xc4934d25590 <poller_thread>, thread_args=0x7f7fffff8748) at threads.c:128 #15 0x00000c4934d0f54c in MAIN_ZABBIX_ENTRY (flags=2) at server.c:1040 #16 0x00000c4934dbf854 in daemon_start (allow_root=0, user=0x0, flags=2) at daemon.c:392 #17 0x00000c4934d0eca2 in main (argc=3, argv=0x7f7fffff96d8) at server.c:819
The problem is also reproducible on Linux using valgrind (but it will not cause a crash). The problematic code is here (some additional comments for clarity):
static void * _sess_open(netsnmp_session * in_session) { netsnmp_transport *transport = NULL; int rc; in_session->s_snmp_errno = 0; in_session->s_errno = 0; _init_snmp(); { char *clientaddr_save = NULL; if (NULL != in_session->localname) { // returns pointer stored in netsnmp_ds_strings[NETSNMP_DS_LIBRARY_ID][NETSNMP_DS_LIB_CLIENT_ADDR] clientaddr_save = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR); // frees pointer stored in netsnmp_ds_strings[NETSNMP_DS_LIBRARY_ID][NETSNMP_DS_LIB_CLIENT_ADDR] netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR, in_session->localname); } if (in_session->flags & SNMP_FLAGS_STREAM_SOCKET) { transport = netsnmp_tdomain_transport_full("snmp", in_session->peername, in_session->local_port, "tcp,tcp6", NULL); } else { transport = netsnmp_tdomain_transport_full("snmp", in_session->peername, in_session->local_port, "udp,udp6", NULL); } if (NULL != clientaddr_save) // tries to use saved pointer which was already freed netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save); }
We also tried to check if we were using the library incorrectly, but it doesn't seems the case. If you think that this is not a bug and we need to do something different, just advise.
I can be contacted at: andrea.biscuola@zabbix.com
Possible patch attached..
A definitive patch tested and working for OpenBSD attached (committed by Stuart Henderson in the ports tree):
It seems like that patch has been generated against an old version of Net-SNMP? Anyway, a somewhat modified version of this patch has been applied on the v5.7 and master branches. See also https://sourceforge.net/p/net-snmp/code/ci/d687248669257328805cf0a6ff00428d0f8db66c/.
Actually the patch was generated from net-snmp 5.7.3 as present in the OpenBSD ports tree. Also I don't see patch versions for it.
Anyway, thanks for fixing the problem!