The FreeBSD SNMP helper cyg_snmp_get_if() exhibits a bug when passed if_num<=0: it loops 2^32 times -- walking through all of memory and then returning a rogue pointer.
This can be demonstrated by sending an eCos-based device an SMP "get" request for OID 1.3.6.1.2.1.2.2.1.6.0. Typical behavior is that the device will lock up for several seconds ans the SNMP management thread loops through all of memory. The problem didn't exist in the helper routine for the NetBSD. The attached patch fixes the problem.
Index: agent/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos-opt/snmp/agent/current/ChangeLog,v retrieving revision 1.29 diff -U8 -r1.29 ChangeLog --- agent/current/ChangeLog 29 Jan 2009 17:49:59 -0000 1.29 +++ agent/current/ChangeLog 11 May 2009 15:46:59 -0000 @@ -1,8 +1,20 @@ +2009-05-11 Grant Edwards <[email protected]> + + * src/mibgroup/mibII/helpers (cyg_snmp_get_if) Rewrite it so that + when passed if_num<=0 it will no longer go into a 2^32 iteration + loop that walks through all of memory and then returns a rogue + pointer + + * src/mibgroup/mibII/helpers.c (cyg_snmp_num_interfaces): Rewrite + it to to use the same (simpler, more obviously correct) loop + structure that cyg_snmp_get_if() now uses. + + 2004-05-14 Matt Jerdonek <[email protected]> * src/mibgroup/mibII/helpers.c (cyg_snmp_num_interfaces): return correct number of interfaces including the loopback interface. * src/mibgroup/mibII/helpers (cyg_snmp_get_if) increment the interface index properly. * src/mibgroup/mibII/interfaces.c (var_ifTable): Add case for IFT_PPP interface type. Index: agent/current/src/mibgroup/mibII/helpers.c =================================================================== RCS file: /cvs/ecos/ecos-opt/snmp/agent/current/src/mibgroup/mibII/helpers.c,v retrieving revision 1.4 diff -U8 -r1.4 helpers.c --- agent/current/src/mibgroup/mibII/helpers.c 29 Jan 2009 17:50:00 -0000 1.4 +++ agent/current/src/mibgroup/mibII/helpers.c 11 May 2009 15:46:59 -0000 @@ -57,43 +57,34 @@ #include <net/if_types.h> /* How many interfaces are there? */ #ifdef CYGPKG_NET_FREEBSD_STACK extern struct ifaddr **ifnet_addrs; long cyg_snmp_num_interfaces(void) { - long long_ret=0; - int cnt = if_index - 1; - - while (cnt >= 0) { - if (ifnet_addrs[cnt] != 0) { - long_ret++; - } - cnt--; - } - return long_ret; + int i,n=0; + + for (i=0; i<if_index; ++i) + if (ifnet_addrs[i]) + ++n; + + return n; } struct ifnet *cyg_snmp_get_if(int if_num) { - int index = 0; - struct ifnet *ifp; - - do { - while(0 == ifnet_addrs[index]) - index++; - - ifp = ifnet_addrs[index]->ifa_ifp; - - if_num--; - index++; - } while (if_num); + int i,n=0; - return ifp; + for (i=0; i<if_index; ++i) + if (ifnet_addrs[i]) + if (++n == if_num) + return ifnet_addrs[i]->ifa_ifp; + + return NULL; } #endif #ifdef CYGPKG_NET_OPENBSD_STACK long cyg_snmp_num_interfaces(void) { register struct ifnet *ifp; long long_ret = 0;
