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 nss/20532] New: getaddrinfo uses errno and h_errno without guaranteeing they're set, wrong errors returned by gaih_inet when lookup functions are not found.


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

            Bug ID: 20532
           Summary: getaddrinfo uses errno and h_errno without
                    guaranteeing they're set, wrong errors returned by
                    gaih_inet when lookup functions are not found.
           Product: glibc
           Version: unspecified
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: nss
          Assignee: unassigned at sourceware dot org
          Reporter: dsansome at google dot com
  Target Milestone: ---

When no gethostbyname*_r lookup functions can be loaded from a module (most
commonly when a module is listed in /etc/nsswitch.conf that does not exist),
gaih_inet falls into this block added in revision
3d04f5db20c8f0d1ba3881b5f5373586a18cf188 for #15339:

  if (errno != 0 && errno != ENOENT)
    __set_h_errno (NETDB_INTERNAL);

but there is no guarantee that errno was set - it's not set by
__nss_lookup_function, and other previous lookup functions don't have to set
it.  This is problem #1.

Problem #2 is lower down:

  if (h_errno == NETDB_INTERNAL)
    {
      result = -EAI_SYSTEM;
      goto free_and_return;
    }

this time there's no guarantee that h_errno is set, so it probably still has
the same value as the last call to gaih_inet.

To reproduce:

$ grep hosts /etc/nsswitch.conf
hosts:          files dns doesnotexist

$ cat test.c
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

void gai(const char* addr) {
  struct addrinfo* res;
  int ret = getaddrinfo(addr, "80", NULL, &res);
  if (ret != 0) {
    printf("\"%s\" failed: %d, errno=%d\n", addr, ret, errno);
  } else {
    printf("\"%s\" succeeded\n", addr);
    freeaddrinfo(res);
  }
}

int main(int argc, char** argv) {
  char hostname[1024];
  gethostname(hostname, sizeof(hostname) - 1);

  gai(hostname);           /* Returns 0. */
  errno = EAGAIN;
  gai("does.not.resolve"); /* Returns EAI_SYSTEM, should return EAI_NONAME. */
  gai(hostname);           /* Returns EAI_SYSTEM, should return 0. */

  return 0;
}


Output:
$ gcc -o test test.c && ./test
"[my hostname]" succeeded
"does.not.resolve" failed: -11, errno=11
"[my hostname]" failed: -11, errno=11


Expected:
$ gcc -o test test.c && ./test
"[my hostname]" succeeded
"does.not.resolve" failed: -2, errno=11
"[my hostname]" succeeded


I'm not sure how to fix this because I'm not sure what errors revision
3d04f5db20c8f0d1ba3881b5f5373586a18cf188 is trying to catch.
Errors loading nss modules don't seem to be reported through errno (and I think
everything's cached after the first call anyway?).

Maybe we should clear errno at the start of gaih_inet, but #19445 says we
should reset it again before we exit.

-- 
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]