This is the mail archive of the
glibc-bugs@sources.redhat.com
mailing list for the glibc project.
[Bug libc/515] gethostbyname_r() returns incorrect error for certain sizes (or alignment)
- From: "jamie at shareable dot org" <sourceware-bugzilla at sources dot redhat dot com>
- To: glibc-bugs at sources dot redhat dot com
- Date: 9 May 2005 13:22:52 -0000
- Subject: [Bug libc/515] gethostbyname_r() returns incorrect error for certain sizes (or alignment)
- References: <20041104163517.515.gmorin1@bloomberg.net>
- Reply-to: sourceware-bugzilla at sources dot redhat dot com
------- Additional Comments From jamie at shareable dot org 2005-05-09 13:22 -------
Not much code uses gethostbyname_r, and unfortunately the Glibc version has a
bit of a reputation for problems. (Look in the code for libcurl for comments:
it no longer uses a dynamically allocated buffer, and just uses a large buffer
without resizing now because some older Glibc versions returned EAGAIN instead
of ERANGE when the buffer's too small, and other Glibc versions returned EAGAIN
when a lookup failed...)
Anyway, I just discovered the same bug as being reported here. With a too-small
buffer, under some circumstances (I found it when resolving CNAMEs over a
certain length, critically dependent on buffer size):
Glibc-2.3.5 returns:
ret == EINVAL, errno == EINVAL, *h_errnop == 3 (NO_RECOVERY)
Glibc-2.3.2-27.9.7 (RH9) returns:
ret == 0, errno == ERANGE, *h_errnop== 3 (NO_RECOVERY)
Clearly an important bit of code is this from Glibc-2.3.5, nss/getXXbyYY_r.c:
int res;
if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
res = 0;
/* Don't pass back ERANGE if this is not for a too-small buffer. */
else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN)
res = EINVAL;
#ifdef NEED_H_ERRNO
/* These functions only set errno if h_errno is NETDB_INTERNAL. */
else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL)
res = EAGAIN;
#endif
else
return errno;
__set_errno (res);
return res;
The three values, status, errno and *h_errnop, are set in the suspicious code of
glibc/resolv/* and glibc/resolv/nss_dns/*.
Following are some ideas about the resolv/ code for the next person to look at
more closely.
1. In glibc/resolv/nss_dns/dns-network.c, getanswer_r():
if (errno == EMSGSIZE)
{
errno = ERANGE;
return NSS_STATUS_TRYAGAIN;
}
Is it missing an assignment to *h_errnop?
All the _other_ places in glibc/resolv/nss_dns/*.c which set errno to ERANGE
and return NSS_STATUS_TRYAGAIN do one more thing: They set *h_errnop to
NETDB_INTERNAL. The above code snipper is not consistent with them.
2. In glibc/resolv/*.c, *h_errnop or h_errno are set to NO_RECOVERY in quite a
lot of places. Should some of them be non-fatal, setting *h_errnop to
NETDB_INTERNAL, errno to ERANGE, and returning NSS_STATUS_TRYAGAIN?
3. In glibc/resolv/gethnamaddr.c, h_errno is set in quite a lot of places using
__set_h_errno. Is that appropriate for gethostbyname_r() calls? The h_errno
value should be stored in *h_errno_p, _not_ in the h_errno variable, right?
Just a few ideas there. And to add another person to the list who've been stung
by this bug.
One final question: Given the existence of the bug: is there a "safe" buffer
size to use with gethostbyname_r where we can be sure this bug doesn't occur?
Glibc uses 1024 internally (in gethostbyname) - is that a safe value to use?
-- Jamie
--
http://sources.redhat.com/bugzilla/show_bug.cgi?id=515
------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.