Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

snmp plugin: double free or heap corruption #2291

Closed
cullorblind opened this issue May 18, 2017 · 27 comments
Closed

snmp plugin: double free or heap corruption #2291

cullorblind opened this issue May 18, 2017 · 27 comments

Comments

@cullorblind
Copy link

cullorblind commented May 18, 2017

  • Version of collectd: 5.7.0-3~bpo8+1 from debian jessie backports repo
  • Operating system / distribution: debian 8.8 jessie

Expected behavior

I am polling connected clients across about 150 ubiquiti access points from the SNMP Station table. A few of the Access points have 0 clients, and therefore return nothing. If the instance string returns nothing it should gracefully log(optional) and move on to the next task.

Actual behavior

After much testing I narrowed it down to a single access point which I realized had no clients attached. With only that access point configured I get the double free or corruption error.
collectd -T
*** Error in `collectd': double free or corruption (!prev): 0x000000000236dd10 ***
Aborted

If the instance OID returns no data it dies here.

Configs to reproduce

my_types.db
ubnt_rm5_sta signal:GAUGE:U:U, noisefloor:GAUGE:U:U, ccq:GAUGE:U:U, amq:GAUGE:U:U, amc:GAUGE:U:U

snmp-rm5.conf

LoadPlugin snmp
<Plugin snmp>
    <Data "stations">
      Type "ubnt_rm5_sta"
      Table true
      Instance ".1.3.6.1.4.1.41112.1.4.7.1.2"
      Values ".1.3.6.1.4.1.41112.1.4.7.1.3" ".1.3.6.1.4.1.41112.1.4.7.1.4"  ".1.3.6.1.4.1.41112.1.4.7.1.6" ".1.3.6.1.4.1.41112.1.4.7.1.8" ".1.3.6.1.4.1.41112.1.4.7.1.9"
    </Data>

   <Host "ubnt-rm5-allstate-N-120">
       Address "172.16.16.253"
       Version 1
       Community "public"
       Collect "stations"
   </Host>
</Plugin>

Extra info from the mib for what I'm polling.

snmptranslate -m /root/MIBs/UBNT-MIB.txt -Tz | grep ubntSta
"ubntStaTable"                  "1.3.6.1.4.1.41112.1.4.7"
"ubntStaEntry"                  "1.3.6.1.4.1.41112.1.4.7.1"
"ubntStaMac"                    "1.3.6.1.4.1.41112.1.4.7.1.1"
"ubntStaName"                   "1.3.6.1.4.1.41112.1.4.7.1.2"
"ubntStaSignal"                 "1.3.6.1.4.1.41112.1.4.7.1.3"
"ubntStaNoiseFloor"                     "1.3.6.1.4.1.41112.1.4.7.1.4"
"ubntStaDistance"                       "1.3.6.1.4.1.41112.1.4.7.1.5"
"ubntStaCcq"                    "1.3.6.1.4.1.41112.1.4.7.1.6"
"ubntStaAmp"                    "1.3.6.1.4.1.41112.1.4.7.1.7"
"ubntStaAmq"                    "1.3.6.1.4.1.41112.1.4.7.1.8"
"ubntStaAmc"                    "1.3.6.1.4.1.41112.1.4.7.1.9"
"ubntStaLastIp"                 "1.3.6.1.4.1.41112.1.4.7.1.10"
"ubntStaTxRate"                 "1.3.6.1.4.1.41112.1.4.7.1.11"
"ubntStaRxRate"                 "1.3.6.1.4.1.41112.1.4.7.1.12"
"ubntStaTxBytes"                        "1.3.6.1.4.1.41112.1.4.7.1.13"
"ubntStaRxBytes"                        "1.3.6.1.4.1.41112.1.4.7.1.14"
"ubntStaConnTime"                       "1.3.6.1.4.1.41112.1.4.7.1.15"

Let me know if you need any more information.

edit:fixed formatting on files/output.

@octo octo changed the title SNMP table snmp plugin: double free or heap corruption May 19, 2017
@octo octo added the Bug A genuine bug label May 19, 2017
@octo
Copy link
Member

octo commented May 19, 2017

Hi @cullorblind, thank you very much for reporting this issue! Is there any chance that you could create a stack trace of this problem? The Core file wiki page has steps to walk you through the process.

Thanks and best regards,
—octo

@cullorblind
Copy link
Author

I think I got it here. Let me know if you need any more info.

root@graphite-collector1:~# gdb /usr/sbin/collectd /root/core.collectd.0.45c938a4867d422e8c8e5d151b04e8b2.1341.1495201488000000000000
GNU gdb (Debian 7.11.1-2~bpo8+1) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/sbin/collectd...Reading symbols from /usr/lib/debug/.build-id/06/6c3e6bfd8ea5ce2c9864f4f07572492fbda0d0.debug...done.
done.
[New LWP 1353]
[New LWP 1341]
[New LWP 1349]
[New LWP 1350]
[New LWP 1351]
[New LWP 1352]
[New LWP 1348]
[New LWP 1347]
[New LWP 1346]
[New LWP 1345]
[New LWP 1344]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/usr/sbin/collectd'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007fa70b314067 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[Current thread is 1 (Thread 0x7fa70479c700 (LWP 1353))]
(gdb) backtrace full
#0  0x00007fa70b314067 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
        resultvar = 0
        pid = 1341
        selftid = 1353
#1  0x00007fa70b315448 in __GI_abort () at abort.c:89
        save_stage = 2
        act = {__sigaction_handler = {sa_handler = 0x7fa6fc01be10, sa_sigaction = 0x7fa6fc01be10}, sa_mask = {__val = {11, 9989, 140355397636187, 140355169183968, 161369041, 140355169183872, 140355169183872,
              140355169159392, 140355169168897, 653150398, 1, 140355169166336, 140355397636345, 124, 140355169159392, 4294967296}}, sa_flags = 161370904, sa_restorer = 0x0}
        sigs = {__val = {32, 0 <repeats 15 times>}}
#2  0x00007fa70b3521b4 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7fa70b447210 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
        ap = {{gp_offset = 40, fp_offset = 32679, overflow_arg_area = 0x7fa704797d50, reg_save_area = 0x7fa704797ce0}}
        fd = 2
        on_2 = <optimized out>
        list = <optimized out>
        nlist = <optimized out>
        cp = <optimized out>
        written = <optimized out>
#3  0x00007fa70b35798e in malloc_printerr (action=1, str=0x7fa70b44333e "free(): invalid size", ptr=<optimized out>) at malloc.c:4996
        buf = "00007fa6fc002810"
        cp = <optimized out>
#4  0x00007fa70b358696 in _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3840
        size = <optimized out>
        fb = <optimized out>
        nextchunk = <optimized out>
        nextsize = <optimized out>
        nextinuse = <optimized out>
        prevsize = <optimized out>
        bck = <optimized out>
        fwd = <optimized out>
        errstr = <optimized out>
        locked = <optimized out>
        __func__ = "_int_free"
#5  0x00007fa709a071e1 in snmp_free_pdu () from /usr/lib/x86_64-linux-gnu/libnetsnmp.so.30
No symbol table info available.
#6  0x00007fa709cb2b71 in csnmp_read_table (host=0x1d721e0, data=0x1d7ff00) at snmp.c:1496
        req = 0x7fa6fc002710
        res = 0x0
        vb = 0x7fa6fc01ef90
        ds = 0x1ccd930
        oid_list_len = <optimized out>
        oid_list = 0x7fa704797e30
        oid_list_todo = <optimized out>
        status = -1
        i = 10
        instance_list_head = 0x0
        instance_list_tail = <optimized out>
        value_list_head = 0x7fa6fc002650
        value_list_tail = 0x7fa6fc0026b0
        __PRETTY_FUNCTION__ = "csnmp_read_table"
#7  0x00007fa709cb3545 in csnmp_read_host (ud=<optimized out>) at snmp.c:1648
        data = <optimized out>
        host = 0x1d721e0
        status = <optimized out>
        success = 0
        i = 0
#8  0x000000000040f1f2 in plugin_read_thread (args=<optimized out>) at plugin.c:538
        callback = <optimized out>
        rf = 0x1cd5e70
        old_ctx = {interval = 0, flush_interval = 0, flush_timeout = 0}
        status = <optimized out>
        rf_type = 1
        start = 1605460373055123765
        now = <optimized out>
        elapsed = <optimized out>
        rc = <optimized out>
        __PRETTY_FUNCTION__ = "plugin_read_thread"
#9  0x00007fa70bca5064 in start_thread (arg=0x7fa70479c700) at pthread_create.c:309
        __res = <optimized out>
        pd = 0x7fa70479c700
        now = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140355311355648, -848822921697474413, 0, 140355441639520, 3, 140355311355648, 825963029144488083, 825979078188812435}, mask_was_saved = 0}}, priv = {pad = {
---Type <return> to continue, or q <return> to quit---
              0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        pagesize_m1 = <optimized out>
        sp = <optimized out>
        freesize = <optimized out>
        __PRETTY_FUNCTION__ = "start_thread"
#10 0x00007fa70b3c762d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
No locals.

@octo
Copy link
Member

octo commented May 19, 2017

That's perfect, thanks @cullorblind!

This shows that the problem is triggered by a call to snmp_free_pdu(). The variable, req, is previously passed to snmp_sess_synch_response() which apparently, under certain circumstances, frees req. My guess would be that we're walking into a corner case in which req is freed and that is not handled correctly. I'll see if I can find the docs for snmp_sess_synch_response()

@octo
Copy link
Member

octo commented May 19, 2017

The current implementation always returns STAT_ERROR when it freed the req argument. If anything, this could lead to memory leaking, not double frees (as far as I can tell). Which

Am I right in assuming that you're using libsnmp30 5.7.2.1+dfsg-1~dfsg?

@cullorblind
Copy link
Author

I don't have the extra ~dfsg on mine, but the rest matches exactly.

 dpkg -l | grep libsnmp30
ii  libsnmp30:amd64                5.7.2.1+dfsg-1                     amd64        SNMP (Simple Network Management Protocol) library```

@rpv-tomsk
Copy link
Contributor

Hi!
I'm tried to dig sources too...

It looks like snmp_sess_synch_response() returns STAT_SUCCESS when that issue happens.

Otherwise the req variable will be assigned to NULL and no snmp_free_pdu(req) call should occur in line 1496.

  status = 0;
  while (status == 0) {
    ...
    status = snmp_sess_synch_response(host->sess_handle, req, &res);
    if ((status != STAT_SUCCESS) || (res == NULL)) {

     if (res != NULL)
        snmp_free_pdu(res);
      res = NULL;

      /* snmp_synch_response already freed our PDU */
      req = NULL;
      ...
      break;
    }
  ...
  } /* while (status == 0) */

  if (res != NULL)
    snmp_free_pdu(res);
  res = NULL;

  if (req != NULL)
    snmp_free_pdu(req);      ### LINE 1496 where double free happens
  req = NULL;
  ...

Is I'm right?

@rpv-tomsk
Copy link
Contributor

rpv-tomsk commented May 28, 2017

As I understand sources, second arg of snmp_sess_synch_response() always freed inside that call.

Proofs:

https://github.com/hardaker/net-snmp/blob/a7bc508a8930a484c3a666cbea4ab226d2a3aa88/snmplib/snmp_api.c#L1253

