[prev in list] [next in list] [prev in thread] [next in thread] 

List:       net-snmp-bugs
Subject:    [ net-snmp-Bugs-3562119 ] segfault in snmpd 5.6.1.1, file at.c on HPUX 11i
From:       SourceForge.net <noreply () sourceforge ! net>
Date:       2012-08-28 8:50:23
Message-ID: E1T6HVC-0007iB-Vu () sfs-ml-3 ! v29 ! ch3 ! sourceforge ! com
[Download RAW message or body]

Bugs item #3562119, was opened at 2012-08-27 05:37
Message generated for change (Comment added) made by villettejp
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=112694&aid=3562119&group_id=12694

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: agent
Group: hpux
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: Jean-Paul VILLETTE (villettejp)
Assigned to: Niels Baggesen (nba)
Summary: segfault in snmpd 5.6.1.1, file at.c on HPUX 11i

Initial Comment:
file : /agent/mibgroup/mibII/at.c

cause : segfault in at.c in line 754 (HPUX specific lines):

   748  #elif defined(hpux11)
   749      if (arptab_current < arptab_size) {
   750          /*
   751           * copy values
   752           */
   753          *IPAddr = at[arptab_current].NetAddr;
   754          memcpy(PhysAddr, at[arptab_current].PhysAddr.o_bytes,
   755                 at[arptab_current].PhysAddr.o_length);
   756          *ifType = at[arptab_current].Type;
   757          *ifIndex = at[arptab_current].IfIndex;
   758          *PhysAddrLen = at[arptab_current].PhysAddr.o_length;

This memcpy segfaults for the two usual reasons : 
- wrong address
- and more often wrong length

The at field is used by these lines (HPUX specific lines):

   546      if (at)
   547          free(at);
   548      at = (mib_ipNetToMediaEnt *) 0;
   549      arptab_size = 0;
   550
   551      if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
   552          p.objid = ID_ipNetToMediaTableNum;
   553          p.buffer = (void *) &val;
   554          ulen = sizeof(int);
   555          p.len = &ulen;
   556          if ((ret = get_mib_info(fd, &p)) == 0)
   557              arptab_size = val;
   558  
   559          if (arptab_size > 0) {
   560              ulen = (unsigned) arptab_size *sizeof(mib_ipNetToMediaEnt);
   561              at = (mib_ipNetToMediaEnt *) malloc(ulen);
   562              p.objid = ID_ipNetToMediaTable;
   563              p.buffer = (void *) at;
   564              p.len = &ulen;
   565              if ((ret = get_mib_info(fd, &p)) < 0)
   566                  arptab_size = 0;
   567          }
   568  
   569          close_mib(fd);
   570      }

I solved this by these lines (HPUX specific lines):

*** 559,569 ****
--- 559,572 ----
          if (arptab_size > 0) {
              ulen = (unsigned) arptab_size *sizeof(mib_ipNetToMediaEnt);
              at = (mib_ipNetToMediaEnt *) malloc(ulen);
+             memset(at, 0, ulen);
              p.objid = ID_ipNetToMediaTable;
              p.buffer = (void *) at;
              p.len = &ulen;
              if ((ret = get_mib_info(fd, &p)) < 0)
                  arptab_size = 0;
+             else
+                 arptab_size = *p.len / sizeof(mib_ipNetToMediaEnt);
          }

The problem comes from the use of the API get_mib_info() (at least not well
documented). The first use of this API is done to get the number of ARP entries
and the second one is done to obtain the entries. But, when a machine is very
active, the number of entries between the two calls may decrease. In this case
when the second call works on a ARP entries list shorter than the first call 
did, the API get_mib_info() only works on the memory corresponding to the 
second number of entries (the shortest one), making the rest of the buffer
unused.

it's the use of this unused so unset portion of the memory which make 
the memcpy() to segfault.

i make two modifications :
- zeroed this segment of memory to be sure to pass the correct values to
memcpy or at least zeros.
- recompute the real length of the list of arp entries.

---------------

You can illustrate the get_mib_info()'s behavior by this simple test. First,
ping your broadcast address to make all your subnet's neighbors reply. 
This action should increase the size of your ARP table.
The following lines are the source code of the tool i used to duplicate this
problem. For a large part, it a copy of the snmpd code. I just added a sleep()
to increase artificially the time between the two get_mib_info(), and a 
conditionnal printf() to see the ARP entries when the numbers of items are 
differenti (so to print the ARP entries when the problem occurs). 

#include <stdio.h>
#include <sys/fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mib.h>
#include <netinet/mib_kern.h>

