GNU glibc Information for VU#844360

Domain Name System (DNS) stub resolver libraries vulnerable to buffer overflows via network name or address lookups

Status

Affected

Vendor Statement

Version 2.3.1 of the GNU C Library is vulnerable. Earlier versions are also vulnerable. The following patch has been installed into the CVS sources, and should appear in the next version of the GNU C Library. This patch is also available from the following URL:

<http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/resolv/nss_dns/dns-network.c.diff?r1=1.17&r2=1.15&cvsroot=glibc>

2002-11-18  Roland McGrath  <roland@redhat.com>

        * resolv/nss_dns/dns-network.c (getanswer_r): In BYNAME case, search
        all aliases for one that matches the "<dotted-quad>.IN-ADDR.ARPA" form.
        Do the parsing inline instead of copying strings and calling
        inet_network, and properly skip all alias names not matching the form.

2002-11-14  Paul Eggert  <eggert@twinsun.com>

        * resolv/nss_dns/dns-network.c (getanswer_r): Check for buffer
        overflow when skipping the question part and when unpacking aliases.

===================================================================
RCS file: /cvs/glibc/libc/resolv/nss_dns/dns-network.c,v
retrieving revision 1.15
retrieving revision 1.17
diff -u -r1.15 -r1.17
--- libc/resolv/nss_dns/dns-network.c   2002/10/17 21:49:12     1.15
+++ libc/resolv/nss_dns/dns-network.c   2002/11/19 06:40:16     1.17
@@ -283,7 +283,15 @@

   /* Skip the question part.  */
   while (question_count-- > 0)
-    cp += __dn_skipname (cp, end_of_message) + QFIXEDSZ;
+    {
+      int n = __dn_skipname (cp, end_of_message);
+      if (n < 0 || end_of_message - (cp + n) < QFIXEDSZ)
+       {
+         __set_h_errno (NO_RECOVERY);
+         return NSS_STATUS_UNAVAIL;
+       }
+      cp += n + QFIXEDSZ;
+    }

   alias_pointer = result->n_aliases = &net_data->aliases[0];
   *alias_pointer = NULL;
@@ -344,64 +352,94 @@
              return NSS_STATUS_UNAVAIL;
            }
          cp += n;
-         *alias_pointer++ = bp;
-         n = strlen (bp) + 1;
-         bp += n;
-         linebuflen -= n;
-         result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
-         ++have_answer;
+         if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES])
+           {
+             *alias_pointer++ = bp;
+             n = strlen (bp) + 1;
+             bp += n;
+             linebuflen -= n;
+             result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
+             ++have_answer;
+           }
        }
     }

   if (have_answer)
     {
-      char *tmp;
-      int len;
-      char *in, *cp, *rp, *wp;
-      int cnt, first_flag;
-
       *alias_pointer = NULL;
       switch (net_i)
        {
        case BYADDR:
-         result->n_name = result->n_aliases[0];
+         result->n_name = *result->n_aliases++;
          result->n_net = 0L;
-         break;
-       case BYNAME:
-         len = strlen (result->n_aliases[0]);
-         tmp = (char *) alloca (len + 1);
-         tmp[len] = 0;
-         wp = &tmp[len - 1];
-
-         rp = in = result->n_aliases[0];
-         result->n_name = ans;
-
-         first_flag = 1;
-         for (cnt = 0; cnt < 4; ++cnt)
-           {
-             char *startp;
+         return NSS_STATUS_SUCCESS;

-             startp = rp;
-             while (*rp != '.')
-               ++rp;
-             if (rp - startp > 1 || *startp != '0' || !first_flag)
-               {
-                 first_flag = 0;
-                 if (cnt > 0)
-                   *wp-- = '.';
-                 cp = rp;
-                 while (cp > startp)
-                   *wp-- = *--cp;
-               }
-             in = rp + 1;
-           }
-
-         result->n_net = inet_network (wp);
+       case BYNAME:
+         {
+           char **ap = result->n_aliases++;
+           while (*ap != NULL)
+             {
+               /* Check each alias name for being of the forms:
+                  4.3.2.1.in-addr.arpa         = net 1.2.3.4
+                  3.2.1.in-addr.arpa           = net 0.1.2.3
+                  2.1.in-addr.arpa             = net 0.0.1.2
+                  1.in-addr.arpa               = net 0.0.0.1
+               */
+               uint32_t val = 0;       /* Accumulator for n_net value.  */
+               unsigned int shift = 0; /* Which part we are parsing now.  */
+               const char *p = *ap; /* Consuming the string.  */
+               do
+                 {
+                   /* Match the leading 0 or 0[xX] base indicator.  */
+                   unsigned int base = 10;
+                   if (*p == '0' && p[1] != '.')
+                     {
+                       base = 8;
+                       ++p;
+                       if (*p == 'x' || *p == 'X')
+                         {
+                           base = 16;
+                           ++p;
+                           if (*p == '.')
+                             break; /* No digit here.  Give up on alias.  */
+                         }
+                       if (*p == '\0')
+                         break;
+                     }
+
+                   uint32_t part = 0; /* Accumulates this part's number.  */
+                   do
+                     {
+                       if (isdigit (*p) && (*p - '0' < base))
+                         part = (part * base) + (*p - '0');
+                       else if (base == 16 && isxdigit (*p))
+                         part = (part << 4) + 10 + (tolower (*p) - 'a');
+                       ++p;
+                     } while (*p != '\0' && *p != '.');
+
+                   if (*p != '.')
+                     break;    /* Bad form.  Give up on this name.  */
+
+                   /* Install this as the next more significant byte.  */
+                   val |= part << shift;
+                   shift += 8;
+                   ++p;
+
+                   /* If we are out of digits now, there are two cases:
+                      1. We are done with digits and now see "in-addr.arpa".
+                      2. This is not the droid we are looking for.  */
+                   if (!isdigit (*p) && !strcasecmp (p, "in-addr.arpa"))
+                     {
+                       result->n_net = val;
+                       return NSS_STATUS_SUCCESS;
+                     }
+
+                   /* Keep going when we have seen fewer than 4 parts.  */
+                 } while (shift < 32);
+             }
+         }
          break;
        }
-
-      ++result->n_aliases;
-      return NSS_STATUS_SUCCESS;
     }

   __set_h_errno (TRY_AGAIN);

Vendor Information

The vendor has not provided us with any further information regarding this vulnerability.

Vendor References

None

Addendum

The CERT/CC has no additional comments at this time.

If you have feedback, comments, or additional information about this vulnerability, please send us email.