The pdu allocated in L1263, passed to snmp_sess_synch_response in L1286 and there is no more free() calls at all.

Other usage examples of snmp_sess_synch_response function shows the same:

https://github.com/hardaker/net-snmp/blob/a7bc508a8930a484c3a666cbea4ab226d2a3aa88/perl/SNMP/SNMP.xs#L1087
https://github.com/hardaker/net-snmp/blob/a7bc508a8930a484c3a666cbea4ab226d2a3aa88/python/netsnmp/client_intf.c#L859
https://github.com/hardaker/net-snmp/blob/a7bc508a8930a484c3a666cbea4ab226d2a3aa88/snmplib/snmpusm.c#L3124

The question is: How that worked before?

I think in case of this topic, break (and exit from while loop) occurs in https://github.com/collectd/collectd/blob/collectd-5.7/src/snmp.c#L1397
The req variable already freed inside of snmp_sess_synch_response then, but still != NULL.

In other cases, exit from while loop occurs in https://github.com/collectd/collectd/blob/collectd-5.7/src/snmp.c#L1361, when req is 'newly'-assigned.

IMHO, the solution is to move req = NULL from L1380 to L1366 (to put it right after snmp_sess_synch_response call).

Or, may be quite more clear solution (patch against 5.7):

diff --git a/src/snmp.c b/src/snmp.c
index 3bfec47..2e2d0e7 100644
--- a/src/snmp.c
+++ b/src/snmp.c
@@ -1357,11 +1357,13 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
     if (oid_list_todo_num == 0) {
       /* The request is still empty - so we are finished */
       DEBUG("snmp plugin: all variables have left their subtree");
+      snmp_free_pdu(req);
       status = 0;
       break;
     }

     res = NULL;