int main(int argc, char **argv)
{
    int             fd;
    struct nmparms  p;
    int             val;
    unsigned int    ulen;
    int             ret;
    static mib_ipNetToMediaEnt *at = (mib_ipNetToMediaEnt *) 0;
    int arptab_size = 0;
    int arptab_current = 0;

    if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
        p.objid = ID_ipNetToMediaTableNum;
        p.buffer = (void *) &val;
        ulen = sizeof(int);
        p.len = &ulen;
        if ((ret = get_mib_info(fd, &p)) == 0)
            arptab_size = val;

        sleep( 2 );

        if (arptab_size > 0) {
           ulen = (unsigned) arptab_size *sizeof(mib_ipNetToMediaEnt);
            at = (mib_ipNetToMediaEnt *) malloc(ulen);
            /* memset(at, 0, ulen); */
            p.objid = ID_ipNetToMediaTable;
            p.buffer = (void *) at;
            p.len = &ulen;
            if ((ret = get_mib_info(fd, &p)) < 0)
                arptab_size = 0;
            /* else
                arptab_size = *p.len / sizeof(mib_ipNetToMediaEnt); */
        }


        for(arptab_current=0;arptab_current<arptab_size;arptab_current++) {
          if (arptab_size != (*p.len / sizeof(mib_ipNetToMediaEnt))) {
              printf("(%u,%u)  ", arptab_current+1, arptab_size);
              printf("%d  ", at[arptab_current].PhysAddr.o_length);
              printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
                     at[arptab_current].PhysAddr.o_bytes[0],
                     at[arptab_current].PhysAddr.o_bytes[1],
                     at[arptab_current].PhysAddr.o_bytes[2],
                     at[arptab_current].PhysAddr.o_bytes[3],
                     at[arptab_current].PhysAddr.o_bytes[4],
                     at[arptab_current].PhysAddr.o_bytes[5]);
           }
         }

    close_mib(fd);
    }

}

The effects may be, when the ARP decreases :
-	wrong last entries,
-	in rare cases, segfaults.

For example, i just did the test. After several minutes, the number of items
decreased from 314 to 245. Here is the result you can see as output from the
tool :

bash-3.00# while true; do ./mygetmib | tee logs ; done 
(247,318)  6  00:0f:20:2b:55:23
(248,318)  6  00:1a:4b:06:66:7a
(249,318)  6  01:00:5e:00:00:00
(250,318)  3755991007  df:df:df:df:df:df
(251,318)  3755991007  df:df:df:df:df:df
(252,318)  3755991007  df:df:df:df:df:df
(253,318)  3755991007  df:df:df:df:df:df
(254,318)  3  00:00:00:05:6c:61
(255,318)  0  00:00:00:00:00:00
(256,318)  0  00:00:00:00:00:00
.....

The columns are :
1/ just the index in the list,
2/ the number of items returned by the first call of get_mib_info(),
3/ the size of the arp entry (also the size used for the memcpy()),
4/ the current arp entry

This time, for example, the length would have been the origin of a segfault.

To check the number of ARP entries at the same time, you can use the 
following command :

bash-3.00# while true ; do arp -an | wc -l; sleep 5; done                
309
311
311
311
313
314
314
314
314
314
245

NOTA : the number of entries differs between the two commands (between the tool
and the arp -an) because both tests are not done at the exact same time.

----------------------------------------------------------------------

>Comment By: Jean-Paul VILLETTE (villettejp)
Date: 2012-08-28 01:50

Message:
I added the memset() line to be sure the memcpy() works. The memcpy()
accepts the length set to zero by doing ... nothing.

I am still concerned by a strange behavior of the API get_mib_info() :
sometimes, the p.len returned by the second get_mib_info() is not a
multiple of sizeof(mib_ipNetToMediaEnt) which make the arptab_size to be
round up. That's why the line memcpy() stays even it should be not
necessary.

I am not yet successfull reproducing this behavior (and i don't know if i
will)  but it seems related with "unsucessfull resolutions" visible in "arp
-an" with lines marked as "no entry" :

#arp -an
....
 (150.130.22.232) at 0:d:29:84:31:cf ether
10.15.17.102 (10.15.17.102) -- no entry
 (150.130.22.234) at 0:d:29:cc:1a:b0 ether
10.15.16.102 (10.15.16.102) -- no entry
 (150.130.22.227) at 0:d:29:4b:f8:5c ether
....



----------------------------------------------------------------------

Comment By: Magnus Fromreide (magfr)
Date: 2012-08-27 14:32

Message:
I just wanted to chime in and say that I love this bug report. Thanks for
doing such detailed work.

----------------------------------------------------------------------

Comment By: Niels Baggesen (nba)
Date: 2012-08-27 12:05

Message:
Yes, that certainly looks like a bug, not to check the actual amount of
data returned. The call to memset on the other hand should not make any
difference.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=112694&aid=3562119&group_id=12694

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Net-snmp-bugs mailing list
Net-snmp-bugs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/net-snmp-bugs
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic