Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > c0394d3068b44395994f031447c8052d > files > 40

net-snmp-5.3.2.2-7.el5_4.2.src.rpm

394591: [4.7] snmpd crashes at OS reboot
429671: snmpd exits with buffer overlow after stress

Source: upstream, http://sourceforge.net/tracker/index.php?func=detail&aid=1678788&group_id=12694&atid=312694
Modified-By: Jan Safranek <jsafrane@redhat.com>
(smux_snmp_process: length is now ssize_t, to be able to check errors from 
recv(), adapted to RHEL5)

diff -up net-snmp-5.3.2.2/agent/mibgroup/smux/smux.c.smux-select net-snmp-5.3.2.2/agent/mibgroup/smux/smux.c
--- net-snmp-5.3.2.2/agent/mibgroup/smux/smux.c.smux-select	2007-10-16 09:17:51.000000000 +0200
+++ net-snmp-5.3.2.2/agent/mibgroup/smux/smux.c	2008-07-10 17:39:09.000000000 +0200
@@ -350,7 +350,7 @@ var_smux_write(int action,
     u_char          buf[SMUXMAXPKTSIZE], *ptr, sout[3], type;
     int             reterr;
     size_t          var_len, datalen, name_length, packet_len;
-    ssize_t         len;
+    ssize_t         len, tmp_len;
     long            reqid, errsts, erridx;
     u_char          var_type, *dataptr;
 
@@ -426,12 +426,17 @@ var_smux_write(int action,
              */
             if ((len = recv(rptr->sr_fd, buf,
                             SMUXMAXPKTSIZE, MSG_PEEK)) <= 0) {
+                if ((len == -1) && ((errno == EINTR) || (errno == EAGAIN)))
+                {
+                   continue;
+                }
                 DEBUGMSGTL(("smux",
                             "[var_smux_write] peek failed or timed out\n"));
                 /*
                  * do we need to do a peer cleanup in this case?? 
                  */
                 smux_peer_cleanup(rptr->sr_fd);
+                smux_snmp_select_list_del(rptr->sr_fd);
                 return SNMP_ERR_GENERR;
             }
 
@@ -455,13 +460,19 @@ var_smux_write(int action,
             /*
              * receive the first packet 
              */
-            if ((len = recv(rptr->sr_fd, buf, len, 0)) <= 0) {
+            tmp_len = len;
+            do
+            {
+               len = tmp_len;
+               len = recv(rptr->sr_fd, buf, len, 0);
+            }
+            while((len == -1) && ((errno == EINTR) || (errno == EAGAIN)));
+
+            if (len <= 0) {
                 DEBUGMSGTL(("smux",
                             "[var_smux_write] recv failed or timed out\n"));
-                /*
-                 * do we need to do a peer cleanup in this case?? 
-                 */
                 smux_peer_cleanup(rptr->sr_fd);
+                smux_snmp_select_list_del(rptr->sr_fd);
                 return SNMP_ERR_GENERR;
             }
 
@@ -593,7 +604,13 @@ smux_accept(int sd)
         /*
          * now block for an OpenPDU 
          */
-        if ((length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0)) <= 0) {
+        do
+        {
+           length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0);
+        }
+        while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
+
+        if (length <= 0) {
             DEBUGMSGTL(("smux",
                         "[smux_accept] peer on fd %d died or timed out\n",
                         fd));
@@ -660,10 +677,45 @@ smux_accept(int sd)
 int
 smux_process(int fd)
 {
-    int             length;
+    int             length, tmp_length;
     u_char          data[SMUXMAXPKTSIZE];
+    u_char          type, *ptr;
+    size_t          packet_len;
+
+    do
+    {
+       length = recv(fd, (char *) data, SMUXMAXPKTSIZE, MSG_PEEK);
+    }
+    while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
+
+    if (length <= 0)
+    {
+       snmp_log_perror("[smux_process] peek failed");
+       smux_peer_cleanup(fd);
+       return -1;
+    }
+
+    /*
+     * determine if we received more than one packet 
+     */
+    packet_len = length;
+    ptr = asn_parse_header(data, &packet_len, &type);
+    packet_len += (ptr - data);
+    if (length > packet_len) {
+        /*
+         * set length to receive only the first packet 
+         */
+        length = packet_len;
+    }
+
+    tmp_length = length;
+    do
+    {
+       length = tmp_length;
+       length = recv(fd, (char *) data, length, 0);
+    }
+    while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
 
-    length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0);
     if (length <= 0) {
         /*
          * the peer went away, close this descriptor 
@@ -729,7 +781,16 @@ smux_pdu_process(int fd, u_char * data, 
             break;
         case SMUX_TRAP:
             snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", fd);
-            ptr = smux_trap_process(ptr, &len);
+            if (ptr != 0)
+            {
+               DEBUGMSGTL(("smux", "[smux_pdu_process] call smux_trap_process.\n"));
+               ptr = smux_trap_process(ptr, &len);
+            }
+            else
+            {
+               DEBUGMSGTL(("smux", "[smux_pdu_process] smux_trap_process not called: ptr=NULL.\n"));
+               DEBUGMSGTL(("smux", "[smux_pdu_process] Error: \n%s\n", snmp_api_errstring(0)));
+            }
             /*
              * watch out for close on top of this...should return correct end 
              */
@@ -1266,7 +1327,8 @@ smux_snmp_process(int exact,
                   size_t * return_len, u_char * return_type, int sd)
 {
     u_char          packet[SMUXMAXPKTSIZE], *ptr, result[SMUXMAXPKTSIZE];
-    int             length = SMUXMAXPKTSIZE;
+    ssize_t          length = SMUXMAXPKTSIZE;
+    int             tmp_length;
     u_char          type;
     size_t          packet_len;
 
@@ -1302,10 +1364,18 @@ smux_snmp_process(int exact,
          * peek at what's received 
          */
         length = recv(sd, (char *) result, SMUXMAXPKTSIZE, MSG_PEEK);
-        if (length < 0) {
-            snmp_log_perror("[smux_snmp_process] peek failed");
-            smux_peer_cleanup(sd);
-            return NULL;
+        if (length <= 0) {
+            if ((length == -1) && ((errno == EINTR) || (errno == EAGAIN)))
+            {
+               continue;
+            }
+            else
+            {
+               snmp_log_perror("[smux_snmp_process] peek failed");
+               smux_peer_cleanup(sd);
+               smux_snmp_select_list_del(sd);
+               return NULL;
+            }
         }
 
         DEBUGMSGTL(("smux", "[smux_snmp_process] Peeked at %d bytes\n",
@@ -1328,11 +1398,19 @@ smux_snmp_process(int exact,
         /*
          * receive the first packet 
          */
-        length = recv(sd, (char *) result, length, 0);
-        if (length < 0) {
-            snmp_log_perror("[smux_snmp_process] recv failed");
-            smux_peer_cleanup(sd);
-            return NULL;
+        tmp_length = length;
+        do
+        {
+           length = tmp_length;
+           length = recv(sd, (char *) result, length, 0);
+        }
+        while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
+
+        if (length <= 0) {
+           snmp_log_perror("[smux_snmp_process] recv failed");
+           smux_peer_cleanup(sd);
+           smux_snmp_select_list_del(sd);
+           return NULL;
         }
 
         DEBUGMSGTL(("smux", "[smux_snmp_process] Received %d bytes\n",
@@ -1950,3 +2028,50 @@ smux_trap_process(u_char * rsp, size_t *
 
 }
 
+#define NUM_SOCKETS	32
+static int      sdlist[NUM_SOCKETS], sdlen = 0;
+
+int smux_snmp_select_list_add(int sd)
+{
+   if (sdlen < NUM_SOCKETS)
+   {
+      sdlist[sdlen++] = sd;
+      return(1);
+   }
+   return(0);
+}
+
+int smux_snmp_select_list_del(int sd)
+{
+   int i, found=0;
+
+   for (i = 0; i < (sdlen); i++) {
+      if (sdlist[i] == sd)
+      {
+         sdlist[i] = 0;
+         found = 1;
+      }
+      if ((found) &&(i < (sdlen - 1)))
+         sdlist[i] = sdlist[i + 1];
+   }
+   if (found)
+   {
+      sdlen--;
+      return(1);
+   }
+   return(0);
+}
+
+int smux_snmp_select_list_get_length()
+{
+   return(sdlen);
+}
+
+int smux_snmp_select_list_get_SD_from_List(int pos)
+{
+   if (pos < NUM_SOCKETS)
+   {
+      return(sdlist[pos]);
+   }
+   return(0);
+}
diff -up net-snmp-5.3.2.2/agent/mibgroup/smux/smux.h.smux-select net-snmp-5.3.2.2/agent/mibgroup/smux/smux.h
--- net-snmp-5.3.2.2/agent/mibgroup/smux/smux.h.smux-select	2005-02-25 22:47:25.000000000 +0100
+++ net-snmp-5.3.2.2/agent/mibgroup/smux/smux.h	2008-07-10 17:35:55.000000000 +0200
@@ -67,3 +67,16 @@ extern void     smux_parse_peer_auth(con
 extern void     smux_free_peer_auth(void);
 extern void     send_enterprise_trap_vars(int, int, oid *, int,
                                           netsnmp_variable_list *);
+
+/* Add socket-fd to list */
+int smux_snmp_select_list_add(int sd);
+
+/* Remove socket-fd from list */
+int smux_snmp_select_list_del(int sd);
+
+/* Returns the count of added socket-fd's in the list */
+int smux_snmp_select_list_get_length();
+
+/* Returns the socket-fd number from the position of the list */
+int smux_snmp_select_list_get_SD_from_List(int pos);
+
diff -up net-snmp-5.3.2.2/agent/snmpd.c.smux-select net-snmp-5.3.2.2/agent/snmpd.c
--- net-snmp-5.3.2.2/agent/snmpd.c.smux-select	2007-05-17 15:53:50.000000000 +0200
+++ net-snmp-5.3.2.2/agent/snmpd.c	2008-07-10 17:35:55.000000000 +0200
@@ -197,12 +197,9 @@ extern char   **argvrestartp;
 extern char    *argvrestart;
 extern char    *argvrestartname;
 
-#define NUM_SOCKETS	32
-
 #ifdef USING_SMUX_MODULE
 #include <mibgroup/smux/smux.h>
-static int      sdlist[NUM_SOCKETS], sdlen = 0;
-#endif                          /* USING_SMUX_MODULE */
+#endif /* USING_SMUX_MODULE */
 
 /*
  * Prototypes.
@@ -1111,9 +1108,14 @@ receive(void)
             FD_SET(smux_listen_sd, &readfds);
             numfds =
                 smux_listen_sd >= numfds ? smux_listen_sd + 1 : numfds;
-            for (i = 0; i < sdlen; i++) {
-                FD_SET(sdlist[i], &readfds);
-                numfds = sdlist[i] >= numfds ? sdlist[i] + 1 : numfds;
+
+            for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
+                sd = smux_snmp_select_list_get_SD_from_List(i);
+                if (sd != 0)
+                {
+                   FD_SET(sd, &readfds);
+                   numfds = sd >= numfds ? sd + 1 : numfds;
+                }
             }
         }
 #endif                          /* USING_SMUX_MODULE */
@@ -1135,13 +1137,11 @@ receive(void)
              * handle the SMUX sd's 
              */
             if (smux_listen_sd >= 0) {
-                for (i = 0; i < sdlen; i++) {
-                    if (FD_ISSET(sdlist[i], &readfds)) {
-                        if (smux_process(sdlist[i]) < 0) {
-                            for (; i < (sdlen - 1); i++) {
-                                sdlist[i] = sdlist[i + 1];
-                            }
-                            sdlen--;
+                for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
+                    sd = smux_snmp_select_list_get_SD_from_List(i);
+                    if (FD_ISSET(sd, &readfds)) {
+                        if (smux_process(sd) < 0) {
+                            smux_snmp_select_list_del(sd);
                         }
                     }
                 }
@@ -1150,10 +1150,11 @@ receive(void)
                  */
                 if (FD_ISSET(smux_listen_sd, &readfds)) {
                     if ((sd = smux_accept(smux_listen_sd)) >= 0) {
-                        sdlist[sdlen++] = sd;
+                        smux_snmp_select_list_add(sd);
                     }
                 }
             }
+
 #endif                          /* USING_SMUX_MODULE */
             netsnmp_dispatch_external_events(&count, &readfds,
                                            &writefds, &exceptfds);