+    /* snmp_sess_synch_response always frees our req PDU */
     status = snmp_sess_synch_response(host->sess_handle, req, &res);
     if ((status != STAT_SUCCESS) || (res == NULL)) {
       char *errstr = NULL;
@@ -1376,8 +1378,6 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
         snmp_free_pdu(res);
       res = NULL;

-      /* snmp_synch_response already freed our PDU */
-      req = NULL;
       sfree(errstr);
       csnmp_host_close_session(host);

@@ -1492,9 +1492,6 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
     snmp_free_pdu(res);
   res = NULL;

-  if (req != NULL)
-    snmp_free_pdu(req);
-  req = NULL;

   if (status == 0)
     csnmp_dispatch_table(host, data, instance_list_head, value_list_head);

@cullorblind
Copy link
Author

I don't know if this helps, but I managed to get a core file from collectd while it was running instead of just "collectd -T". One of our APs was rebooted and before any clients reconnected, collectd polled and crashed/restarted a few times until clients reconnected. It looks mostly the same without the snmp_free_pdu section.

root@graphite-collector1:~/collectd-cores# gdb /usr/sbin/collectd /root/collectd-cores/core.collectd.0.45c938a4867d422e8c8e5d151b04e8b2.13163.149584476700
0000000000
GNU gdb (Debian 7.11.1-2~bpo8+1) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/sbin/collectd...Reading symbols from /usr/lib/debug/.build-id/06/6c3e6bfd8ea5ce2c9864f4f07572492fbda0d0.debug...done.
done.
[New LWP 13200]
[New LWP 13201]
[New LWP 13163]
[New LWP 13165]
[New LWP 13202]
[New LWP 13166]
[New LWP 13167]
[New LWP 13203]
[New LWP 13173]
[New LWP 13164]
[New LWP 13175]
[New LWP 13168]
[New LWP 13176]
[New LWP 13169]
[New LWP 13177]
[New LWP 13170]
[New LWP 13178]
[New LWP 13171]
[New LWP 13179]
[New LWP 13180]
[New LWP 13172]
[New LWP 13181]
[New LWP 13174]
[New LWP 13182]
[New LWP 13184]
[New LWP 13183]
[New LWP 13185]
[New LWP 13198]
[New LWP 13186]
[New LWP 13187]
[New LWP 13188]
[New LWP 13189]
[New LWP 13190]
[New LWP 13191]
[New LWP 13192]
[New LWP 13193]
[New LWP 13194]
[New LWP 13195]
[New LWP 13196]
[New LWP 13197]
[New LWP 13199]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/usr/sbin/collectd'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007f086e472067 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[Current thread is 1 (Thread 0x7f0859ed9700 (LWP 13200))]
(gdb) backtrace full
#0  0x00007f086e472067 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
        resultvar = 0
        pid = 13163
        selftid = 13200
#1  0x00007f086e473448 in __GI_abort () at abort.c:89
        save_stage = 2
        act = {__sigaction_handler = {sa_handler = 0x2705, sa_sigaction = 0x2705}, sa_mask = {__val = {139674160214107, 139673410413280, 1823747025,
              139673410413184, 139673410413184, 139673410654496, 139673410405633, 970455699, 1, 139673410603776, 139674160214265, 124, 139673410654496,
              4294967296, 139674160214808, 0}}, sa_flags = 272, sa_restorer = 0x100000000}
        sigs = {__val = {32, 0 <repeats 15 times>}}
#2  0x00007f086e4b01b4 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f086e5a5210 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
        ap = {{gp_offset = 40, fp_offset = 32520, overflow_arg_area = 0x7f0859ed4d60, reg_save_area = 0x7f0859ed4cf0}}
        fd = 2
        on_2 = <optimized out>
        list = <optimized out>
        nlist = <optimized out>
        cp = <optimized out>
        written = <optimized out>
#3  0x00007f086e4b598e in malloc_printerr (action=1, str=0x7f086e5a5360 "double free or corruption (out)", ptr=<optimized out>) at malloc.c:4996
        buf = "00007f0840057d70"
        cp = <optimized out>
#4  0x00007f086e4b6696 in _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3840
        size = <optimized out>
        fb = <optimized out>
        nextchunk = <optimized out>
        nextsize = <optimized out>
        nextinuse = <optimized out>
        prevsize = <optimized out>
        bck = <optimized out>
        fwd = <optimized out>
        errstr = <optimized out>
        locked = <optimized out>
        __func__ = "_int_free"
#5  0x00007f086ce10b71 in csnmp_read_table (host=0x1c4aef0, data=0x1c44fe0) at snmp.c:1496
        req = 0x7f0840057d70
        res = 0x0
        vb = 0x7f0840055f70
        ds = 0x1b414f0
        oid_list_len = <optimized out>
        oid_list = 0x7f0859ed4e30
        oid_list_todo = <optimized out>
        status = -1
        i = 10
        instance_list_head = 0x0
        instance_list_tail = <optimized out>
        value_list_head = 0x7f084000aae0
        value_list_tail = 0x7f0840047dd0
        __PRETTY_FUNCTION__ = "csnmp_read_table"
#6  0x00007f086ce11545 in csnmp_read_host (ud=<optimized out>) at snmp.c:1648
        data = <optimized out>
        host = 0x1c4aef0
        status = <optimized out>
        success = 0
        i = 0
#7  0x000000000040f1f2 in plugin_read_thread (args=<optimized out>) at plugin.c:538
        callback = <optimized out>
        rf = 0x1c4b0e0
        old_ctx = {interval = 0, flush_interval = 0, flush_timeout = 0}
        status = <optimized out>
        rf_type = 1
        start = 1606151088684808395
        now = <optimized out>
        elapsed = <optimized out>
        rc = <optimized out>
        __PRETTY_FUNCTION__ = "plugin_read_thread"
#8  0x00007f086ee03064 in start_thread (arg=0x7f0859ed9700) at pthread_create.c:309
        __res = <optimized out>
        pd = 0x7f0859ed9700
        now = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {139673845208832, -7016881850212608820, 0, 139674204217440, 3, 139673845208832, 6957978931956880588,
                6958020614572152012}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        pagesize_m1 = <optimized out>
        sp = <optimized out>
        freesize = <optimized out>
        __PRETTY_FUNCTION__ = "start_thread"
#9  0x00007f086e52562d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
No locals.
root@graphite-collector1:~/collectd-cores#

@rpv-tomsk
Copy link
Contributor

#5 0x00007f086ce10b71 in csnmp_read_table (host=0x1c4aef0, data=0x1c44fe0) at snmp.c:1496

That is the same line L1496 of snmp_free_pdu(req); call in your new backtrace.

Can you please try to test mine proposed patch?

@cullorblind
Copy link
Author

cullorblind commented May 30, 2017

I finally got a VM spun up where I could compile/test this. It seems to be working. The "empty" tables returned on APs with no clients now log to syslog properly without crashing.

May 30 10:04:57 debian collectd[32543]: [2017-05-30 10:04:58] snmp plugin: host ubnt-rm5-abell-S-120: csnmp_instance_list_add failed.

I've manually copied the snmp.so plugin over to my collector for a proper stress test with 204 APs. ~12 of those currently have no clients and it's running okay so far.

@rpv-tomsk
Copy link
Contributor

rpv-tomsk commented May 31, 2017

Could you please show

snmpwalk -v2c -c public 172.16.16.253 1.3.6.1.4.1.41112.1.4.7

or something similar to show which data is present in case of AP with 0 clients.

I think we also need that output for each 'table' separately (like requests collectd does):

snmpwalk  -v2c -c public 172.16.16.253 .1.3.6.1.4.1.41112.1.4.7.1.2
snmpwalk  -v2c -c public 172.16.16.253 .1.3.6.1.4.1.41112.1.4.7.1.3
snmpwalk  -v2c -c public 172.16.16.253 .1.3.6.1.4.1.41112.1.4.7.1.4
snmpwalk  -v2c -c public 172.16.16.253 .1.3.6.1.4.1.41112.1.4.7.1.6
snmpwalk  -v2c -c public 172.16.16.253 .1.3.6.1.4.1.41112.1.4.7.1.8
snmpwalk  -v2c -c public 172.16.16.253 .1.3.6.1.4.1.41112.1.4.7.1.9

Sorry, I'm not familiar enough with SNMP, so you required to set correct MIB/OID in these commands.
Thanks.

I'm expect to get something like this:

Full tree

# snmpwalk  -v2c -c public 127.0.0.1 iso.3.6.1.2.1.2.2.1
iso.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1
iso.3.6.1.2.1.2.2.1.1.2 = INTEGER: 2
iso.3.6.1.2.1.2.2.1.2.1 = STRING: "GbE_1"
iso.3.6.1.2.1.2.2.1.2.2 = STRING: "GbE_2"
iso.3.6.1.2.1.2.2.1.3.1 = INTEGER: 6
iso.3.6.1.2.1.2.2.1.3.2 = INTEGER: 6
iso.3.6.1.2.1.2.2.1.4.1 = INTEGER: 1514
iso.3.6.1.2.1.2.2.1.4.2 = INTEGER: 1514
iso.3.6.1.2.1.2.2.1.5.1 = Gauge32: 10000000
iso.3.6.1.2.1.2.2.1.5.2 = Gauge32: 100000000
...

Subtree(s)

# snmpwalk  -v2c -c public 127.0.0.1 iso.3.6.1.2.1.2.2.1.1
iso.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1
iso.3.6.1.2.1.2.2.1.1.2 = INTEGER: 2

Thanks.

@rpv-tomsk
Copy link
Contributor

snmp plugin: host ubnt-rm5-abell-S-120: csnmp_instance_list_add failed.csnmp_instance_list_add failed.

That message has nothing good as it shows what csnmp_dispatch_table() call will be skipped.
In your case that is likely no problem, but in other cases that may lead to skip other, correct instances.

IMHO these cases are rare, but I also think there is two mistakes, and only one was fixed.

snmp.c is not one of simple plugins, so your help is required.

@cullorblind
Copy link
Author

Here is an AP with 0 clients: (they only respond to v1)

root@graphite-collector1:~# snmpwalk -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7
End of MIB

Here's another with 2 clients just for comparison:

root@graphite-collector1:~# snmpwalk -v1 -c public 172.16.16.253 1.3.6.1.4.1.41112.1.4.7
UBNT-MIB::ubntStaMac.1.'hrQTx.' = STRING: 68:72:51:54:78:cb
UBNT-MIB::ubntStaMac.1.'.*.0.@' = STRING: 80:2a:a8:30:b3:40
UBNT-MIB::ubntStaName.1.'hrQTx.' = STRING: MLonghofer-NBM5
UBNT-MIB::ubntStaName.1.'.*.0.@' = STRING: Chiyos-PBM5
UBNT-MIB::ubntStaSignal.1.'hrQTx.' = INTEGER: -46
UBNT-MIB::ubntStaSignal.1.'.*.0.@' = INTEGER: -60
UBNT-MIB::ubntStaNoiseFloor.1.'hrQTx.' = INTEGER: -96
UBNT-MIB::ubntStaNoiseFloor.1.'.*.0.@' = INTEGER: -96
UBNT-MIB::ubntStaDistance.1.'hrQTx.' = INTEGER: 450
UBNT-MIB::ubntStaDistance.1.'.*.0.@' = INTEGER: 4200
UBNT-MIB::ubntStaCcq.1.'hrQTx.' = INTEGER: 99
UBNT-MIB::ubntStaCcq.1.'.*.0.@' = INTEGER: 98
UBNT-MIB::ubntStaAmp.1.'hrQTx.' = INTEGER: 2
UBNT-MIB::ubntStaAmp.1.'.*.0.@' = INTEGER: 2
UBNT-MIB::ubntStaAmq.1.'hrQTx.' = INTEGER: 98
UBNT-MIB::ubntStaAmq.1.'.*.0.@' = INTEGER: 96
UBNT-MIB::ubntStaAmc.1.'hrQTx.' = INTEGER: 94
UBNT-MIB::ubntStaAmc.1.'.*.0.@' = INTEGER: 93
UBNT-MIB::ubntStaLastIp.1.'hrQTx.' = IpAddress: 208.185.189.62
UBNT-MIB::ubntStaLastIp.1.'.*.0.@' = IpAddress: 104.245.74.198
UBNT-MIB::ubntStaTxRate.1.'hrQTx.' = INTEGER: 65000000
UBNT-MIB::ubntStaTxRate.1.'.*.0.@' = INTEGER: 65000000
UBNT-MIB::ubntStaRxRate.1.'hrQTx.' = INTEGER: 65000000
UBNT-MIB::ubntStaRxRate.1.'.*.0.@' = INTEGER: 65000000
UBNT-MIB::ubntStaTxBytes.1.'hrQTx.' = Counter64: 1195606809
UBNT-MIB::ubntStaTxBytes.1.'.*.0.@' = Counter64: 50018321915
UBNT-MIB::ubntStaRxBytes.1.'hrQTx.' = Counter64: 436081987
UBNT-MIB::ubntStaRxBytes.1.'.*.0.@' = Counter64: 4617831594
UBNT-MIB::ubntStaConnTime.1.'hrQTx.' = Timeticks: (43569800) 5 days, 1:01:38.00
UBNT-MIB::ubntStaConnTime.1.'.*.0.@' = Timeticks: (43570300) 5 days, 1:01:43.00
End of MIB

@cullorblind
Copy link
Author

cullorblind commented May 31, 2017

Wondering if snmptable would be useful. It knows the difference between tables/not tables and also knows when a table is empty.

root@graphite-collector1:~# snmpwalk -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7
End of MIB
root@graphite-collector1:~# snmptable -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7
End of MIB
UBNT-MIB::ubntStaTable: No entries
root@graphite-collector1:~#
root@graphite-collector1:~# snmpwalk -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.8
End of MIB
root@graphite-collector1:~# snmptable -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.8
Was that a table? UBNT-MIB::ubntAirMAX.8

Edit: nevermind that. It only recognizes tables if the MIBs are installed. Just tested this from another box and it asks "Was that a table?" on .7 too..

@rpv-tomsk
Copy link
Contributor

Hi!
Thanks for your answers!

What about direct request of appropriate 'tables'?

I.e. table should be requested not from

1.3.6.1.4.1.41112.1.4.7   ("ubntStaTable" OID)

but from

1.3.6.1.4.1.41112.1.4.7.1.2  (ubntStaName OID/table)
1.3.6.1.4.1.41112.1.4.7.1.3  (ubntStaSignal OID/table)

Please check these commands:

snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.2
snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.3
snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.4
snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.6
snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.8
snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.9

They might be interesting because Collectd queries values / instance names from these OID(s) directly, and does not use top-level 1.3.6.1.4.1.41112.1.4.7 at all.

@cullorblind
Copy link
Author

Here's the direct requests.

root@graphite-collector1:~# snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.2
End of MIB
root@graphite-collector1:~# snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.3
End of MIB
root@graphite-collector1:~# snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.4
End of MIB
root@graphite-collector1:~# snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.6
End of MIB
root@graphite-collector1:~# snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.8
End of MIB
root@graphite-collector1:~# snmpwalk  -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.9
End of MIB

@rpv-tomsk
Copy link
Contributor

rpv-tomsk commented May 31, 2017

Ok. Thanks.

Can you please try to add some debugging to your already patched code?

--- a/src/snmp.c
+++ b/src/snmp.c
@@ -1055,8 +1055,11 @@ static int csnmp_instance_list_add(csnmp_list_instances_t **head,

   status = csnmp_oid_suffix(&il->suffix, &vb_name, &dd->instance.oid);
   if (status != 0) {
+    char oid_buffer[1024] = {0};
+    snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, vb->name, vb->name_length);
+    ERROR("snmp plugin: Unable to find value for Instance of Data `%s`. Skip OID %s of type #%i.", dd->name, oid_buffer, (int)vb->type);
     sfree(il);
-    return (status);
+    return (status);
   }

   /* Get instance name */

I think what exit from csnmp_instance_list_add happens here in this code, so adding of a message output will show new info in logs. Can you confirm?

That is my last request for today, and it does not require fast answer :-)

