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

Bug #386791 reported by Fibonacci
22
This bug affects 2 people
Affects Status Importance Assigned to Milestone
GLibC
Fix Released
Low
eglibc (Ubuntu)
Triaged
Low
Unassigned

Bug Description

I'm using the latest SVN version of aMSN, compiled directly from source. When running it once, all is fine and dandy; but if I run it again whenever another instance of the program is running, it will segfault.
I reported it to the aMSN team (see http://www.amsn-project.net/forums/viewtopic.php?t=6662), and they claim the error is not within their code - apparently the culprit is a buggy version of libc. So I'm reporting it here without specifying the package.

I've attached a full backtrace obtained on GDB.

Tags: amsn segfault
Revision history for this message
Fibonacci (fibonacci-prower) wrote :
Revision history for this message
Nick Ellery (nick.ellery) wrote :

As the version you are currently running is not in Ubuntu as you compiled it directly from source, it is also not supported by Ubuntu, and thus bug reports cannot be reported against this version.

Changed in ubuntu:
status: New → Invalid
Revision history for this message
Nick Ellery (nick.ellery) wrote :

I should also note that if you are able to reproduce this on a version in Ubuntu, then this is a valid report. If that's the case, then feel free to reopen the bug.

Revision history for this message
Fibonacci (fibonacci-prower) wrote :

Perhaps you didn't read my original report. The bug is not within the code not supported by Ubuntu. As it was written in the URL I posted, which you didn't take the time to read, "this looks to me like they're using a bugged version of libc or some other library."
Anyway, I tried it with the official amsn package from the Ubuntu repos, and yes, it does still fail, so the bug IS valid - but not within amsn.

Changed in ubuntu:
status: Invalid → New
Revision history for this message
Fibonacci (fibonacci-prower) wrote :

The root of the problem is that getaddrinfo("localhost", NULL, NULL, &result); (which is what aMSN does - both in the official and the SVN version) causes a segfault in my system. There's no reason it should cause a segfault, so the bug, as originally stated, is not within aMSN code.

However, doing some experimentation, I discovered that the segfault will only happen if /etc/hosts contains a *very* long line - around 3000-4000 characters seems to be the critical length in my system.
This is problematic because network-admin always lumps in one single line all URLs contained in /etc/hosts which point to the same IP, leading to unmanageably long lines, thus causing the aforementioned line of code to segfault. Of course, it shouldn't segfault even in that case, but due to the behaviour of network-admin, this is hardly avoidable.

Perhaps this should be considered a bug in both getaddrinfo and network-admin?

Revision history for this message
Adil Arif (adisari06) wrote :

I am trying to assign this bug to the right package. Do you know what program is called upon for getaddrinfo?

Revision history for this message
Fibonacci (fibonacci-prower) wrote :

I think it's libc6.

Revision history for this message
Adil Arif (adisari06) wrote :

Thanks for your package suggestion, hopefully by notifying the right package maintainers, I can get this bug fixed a bit faster then under just the generic Ubuntu. Good luck.

affects: ubuntu → eglibc (Ubuntu)
Revision history for this message
to be removed (liw) wrote :

@Nick Ellery: If it is a bug in libc, it does not matter if the code that triggers the bug is in Ubuntu or not. The bug is still valid.

@everyone: I can reproduce this on jaunty with glibc, not just in karmic with eglibc. Steps to reproduce:

0. Run the attached program. It will not segfault.
1. Create a line in /etc/hosts at least 4000 characters long (I did not figure out the exact line length).
2. Re-run the attached program. It will segfault.
3. Remove the long line from hosts.
4. Re-run th eattached program. It will again not segfault.

to be removed (liw)
Changed in eglibc (Ubuntu):
status: New → Triaged
importance: Undecided → Low
Revision history for this message
to be removed (liw) wrote :

The problem seems to be that glibc (eglibc is identical in this regard, it seems) uses alloca when reading the /etc/hosts file, and does not do the complicated signal handling magic to handle the case when the stack gets full. The fix would be to rewrite the parsing logic to use safer memory allocation methods instead.

Revision history for this message
In , Lars Wirzenius (lars-ubuntu) 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

to be removed (liw)
summary: - aMSN crashes when running it twice
+ libc getaddrinfo crashes if /etc/hosts has very long lines
Changed in glibc:
status: Unknown → Confirmed
Revision history for this message
Fibonacci (fibonacci-prower) wrote :

Shouldn't this bug be reported also to network-admin? Of course, libc shouldn't crash in the first place even if there are too long lines (which is the original report), but also, there's no reason for network-admin to lump all entries into as few lines as possible, creating lines that long.

Revision history for this message
In , Fibonacci (fibonacci-prower) 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.

Revision history for this message
to be removed (liw) wrote :

Fibonacci: you are probably right. Please do so. I don't want to do that, since I don't use network-admin.

Revision history for this message
Fibonacci (fibonacci-prower) wrote :

Lars: I just found this was reported more than two years ago, and marked as invalid. I've just reopened it: bug 103960.

Revision history for this message
In , Drepper-fsp (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.

Changed in glibc:
status: Confirmed → Incomplete
Revision history for this message
In , Fibonacci (fibonacci-prower) wrote :

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

Changed in glibc:
status: Incomplete → In Progress
Revision history for this message
In , agl (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.

Revision history for this message
In , Drepper-fsp (drepper-fsp) wrote :

I've checked in a patch.

Revision history for this message
Fibonacci (fibonacci-prower) wrote :

Has there been any progress on this?

Changed in glibc:
importance: Unknown → Low
status: In Progress → Fix Released
Revision history for this message
In , Jackie-rosen (jackie-rosen) wrote :

*** Bug 260998 has been marked as a duplicate of this bug. ***
Seen from the domain http://volichat.com
Page where seen: http://volichat.com/adult-chat-rooms
Marked for reference. Resolved as fixed @bugzilla.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.