This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug network/17630] New: endless loop in getaddr_r


https://sourceware.org/bugzilla/show_bug.cgi?id=17630

            Bug ID: 17630
           Summary: endless loop in getaddr_r
           Product: glibc
           Version: 2.11
            Status: NEW
          Severity: normal
          Priority: P2
         Component: network
          Assignee: unassigned at sourceware dot org
          Reporter: yashavanth.hsn at gmail dot com

Hallo,

DESCRIPTION: getanswer_r ends in infinite loop on certain inputs.
GLIBC_VERSION: 2.11.3

Note: I am novice into glibc and don't have complete understanding of glibc
with respect to dns resolution. 

IN DETAIL: 
When I execute iptables-restore on one of our Lab's system, iptables-restore
started consuming 100% cpu all the time. I did strace on iptables-restore I
found that most of the cpu is comsumed by NSS DNS resolver of libc as given
below.

 67.50%  iptables-restor  libnss_dns-2.11.3.so  [.] getanswer_r
 15.12%  iptables-restor  libc-2.11.3.so        [.] __strcasecmp
  9.02%  iptables-restor  libc-2.11.3.so        [.] __ctype_b_loc
  7.02%  iptables-restor  libc-2.11.3.so        [.] __i686.get_pc_thunk.bx
  0.77%  iptables-restor  libnss_dns-2.11.3.so  [.] 0x00000c00
  0.18%  iptables-restor  [kernel.kallsyms]     [k] read_hpet  

To get more details, I attached iptables-restore to gdb with debugging symbols
loaded and found that glibc takes most of the CPU, since it ends in endless
loop. when, 

1. have_answer is set 
2. net_i is set to BYNAME
3. result->n_aliases is set to ns5.dsredirections.com ( i,e in the code ap is
set to ns5.dsredirections.com )

With this input, I found that the loop never exists and continue to process the
same input again and again. 

Basically as per the code comment, the loop functionality is to :

               /* 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
                */

But then the question is : 
1. Is this is a valid input or not to getanswer_r.

on the other hand, when the input is of bad form like ns5.dsredirections.com,
code has to detect and come out of loop.

FINDINGS and SOLUTION: 

I found that the most recent Upstream code does not have this fixed as this
part of the code is stable since 2002.

** I tried to patch glibc as given below. ( Not sure if its correct and does
not break other scenarios )

    avoid infinite loop for invalid entry.

    getaddr_r gets into infinite loop for invalid entries
    like ns5.dsredirections.com then it never detects and
    breaks from  infinite loop.

    This patch detects the entries with non digit and
    non hexadecimal digits and returns.

diff --git a/glibc/glibc-2.11.3-getaddr.diff b/glibc/glibc-2.11.3-getaddr.diff
new file mode 100644
index 0000000..664b033
--- /dev/null
+++ b/glibc/glibc-2.11.3-getaddr.diff
@@ -0,0 +1,42 @@
+Index: glibc-2.11.3/resolv/nss_dns/dns-network.c
+===================================================================
+--- glibc-2.11.3.orig/resolv/nss_dns/dns-network.c
++++ glibc-2.11.3/resolv/nss_dns/dns-network.c
+@@ -414,6 +414,7 @@ getanswer_r (const querybuf *answer, int
+               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.  */
++              unsigned int invalid = 0;
+               do
+                 {
+                   /* Match the leading 0 or 0[xX] base indicator.  */
+@@ -440,12 +441,23 @@ getanswer_r (const querybuf *answer, int
+                         part = (part * base) + (*p - '0');
+                       else if (base == 16 && isxdigit (*p))
+                         part = (part << 4) + 10 + (tolower (*p) - 'a');
++      
++                      /* when neither digit nor hexadigit, then its a invalid
*/    
++                      if ( !isdigit(*p) && !isxdigit(*p) && *p != '.')
++                        {
++                             invalid = 1;
++                      }
++  
+                       ++p;
+                     } while (*p != '\0' && *p != '.');
+ 
++                  if( invalid )
++                      return NSS_STATUS_NOTFOUND;
++              
+                   if (*p != '.')
+                     break;    /* Bad form.  Give up on this name.  */
+ 
++                      
+                   /* Install this as the next more significant byte.  */
+                   val |= part << shift;
+                   shift += 8;
+@@ -470,4 +482,4 @@ getanswer_r (const querybuf *answer, int
+ 
+   __set_h_errno (TRY_AGAIN);
+   return NSS_STATUS_TRYAGAIN;
+-}
++}  

After the patched glibc is installed, iptables-restore does not run infinitely
and everything is normal.

Could you please let me know, whether this will be fixed moving further. 

I would like to extend my help with any information if needed.

Best,
Yash

-- 
You are receiving this mail because:
You are on the CC list for the bug.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]