I will try to configure my Collectd to request some empty tables too. :-)
Thanks for your help.

@cullorblind
Copy link
Author

cullorblind commented May 31, 2017

Here's the updated log output

May 31 15:52:39 deb8test1 collectd[30761]: [2017-05-31 15:52:40] snmp plugin: Unable to find value for Instance of Data `stations`. Skip OID iso.3.6.1.4.1.41112.1.4.7.1.2.
May 31 15:52:39 deb8test1 collectd[30761]: [2017-05-31 15:52:40] snmp plugin: host ubnt-rm5-umbarger-SW-120: csnmp_instance_list_add failed.

Edit: No problem. Thanks for your work on a great plugin. And I think pulling just about any empty OID should replicate the problem.

@rpv-tomsk
Copy link
Contributor

You reply super-fast ;-)
Patch updated to add output of skipped variable type.

Can you please try it?

@cullorblind
Copy link
Author

I'm kindof procrastinating other work, and this is fairly easy to do right now. =)

May 31 16:17:28 deb8test1 collectd[32049]: [2017-05-31 16:17:28] snmp plugin: Unable to find value for Instance of Data `stations`. Skip OID iso.3.6.1.4.1.41112.1.4.7.1.2 of type #5.
May 31 16:17:28 deb8test1 collectd[32049]: [2017-05-31 16:17:28] snmp plugin: host ubnt-rm5-umbarger-SW-120: csnmp_instance_list_add failed.

