cURL / Mailing Lists / curl-users / Single Mail

curl-users

[ curl-Bugs-616401 ] 7.10-pre3 segfault on invalid URLs

From: <noreply_at_sourceforge.net>
Date: Sun, 29 Sep 2002 23:31:06 -0700

Bugs item #616401, was opened at 2002-09-30 06:31
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=100976&aid=616401&group_id=976

Category: libcurl
Group: crash
Status: Open
Resolution: None
Priority: 5
Submitted By: Cris Bailiff (crisb)
Assigned to: Daniel Stenberg (bagder)
Summary: 7.10-pre3 segfault on invalid URLs

Initial Comment:
I have an application which managed to pass a URL with
an invalid scheme
to libcurl (the URL format was basically 'error:foo').

With libcurl 7.10-pre3 and 7.10-pre4 (on linux Mandrake
8.2, gcc 2.96, glibc-2.2.4),
this resulted in a segfault in hostip.c, line 495.

Here's the backtrace:
-------------------------------------------------

#0 hostcache_fixoffset (h=0x80656a0, offset=0) at
hostip.c:495
#1 0x000000c8 in ?? ()
#2 0x4001c04d in Curl_getaddrinfo (data=0x8050660,
hostname=0x8064fcc "a:", port=80, bufp=0xbffff3ec) at
hostip.c:616
#3 0x4001bde5 in Curl_resolv (data=0x8050660,
hostname=0x8064fcc "a:", port=80) at hostip.c:256
#4 0x40027318 in CreateConnection (data=0x8050660,
in_connect=0xbffff6d8) at url.c:2636
#5 0x40027734 in Curl_connect (data=0x8050660,
in_connect=0xbffff6d8) at url.c:2782
#6 0x40030ef9 in Curl_perform (data=0x8050660) at
transfer.c:1238
#7 0x4003133e in curl_easy_perform (curl=0x8050660) at
easy.c:245

------------------------------------------------
I couldn't reproduce it with the curl command line, but
I managed to
duplicate it with the following trivial code, taken
from simple.c:

-------------------------------------------------

#include <stdio.h>
#include <curl/curl.h>

int main(int argc, char **argv)
{
  CURL *curl;
  CURLcode res;
  printf("Version=%s\n",curl_version());

  curl = curl_easy_init();
  if(curl && argc) {
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
    res = curl_easy_perform(curl);
    printf("Result code = %d\n",res);

    curl_easy_cleanup(curl);
  }
  return 0;
}
-------------------------------------------------

When run with regular arguments, 'http://foo' etc. all
is fine. When
run with 'a:' or 'error:' or whatever, it segfaults. It
seems ok under
7.9.8. Further testing seemed to narrow the issue to
addresses which
look like they could be parseable as IPv6 addresses
(':' delimited),
but turn out not to be - basically, anything starting
'0-9' or 'a-f'
faults, otherwise it's ok.

(foo:, bar: baz: fault, but not xyzzy: or plugh:)

Tracing back from the fault in hostcache_fixoffset, it
looks like the
behaviour is governed by the return value in hostip.c,
line 600:

-------------------------------------------------
hostip.c:600: (7.10-pre3):
   /* Linux */
    while((res=gethostbyname_r(hostname,
                               (struct hostent *)buf,
                               (char *)buf +
sizeof(struct hostent),
                               step_size -
sizeof(struct hostent),
                               &h, /* DIFFERENCE */
                               &h_errnop))==ERANGE) {
      step_size+=200;
    }
-------------------------------------------------

'hostname' here is set to the entire input string for
unrecognised
 schemes ('foo:'), whereas recognised schemes make the
hostname just
the alpha-numeric part (no ':').

The crash seems to be triggered by differing behaviour in
gethostbyname_r when given valid hostnames compared to
(what seem to be)
raw addresses.

For unresolvable regular names (including 'illegal
names', like 'z:',
gethostbyname_r returns

        res=2

which libcurl returns as an unresolveable host error
(actually
buf->h_name and buf->h_aliases also are set to point to
'something',
even though they are unused), whereas for hostnames
that look like
resolvable addresses but turn out not to be (a:, b:
127.0.0.1:),
gethostbyname_r returns

        res=0

indicating success, but buf->h_name and buf->h_aliases
are left untouched
and therefore remain NULL, which causes the segfault
shortly afterwards
at h->h_aliases[0] in hostcache_fixoffset: (hostip.c:494):

-------------------------------------------------
h->h_aliases=(char **)((long)h->h_aliases+offset);
while(h->h_aliases[i]) {
    h->h_aliases[i]=(char *)((long)h->h_aliases[i]+offset);
    i++;
}
-------------------------------------------------

h_errnop doesn't seem to be modified in either case, so
I think this
must be a resolver bug, but in any case, here's an
attempted fix:

-------------------------------------------------
--- hostip.c.orig Mon Sep 30 16:01:34 2002
+++ hostip.c Mon Sep 30 16:04:53 2002
@@ -609,7 +609,7 @@
 #ifdef MALLOCDEBUG
     infof(data, "gethostbyname_r() uses %d bytes\n",
step_size);
 #endif
- if(!res) {
+ if(!res && ((struct hostent *)buf)->h_name) {
       int offset;
       h=(struct hostent *)realloc(buf, step_size);
       offset=(long)h-(long)buf;

-------------------------------------------------
(attached also).

This fix 'works for me' on 7.10-pre3 and 7.10-pre4. I'm
not sure why
this doesn't show up on 7.9.8, as I can't see any major
changes in this
area.
                                                      
                                   
I don't know if this applies to any of the other
variants of gethostbyname used by other platforms.

Cris

----------------------------------------------------------------------

You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=100976&aid=616401&group_id=976

-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
Received on 2002-09-30