From patchwork Tue Jul 4 14:10:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 21402 Received: (qmail 12905 invoked by alias); 4 Jul 2017 14:10:25 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 11144 invoked by uid 89); 4 Jul 2017 14:10:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=tighten, 3586 X-HELO: mx1.redhat.com DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6B12C7D0CB Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=fweimer@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 6B12C7D0CB From: Florian Weimer Subject: Re: [PATCH] resolv: Mirror the entire resolver configuration in struct resolv_conf To: GNU C Library References: <20170630193802.80D6C439942F0@oldenburg.str.redhat.com> <5bb0919b-0dfe-df45-5033-ca610fee52d6@redhat.com> <79fd6bdd-7a1d-ba01-1423-ae1c497c9476@redhat.com> <167ff222-1348-d326-ffd4-db7152b494f7@redhat.com> <77c23b20-8a65-cfec-4902-b3d9f0b7375c@redhat.com> Message-ID: Date: Tue, 4 Jul 2017 16:10:18 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.2.1 MIME-Version: 1.0 In-Reply-To: <77c23b20-8a65-cfec-4902-b3d9f0b7375c@redhat.com> On 07/04/2017 02:55 PM, Florian Weimer wrote: > On 07/04/2017 02:21 PM, Florian Weimer wrote: >> On 07/04/2017 02:16 PM, Andreas Schwab wrote: >>> 298 if (!(resp->dnsrch[0] == resp->defdname >>> 299 && resp->dnsrch[MAXDNSRCH] == NULL)) >> >> Ah. I assume this breaks for defname[0] == '\0' and dnsrch[0] == NULL. >> >> It seems that this is triggered by having a host name which does not >> contain a dot. I'll fix this and add a test case. Thanks. > > And this is the fix I'm going to commit. Trying again to send the attachment. Florian resolv: Fix resolv_conf _res matching A dot-less host name without an /etc/resolv.conf file caused an assertion failure in update_from_conf because the function would not deal correctly with the empty search list case. Thanks to Andreas Schwab for debugging assistence. 2017-07-04 Florian Weimer * resolv/resolv_conf.c (resolv_conf_matches): Tighten check for name server and sort list counts. Fix improper check for empty search path (completely missing domain name) leading to assertion failure in update_from_conf. * resolv/tst-resolv-res_init-skeleton.c (struct test_case): Add hostname member. (run_res_init): Set host name if requested. (test_cases): Update. diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c index 0ed36cd..f391d30c2 100644 --- a/resolv/resolv_conf.c +++ b/resolv/resolv_conf.c @@ -272,7 +272,7 @@ resolv_conf_matches (const struct __res_state *resp, nserv = MAXNS; /* _ext.nscount is 0 until initialized by res_send.c. */ if (resp->nscount != nserv - && (resp->_u._ext.nscount != 0 && resp->_u._ext.nscount != nserv)) + || (resp->_u._ext.nscount != 0 && resp->_u._ext.nscount != nserv)) return false; for (size_t i = 0; i < nserv; ++i) { @@ -295,9 +295,25 @@ resolv_conf_matches (const struct __res_state *resp, /* Check that the search list in *RESP has not been modified by the application. */ { - if (!(resp->dnsrch[0] == resp->defdname - && resp->dnsrch[MAXDNSRCH] == NULL)) + if (resp->dnsrch[0] == NULL) + { + /* Empty search list. No default domain name. */ + return conf->search_list_size == 0 && resp->defdname[0] == '\0'; + } + + if (resp->dnsrch[0] != resp->defdname) + /* If the search list is not empty, it must start with the + default domain name. */ return false; + + size_t nsearch; + for (nsearch = 0; nsearch < MAXDNSRCH; ++nsearch) + if (resp->dnsrch[nsearch] == NULL) + break; + if (nsearch > MAXDNSRCH) + /* Search list is not null-terminated. */ + return false; + size_t search_list_size = 0; for (size_t i = 0; i < conf->search_list_size; ++i) { @@ -326,6 +342,8 @@ resolv_conf_matches (const struct __res_state *resp, size_t nsort = conf->sort_list_size; if (nsort > MAXRESOLVSORT) nsort = MAXRESOLVSORT; + if (resp->nsort != nsort) + return false; for (size_t i = 0; i < nsort; ++i) if (resp->sort_list[i].addr.s_addr != conf->sort_list[i].addr.s_addr || resp->sort_list[i].mask != conf->sort_list[i].mask) diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c index 9e496a3..8f395d8 100644 --- a/resolv/tst-resolv-res_init-skeleton.c +++ b/resolv/tst-resolv-res_init-skeleton.c @@ -307,6 +307,10 @@ struct test_case /* Setting for the RES_OPTIONS environment variable. NULL if the variable is not to be set. */ const char *res_options; + + /* Override the system host name. NULL means that no change is made + and the default is used (test_hostname). */ + const char *hostname; }; enum test_init @@ -358,6 +362,14 @@ run_res_init (void *closure) setenv ("LOCALDOMAIN", ctx->t->localdomain, 1); if (ctx->t->res_options != NULL) setenv ("RES_OPTIONS", ctx->t->res_options, 1); + if (ctx->t->hostname != NULL) + { + /* This test needs its own namespace, to avoid changing the host + name for the parent, too. */ + TEST_VERIFY_EXIT (unshare (CLONE_NEWUTS) == 0); + if (sethostname (ctx->t->hostname, strlen (ctx->t->hostname)) != 0) + FAIL_EXIT1 ("sethostname (\"%s\"): %m", ctx->t->hostname); + } switch (ctx->init) { @@ -434,6 +446,12 @@ struct test_case test_cases[] = "nameserver 127.0.0.1\n" "; nameserver[0]: [127.0.0.1]:53\n" }, + {.name = "empty file, no-dot hostname", + .conf = "", + .expected = "nameserver 127.0.0.1\n" + "; nameserver[0]: [127.0.0.1]:53\n", + .hostname = "example", + }, {.name = "empty file with LOCALDOMAIN", .conf = "", .expected = "search example.net\n" @@ -462,8 +480,7 @@ struct test_case test_cases[] = .res_options = "edns0 attempts:5", }, {.name = "basic", - .conf = "domain example.net\n" - "search corp.example.com example.com\n" + .conf = "search corp.example.com example.com\n" "nameserver 192.0.2.1\n", .expected = "search corp.example.com example.com\n" "; search[0]: corp.example.com\n" @@ -471,6 +488,16 @@ struct test_case test_cases[] = "nameserver 192.0.2.1\n" "; nameserver[0]: [192.0.2.1]:53\n" }, + {.name = "basic with no-dot hostname", + .conf = "search corp.example.com example.com\n" + "nameserver 192.0.2.1\n", + .expected = "search corp.example.com example.com\n" + "; search[0]: corp.example.com\n" + "; search[1]: example.com\n" + "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n", + .hostname = "example", + }, {.name = "basic no-reload", .conf = "options no-reload\n" "search corp.example.com example.com\n"