@rpv-tomsk
Copy link
Contributor

rpv-tomsk commented Jun 1, 2017

Yeah!
I can reproduce this on my system (collectd-5.7 from git).

debian:/opt# ./run_fg
[2017-06-01 12:36:31] plugin_load: plugin "logfile" successfully loaded.
[2017-06-01 12:36:31] plugin_load: plugin "network" successfully loaded.
[2017-06-01 12:36:31] plugin_load: plugin "snmp" successfully loaded.
[2017-06-01 12:36:32] Initialization complete, entering read-loop.
[2017-06-01 12:36:32] snmp plugin: host officeswitch: csnmp_instance_list_add failed.
*** Error in `/opt/collectd/sbin/collectd': double free or corruption (out): 0xb3f00760 ***
./run_fg: line 1: 10365 Аварийный останов       /opt/collectd/sbin/collectd -C /opt/collectd-test.conf -P /var/run/collectd-test.pid -f

I found OIDs which reply the same result like yours

root@graphite-collector1:~# snmpwalk -v1 -c public 172.16.145.242 1.3.6.1.4.1.41112.1.4.7.1.2
End of MIB

In my case that is

# snmpwalk   -v2c -c public 192.168.0.100 iso.3.6.7.2
End of MIB

I have put these OIDs into config:

<Plugin snmp>
        <Data "std_traffic">
                Type "if_octets"
                Table true
                InstancePrefix "traffic"
                Instance "iso.3.6.7.2.1.2.2.1.1"
                Values   "iso.3.6.7.2.1.2.2.1.2" "iso.3.6.7.2.1.2.2.1.3"
        </Data>
        <Host "officeswitch">
                Address "192.168.0.100"
                Version 1
                Community "public"
                Collect "std_traffic"
        </Host>
</Plugin>

In case of collectd-5.1 which is installed on that machine, there is deadloop with this config.
The collectd-5.1 output is:

[2017-06-01 11:55:34] snmp plugin: OID "iso.3.6.7.2.1.2.2.1.1" is undefined (type ASN_NULL)
[2017-06-01 11:55:34] snmp plugin: OID "iso.3.6.7.2.1.2.2.1.1" is undefined (type ASN_NULL)
[2017-06-01 11:55:34] snmp plugin: OID "iso.3.6.7.2.1.2.2.1.1" is undefined (type ASN_NULL)
....

... and collectd is unable to terminate correctly.

The tcpdump of this:

11:55:43.145263 IP 192.168.0.1.53737 > 192.168.0.100.161:  GetNextRequest(59)  .1.3.6.7.2.1.2.2.1.2 .1.3.6.7.2.1.2.2.1.3 .1.3.6.7.2.1.2.2.1.1
11:55:43.171320 IP 192.168.0.100.161 > 192.168.0.1.53737:  GetResponse(59)  noSuchName@1 .1.3.6.7.2.1.2.2.1.2= .1.3.6.7.2.1.2.2.1.3= .1.3.6.7.2.1.2.2.1.1=
11:55:43.171450 IP 192.168.0.1.53737 > 192.168.0.100.161:  GetNextRequest(59)  .1.3.6.7.2.1.2.2.1.2 .1.3.6.7.2.1.2.2.1.3 .1.3.6.7.2.1.2.2.1.1
11:55:43.213384 IP 192.168.0.100.161 > 192.168.0.1.53737:  GetResponse(59)  noSuchName@1 .1.3.6.7.2.1.2.2.1.2= .1.3.6.7.2.1.2.2.1.3= .1.3.6.7.2.1.2.2.1.1=
11:55:43.213506 IP 192.168.0.1.53737 > 192.168.0.100.161:  GetNextRequest(59)  .1.3.6.7.2.1.2.2.1.2 .1.3.6.7.2.1.2.2.1.3 .1.3.6.7.2.1.2.2.1.1
11:55:43.255320 IP 192.168.0.100.161 > 192.168.0.1.53737:  GetResponse(59)  noSuchName@1 .1.3.6.7.2.1.2.2.1.2= .1.3.6.7.2.1.2.2.1.3= .1.3.6.7.2.1.2.2.1.1=
... indefinitely...

Collectd-5.7 dies with double free or corruption.
And patched version reports

[2017-06-01 12:53:58] snmp plugin: Unable to find value for Instance of Data `std_traffic`. Skip OID iso.3.6.7.2.1.2.2.1.1 of type #5.
[2017-06-01 12:53:58] snmp plugin: host officeswitch: csnmp_instance_list_add failed.

"Type # 5" which you see in your logs is ASN_NULL.
So, all is similar with your case, I think.
I will play with this some.

@rpv-tomsk
Copy link
Contributor

@octo, what do you think about all this?

Should we only patch double free error or need to dig deeper?

The issue which I see is: collectd does not check for res->errstat value.
In case of 'this issue' there is an error, value 2 / SNMP_ERR_NOSUCHNAME.

That means what no variable values will be in this res.

net-snmp tries to solve this by 'fixing' the PDU (removing the error-prone OID) and do retry.
https://github.com/hardaker/net-snmp/blob/a7bc508a8930a484c3a666cbea4ab226d2a3aa88/apps/snmpget.c#L192

Should collectd do the same?

rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Jun 1, 2017
snmp_sess_synch_response() always frees request PDU, in both case of request
error and success. If error condition occurs inside of `while (status == 0)`
loop, double free of `req` happens.

Issue: collectd#2291
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Jun 1, 2017
snmp_sess_synch_response() always frees request PDU, in both case of request
error and success. If error condition occurs inside of `while (status == 0)`
loop, double free of `req` happens.

Issue: collectd#2291
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Jun 1, 2017
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Jun 1, 2017
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Jun 1, 2017
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Jun 1, 2017
Collectd does not check for `res->errstat` value after
`snmp_sess_synch_response()` call. In case of error, there is no any data in
`res->variables` actually, but variables are tried to be processed as usual.
Suffix calculation will fail, so all subtrees will be marked as failed, not
only one subtree which caused an error.

The csnmp_instance_list_add() call will fail too, and, as result,
`csnmp_read_table` will finish it's work without any data submission.

The log message like
"snmp plugin: host HOSTNAME: csnmp_instance_list_add failed",
which is put into logs in this case, also has no enough diagnostic data.

Added code to proper check for `res->errstat` and to try to get available data.

Issue: collectd#2291
@rpv-tomsk
Copy link
Contributor

rpv-tomsk commented Jun 1, 2017

Hi!

Sorry for commits noise.

Let's check f3168df changes, which added the check of res->errstat value.

Before the patch:

[2017-06-01 15:22:22] snmp plugin: csnmp_read_table (host = officeswitch, data = std_traffic)
[2017-06-01 15:22:22] snmp plugin: host = officeswitch; data = std_traffic; i = 0; Value probably left its subtree.
[2017-06-01 15:22:22] snmp plugin: host = officeswitch; data = std_traffic; i = 1; Value probably left its subtree.
[2017-06-01 15:22:22] snmp plugin: host officeswitch: csnmp_instance_list_add failed.

tcpdump:

15:20:06.502813 IP 192.168.0.1.49545 > 192.168.0.100.161:  GetNextRequest(59)  .1.3.6.7.2.1.2.2.1.2 .1.3.6.7.2.1.2.2.1.3 .1.3.6.1.2.1.2.2.1.2
15:20:06.506613 IP 192.168.0.100.161 > 192.168.0.1.49545:  GetResponse(59)  noSuchName@1 .1.3.6.7.2.1.2.2.1.2= .1.3.6.7.2.1.2.2.1.3= .1.3.6.1.2.1.2.2.1.2=

Collectd stops after first response failed.

After patch:

[2017-06-01 15:50:16] snmp plugin: csnmp_read_table (host = officeswitch, data = std_traffic)
[2017-06-01 15:50:16] snmp plugin: host officeswitch; data std_traffic: OID `SNMPv2-SMI::dod.7.2.1.2.2.1.2` failed: (noSuchName) There is no such variable name in this MIB.
[2017-06-01 15:50:16] snmp plugin: host officeswitch; data std_traffic: OID `SNMPv2-SMI::dod.7.2.1.2.2.1.3` failed: (noSuchName) There is no such variable name in this MIB.
[2017-06-01 15:50:16] snmp plugin: il->instance = `GbE_1';
[2017-06-01 15:50:16] snmp plugin: il->instance = `GbE_2';

tcpdump:

15:50:06.001028 IP 192.168.0.1.34381 > 192.168.0.100.161:  GetNextRequest(59)  .1.3.6.7.2.1.2.2.1.2 .1.3.6.7.2.1.2.2.1.3 .1.3.6.1.2.1.2.2.1.2
15:50:06.004803 IP 192.168.0.100.161 > 192.168.0.1.34381:  GetResponse(59)  noSuchName@1 .1.3.6.7.2.1.2.2.1.2= .1.3.6.7.2.1.2.2.1.3= .1.3.6.1.2.1.2.2.1.2=
15:50:06.004897 IP 192.168.0.1.34381 > 192.168.0.100.161:  GetNextRequest(44)  .1.3.6.7.2.1.2.2.1.3 .1.3.6.1.2.1.2.2.1.2
15:50:06.008586 IP 192.168.0.100.161 > 192.168.0.1.34381:  GetResponse(44)  noSuchName@1 .1.3.6.7.2.1.2.2.1.3= .1.3.6.1.2.1.2.2.1.2=
15:50:06.008647 IP 192.168.0.1.34381 > 192.168.0.100.161:  GetNextRequest(29)  .1.3.6.1.2.1.2.2.1.2
15:50:06.017821 IP 192.168.0.100.161 > 192.168.0.1.34381:  GetResponse(37)  .1.3.6.1.2.1.2.2.1.2.1="GbE_1"
15:50:06.017880 IP 192.168.0.1.34381 > 192.168.0.100.161:  GetNextRequest(30)  .1.3.6.1.2.1.2.2.1.2.1
15:50:06.062414 IP 192.168.0.100.161 > 192.168.0.1.34381:  GetResponse(37)  .1.3.6.1.2.1.2.2.1.2.2="GbE_2"

As we see, Collectd handles an exception and re-request the rest of data available.

But it appears what rest of data will be useless in most of cases - datatype will not be submitted with any 'column' completely missing. At other hand, we can show error message about wrong OID / missing data and stop query of rest of data too, like it happens before this patch.

What do you think?

@octo
Copy link
Member

octo commented Sep 25, 2017

Oh boy. Looking at the sources of snmp_sess_synch_response()

The first block in snmp_sess_synch_response() is:

    ss = snmp_sess_session(sessp);
    if (ss == NULL) {
        return STAT_ERROR;
    }

So clearly pdu can be allocated when STAT_ERROR is returned. What follows is initialization of local variables and some writes to the session object ss. None of this touches pdu (unless some really, really evil preprocessor magic at play here).

Then we come to this block:

    if (snmp_sess_send(sessp, pdu) == 0) {
        snmp_free_pdu(pdu);
        state->status = STAT_ERROR;
    } else {
        state->waiting = 1;
        state->reqid = pdu->reqid;
    }

So one of two things happens:

  1. snmp_sess_send() returns zero, in which case pdu is freed, but state->status is set to STAT_ERROR (which is later used as return value). The rest of the function does not set state->status to zero.
  2. snmp_sess_send() returns non-zero, in which case pdu is dereferenced, so it should still be valid. The rest of the function does not touch (neither read nor write) pdu, let alone free it.

snmp_sess_send() is a complex beast (with callback functions passed as part of sessp) but clearly it cannot free pdu: either it is passed to snmp_free_pdu() or dereferenced after the call, which we would see in the stack trace.

I'm very sad to say that I cannot explain that stacktrace. I didn't find a bug report nor a commit which seems to have fixed this, though I don't have access to git blame right now, so maybe I missed something.

Best regards,
—octo

@rpv-tomsk
Copy link
Contributor

rpv-tomsk commented Sep 25, 2017

The snmp_sess_send() has exact documentation (https://sourceforge.net/p/net-snmp/code/ci/master/tree/snmplib/snmp_api.c#l5146):

/*
 * These functions send PDUs using an active session:
...
 * snmp_sess_send        - single session API, no callback
...
 * Send the pdu to the target identified by this session.
 * Return on success:
 *   The request id of the pdu is returned, and the pdu is freed.
 * Return on failure:
 *   Zero (0) is returned.
 *   The caller must call snmp_free_pdu if 0 is returned.
 */

So, there is no problems with pdu memory.

    if ((state->reqid = snmp_sess_send(sessp, pdu)) == 0) {
        snmp_free_pdu(pdu);
        state->status = STAT_ERROR;
    } 

This piece of snmp_sess_synch_response() code (plus snmp_sess_send() documentation) shows what this function built with goal to free pdu (request) memory in all possible cases.

rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Sep 26, 2017
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Sep 26, 2017
rpv-tomsk added a commit to rpv-tomsk/collectd that referenced this issue Sep 26, 2017
Collectd does not check for `res->errstat` value after
`snmp_sess_synch_response()` call. In case of error, there is no any data in
`res->variables` actually, but variables are tried to be processed as usual.
Suffix calculation will fail, so all subtrees will be marked as failed, not
only one subtree which caused an error.

The csnmp_instance_list_add() call will fail too, and, as result,
`csnmp_read_table` will finish it's work without any data submission.

The log message like
"snmp plugin: host HOSTNAME: csnmp_instance_list_add failed",
which is put into logs in this case, also has no enough diagnostic data.

Added code to proper check for `res->errstat` and to try to get available data.

Issue: collectd#2291
octo pushed a commit that referenced this issue Sep 27, 2017
snmp_sess_synch_response() always frees request PDU, in both case of request
error and success. If error condition occurs inside of `while (status == 0)`
loop, double free of `req` happens.

Issue: #2291
Signed-off-by: Florian Forster <octo@collectd.org>
octo pushed a commit that referenced this issue Sep 27, 2017
Issue: #2291
Signed-off-by: Florian Forster <octo@collectd.org>
@octo
Copy link
Member

octo commented Oct 20, 2017

This has been fixed.

@octo octo closed this as completed Oct 20, 2017
@carnil
Copy link

carnil commented Nov 14, 2017

This issue has been assigned CVE-2017-16820

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants