Launchpad has imported 6 comments from the remote bug at
http://sourceware.org/bugzilla/show_bug.cgi?id=10484.

If you reply to an imported comment from within Launchpad, your comment
will be sent to the remote bug automatically. Read more about
Launchpad's inter-bugtracker facilities at
https://help.launchpad.net/InterBugTracking.

------------------------------------------------------------------------
On 2009-08-05T15:22:27+00:00 Lars Wirzenius wrote:

If /etc/hosts contains a long line (thousands of bytes), getaddrinfo causes a
segmentation fault. A small program to test:

-- 8< ---
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main(void)
{
    struct addrinfo *result;
    getaddrinfo("localhost", NULL, NULL, &result);
    return 0;
}
--- 8< ---

On a system with short lines in /etc/hosts, the above program exits normally. If
/etc/hosts has a very long line (5500 bytes is sufficiently long), it
segmentation faults.

I think this is due to using alloca and extend_alloca to hold the line when
parsing the file, which leads to a stack overflow, which then results in the
kernel sending a SIGSEGV to the program. The parsing code is not set up to
handle that. Unfortunately, I am too stupid to provide a patch to fix this.

My test /etc/hosts file has IPv6 addresses commented out, so the segmentation
fault happens in sysdeps/posix/getaddrinfo.c, function gaih_inet, around line
531, on this line:

                  rc = __gethostbyname2_r (name, family, &th, tmpbuf,
                                           tmpbuflen, &h, &herrno);

My stack limit is 8 megabytes.

This was originally filed as a bug in Ubuntu, and applies to both versions 2.9
and 2.10 in that distribution. I have compared the source file against the
current version in git, and it has no relevant changes. (I was unable to set up
a chroot to actually test the current git version, sorry.)

Original bug:
https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/386791

Reply at: https://bugs.launchpad.net/glibc/+bug/386791/comments/11

------------------------------------------------------------------------
On 2009-08-05T19:28:48+00:00 Fibonacci wrote:

This also happens on plain x86 processors. The original bug was found on
a PIV.

Perhaps it shouldn't be marked as x86_64.

Reply at: https://bugs.launchpad.net/glibc/+bug/386791/comments/13

------------------------------------------------------------------------
On 2009-10-30T05:38:19+00:00 Drepper-fsp wrote:

You have to be much more precise.  I cannot reproduce any problem and your
description doesn't say where the stack overflow is supposed to happen.

Reply at: https://bugs.launchpad.net/glibc/+bug/386791/comments/16

------------------------------------------------------------------------
On 2009-10-30T13:49:45+00:00 Fibonacci wrote:

Try a longer line. I've gotten 100k+ lines just by using a hosts file for
adblock and then running network-admin.

Reply at: https://bugs.launchpad.net/glibc/+bug/386791/comments/17

------------------------------------------------------------------------
On 2011-01-07T17:40:48+00:00 agl wrote:

The following program will blow its stack and crash if I have an
/etc/hosts line longer than 4Kish.

---
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main() {
  struct addrinfo hints, *res;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = PF_INET;
  getaddrinfo("www.google.com", "http", &hints, &res);

  return 0;
}
---

Setting the ai_family in the hints is required in order to reproduce the
crash.

(File and line references in the following are relative to git
16c2895feabae0962e0eba2b9164c6a83014bfe4)

In sysdeps/posix/getaddrinfo.c:531 we have a loop in gaih_inet which
allocas a buffer and doubles the size of that buffer each time
__gethostbyname2_r returns with ERANGE.

The __gethostbyname2_r ends up in nss/nss_files/files-hosts.c:128:

      if (status == NSS_STATUS_SUCCESS»·»·······»·······»·······»·······      \
»·······  && _res_hconf.flags & HCONF_FLAG_MULTI)»······»·······»·······      \
»·······{»······»·······»·······»·······»·······»·······»·······»·······      \
»·······  /* We have to get all host entries from the file.  */»»·······      \
»·······  const size_t tmp_buflen = MIN (buflen, 4096);»»·······»·······      \
»·······  char tmp_buffer[tmp_buflen]»··»·······»·······»·······»·······      \
»·······    __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));\

Here, if HCONF_FLAG_MULTI is set then a secondary buffer is created on
the stack for the use of internal_getent. This buffer is limited to 4K
in size.

internal_getent will try to read lines from /etc/hosts and it will
return ERANGE if the line (plus an internal structure) doesn't fit into
|tmp_buffer|. When this happens the loop in getaddrinfo.c will try
doubling the size of its buffer. However, |tmp_buffer| was limited to 4K
so __gethostbyname2_r repeatedly returns ERANGE and gaih_inet uselessly
expands the buffer on the stack until the program crashes.

I believe that the best solution is to replace:
  const size_t tmp_buflen = MIN (buflen, 4096);
with:
  const size_t tmp_buflen = buflen;

I can confirm that this fixes the crash for me.

Reply at: https://bugs.launchpad.net/glibc/+bug/386791/comments/18

------------------------------------------------------------------------
On 2011-01-13T16:29:25+00:00 Drepper-fsp wrote:

I've checked in a patch.

Reply at: https://bugs.launchpad.net/glibc/+bug/386791/comments/19


** Changed in: glibc
       Status: In Progress => Fix Released

** Changed in: glibc
   Importance: Unknown => Low

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/386791

Title:
  libc getaddrinfo crashes if /etc/hosts has very long lines

-- 
ubuntu-bugs mailing list
ubuntu-bugs@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to