djdelorie / rpms / glibc

Forked from rpms/glibc 3 years ago
Clone
8597553
commit 4446a885f3aeb3a33b95c72bae1f115bed77f0cb
8597553
Author: Florian Weimer <fweimer@redhat.com>
8597553
Date:   Tue Jul 4 14:47:29 2017 +0200
8597553
8597553
    resolv: Fix resolv_conf _res matching
8597553
    
8597553
    A dot-less host name without an /etc/resolv.conf file caused an
8597553
    assertion failure in update_from_conf because the function would not
8597553
    deal correctly with the empty search list case.
8597553
    
8597553
    Thanks to Andreas Schwab for debugging assistence.
8597553
8597553
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
8597553
index 0ed36cde02608f2d..f391d30c277bb348 100644
8597553
--- a/resolv/resolv_conf.c
8597553
+++ b/resolv/resolv_conf.c
8597553
@@ -272,7 +272,7 @@ resolv_conf_matches (const struct __res_state *resp,
8597553
       nserv = MAXNS;
8597553
     /* _ext.nscount is 0 until initialized by res_send.c.  */
8597553
     if (resp->nscount != nserv
8597553
-        && (resp->_u._ext.nscount != 0 && resp->_u._ext.nscount != nserv))
8597553
+        || (resp->_u._ext.nscount != 0 && resp->_u._ext.nscount != nserv))
8597553
       return false;
8597553
     for (size_t i = 0; i < nserv; ++i)
8597553
       {
8597553
@@ -295,9 +295,25 @@ resolv_conf_matches (const struct __res_state *resp,
8597553
   /* Check that the search list in *RESP has not been modified by the
8597553
      application.  */
8597553
   {
8597553
-    if (!(resp->dnsrch[0] == resp->defdname
8597553
-          && resp->dnsrch[MAXDNSRCH] == NULL))
8597553
+    if (resp->dnsrch[0] == NULL)
8597553
+      {
8597553
+        /* Empty search list.  No default domain name.  */
8597553
+        return conf->search_list_size == 0 && resp->defdname[0] == '\0';
8597553
+      }
8597553
+
8597553
+    if (resp->dnsrch[0] != resp->defdname)
8597553
+      /* If the search list is not empty, it must start with the
8597553
+         default domain name.  */
8597553
+      return false;
8597553
+
8597553
+    size_t nsearch;
8597553
+    for (nsearch = 0; nsearch < MAXDNSRCH; ++nsearch)
8597553
+      if (resp->dnsrch[nsearch] == NULL)
8597553
+        break;
8597553
+    if (nsearch > MAXDNSRCH)
8597553
+      /* Search list is not null-terminated.  */
8597553
       return false;
8597553
+
8597553
     size_t search_list_size = 0;
8597553
     for (size_t i = 0; i < conf->search_list_size; ++i)
8597553
       {
8597553
@@ -326,6 +342,8 @@ resolv_conf_matches (const struct __res_state *resp,
8597553
     size_t nsort = conf->sort_list_size;
8597553
     if (nsort > MAXRESOLVSORT)
8597553
       nsort = MAXRESOLVSORT;
8597553
+    if (resp->nsort != nsort)
8597553
+      return false;
8597553
     for (size_t i = 0; i < nsort; ++i)
8597553
       if (resp->sort_list[i].addr.s_addr != conf->sort_list[i].addr.s_addr
8597553
           || resp->sort_list[i].mask != conf->sort_list[i].mask)
8597553
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
8597553
index 9e496a3212b0f2ab..8f395d8ce92773a9 100644
8597553
--- a/resolv/tst-resolv-res_init-skeleton.c
8597553
+++ b/resolv/tst-resolv-res_init-skeleton.c
8597553
@@ -307,6 +307,10 @@ struct test_case
8597553
   /* Setting for the RES_OPTIONS environment variable.  NULL if the
8597553
      variable is not to be set.  */
8597553
   const char *res_options;
8597553
+
8597553
+  /* Override the system host name.  NULL means that no change is made
8597553
+     and the default is used (test_hostname).  */
8597553
+  const char *hostname;
8597553
 };
8597553
 
8597553
 enum test_init
8597553
@@ -358,6 +362,14 @@ run_res_init (void *closure)
8597553
     setenv ("LOCALDOMAIN", ctx->t->localdomain, 1);
8597553
   if (ctx->t->res_options != NULL)
8597553
     setenv ("RES_OPTIONS", ctx->t->res_options, 1);
8597553
+  if (ctx->t->hostname != NULL)
8597553
+    {
8597553
+      /* This test needs its own namespace, to avoid changing the host
8597553
+         name for the parent, too.  */
8597553
+      TEST_VERIFY_EXIT (unshare (CLONE_NEWUTS) == 0);
8597553
+      if (sethostname (ctx->t->hostname, strlen (ctx->t->hostname)) != 0)
8597553
+        FAIL_EXIT1 ("sethostname (\"%s\"): %m", ctx->t->hostname);
8597553
+    }
8597553
 
8597553
   switch (ctx->init)
8597553
     {
8597553
@@ -434,6 +446,12 @@ struct test_case test_cases[] =
8597553
      "nameserver 127.0.0.1\n"
8597553
      "; nameserver[0]: [127.0.0.1]:53\n"
8597553
     },
8597553
+    {.name = "empty file, no-dot hostname",
8597553
+     .conf = "",
8597553
+     .expected = "nameserver 127.0.0.1\n"
8597553
+     "; nameserver[0]: [127.0.0.1]:53\n",
8597553
+     .hostname = "example",
8597553
+    },
8597553
     {.name = "empty file with LOCALDOMAIN",
8597553
      .conf = "",
8597553
      .expected = "search example.net\n"
8597553
@@ -462,8 +480,7 @@ struct test_case test_cases[] =
8597553
      .res_options = "edns0 attempts:5",
8597553
     },
8597553
     {.name = "basic",
8597553
-     .conf = "domain example.net\n"
8597553
-     "search corp.example.com example.com\n"
8597553
+     .conf =  "search corp.example.com example.com\n"
8597553
      "nameserver 192.0.2.1\n",
8597553
      .expected = "search corp.example.com example.com\n"
8597553
      "; search[0]: corp.example.com\n"
8597553
@@ -471,6 +488,16 @@ struct test_case test_cases[] =
8597553
      "nameserver 192.0.2.1\n"
8597553
      "; nameserver[0]: [192.0.2.1]:53\n"
8597553
     },
8597553
+    {.name = "basic with no-dot hostname",
8597553
+     .conf = "search corp.example.com example.com\n"
8597553
+     "nameserver 192.0.2.1\n",
8597553
+     .expected = "search corp.example.com example.com\n"
8597553
+     "; search[0]: corp.example.com\n"
8597553
+     "; search[1]: example.com\n"
8597553
+     "nameserver 192.0.2.1\n"
8597553
+     "; nameserver[0]: [192.0.2.1]:53\n",
8597553
+     .hostname = "example",
8597553
+    },
8597553
     {.name = "basic no-reload",
8597553
      .conf = "options no-reload\n"
8597553
      "search corp.example.com example.com\n"