Compare commits

...

26 Commits
master ... f26

Author SHA1 Message Date
Florian Weimer ab210104fb - Auto-sync with upstream branch release/2.25/master
Upstream commit: edcf13e25c1559558a6f12ff5a71d4136a39235e

- PTHREAD_STACK_MIN is too small on x86-64 (#1527887)
- CVE-2018-1000001: Make getcwd fail if it cannot obtain an absolute path
  (#1533837)
- CVE-2017-16997: Check for empty tokens before dynamic string token
  expansion in the dynamic linker (#1526866)
- CVE-2017-15804: glob: Fix overflow in GLOB_TILDE unescaping (swbz#22332)
- CVE-2017-15670: glob: Fix one-byte overflow (#1504807)
- CVE-2017-15671: glob: Fix memory leak (#1504807)
- nss_files: Avoid large buffers with many host addresses (swbz#22078)
- nss_files: Use struct scratch_buffer for gethostbyname (swbz#18023)
- posix: Fix improper assert in Linux posix_spawn (BZ#22273)
- Don't use IFUNC resolver for longjmp or system in libpthread (swbz#21041)
- x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve (swbz#21265)
2018-01-17 16:10:03 +01:00
Florian Weimer bdd2e8da08 Actually rename glibc-rh168253-gtaddrinfo-no_data.patch 2018-01-17 15:18:41 +01:00
Florian Weimer 6b34bf502d Fix glibc-rh168253-getaddrinfo-no_data.patch patch name 2018-01-16 08:38:35 +01:00
Florian Weimer bd8a4ead36 Define glibc_release_url based on glibcsrcdir, not glibcversion
The former is more reliable because glibcsrcdir changes in case of a
release off the release/*/master branch (which does not have a
tarball), but glibcversion remains the same.
2017-10-17 12:56:52 +02:00
Florian Weimer 8597553f96 Rebase DNS stub resolver to the glibc 2.26 version
- Support an arbitrary number of search domains (#168253)
- Detect and apply /etc/resolv.conf changes in libresolv (#1374239)
- CVE-2015-5180: DNS stub resolver crash with crafted record type (#1251403)
2017-10-11 14:41:27 +02:00
Florian Weimer a13e3a1e46 Auto-sync with upstream branch release/2.25/master
Upstream commit: 595f287ae092dd973f6d5fb748cbe31ef7d82b2d
2017-10-11 13:20:34 +02:00
Florian Weimer 3262c2cba5 iconv: Support the IBM858 character set (#1416405) 2017-10-09 13:50:36 +02:00
Florian Weimer cd836dbd43 Move nss_compat to the main glibc package (#1400538) 2017-10-09 13:37:43 +02:00
Florian Weimer 0f76f1d26a Remove libnsl dependency from nss_compat 2017-10-09 13:36:07 +02:00
Florian Weimer 95f1260cfd Make build of nscd reproducible 2017-10-09 13:27:45 +02:00
Florian Weimer e2343bce79 Drop glibc-gcc-strict-overflow.patch
Different workaround was applied upstream.
2017-10-09 13:23:52 +02:00
Florian Weimer b17de1d824 Move /var/db/Makefile to nss_db (#1498900) 2017-10-09 13:22:25 +02:00
Florian Weimer d9fc484e2b Auto-sync with upstream branch release/2.25/master
Upstream commia:t 864ea5f6579edfee41f7d4a778807045b5aff66b
2017-10-09 13:21:49 +02:00
Florian Weimer 59c40130ab Rewrite langpack generation Lua
The existing shell-based approach required super-linear processing
time for the SUPPORTED file.
2017-10-08 11:17:30 +02:00
Florian Weimer 387c3212c7 Auto-sync with upstream release/2.25/master
Upstream commit: bc5ace67fe9823757532e0273f6c1cdfda065433

- mutex: Fix robust mutex lock acquire (#1485900)
- rwlock: Fix explicit hand-over (swbz#21298)
2017-08-28 15:32:38 +02:00
Florian Weimer e68f1ebb7b Auto-sync with upstream release/2.25/master
Upstream commit: 02aaa3c749bf18a3dbafff4c1f0180f135cad7ed

- assert: Support types without operator== (int) (#1483005)
2017-08-22 08:29:48 +02:00
Florian Weimer d771af991f Change invocation style for find-debuginfo.sh
Using eval affects command line parsing in the shell script.  Call the
script directly, but do not quote $find_debuginfo_args, to splice its
contents into the argument list.
2017-08-16 14:30:33 +02:00
Florian Weimer 67abe960c0 Replace create_lang_packages macro with its Lua code
This works around an RPM change in the processing of macro argument lists.
Newer RPM versions split the argument list, so that %1 contains just eo,
and not the whole language list.

Instead, use %language_list directly.  This is compatible with earlier
RPM versions, too.
2017-08-16 14:30:33 +02:00
Florian Weimer be8d2dcb53 Remove unused require_langpacks macro 2017-08-16 14:30:33 +02:00
Florian Weimer 4cd15aea67 Auto-sync with upstream release/2.25/master
Upstream commit: 47db584c74e2bbcf1ba55e62d949c1a738da5e0a

- Disable SSE2 usage on i686 (#1471427)
- CVE-2017-12132: Reduce EDNS payload size to 1200 bytes (#1477530)
- Call exit directly in clone (swbz#21512)
- assert: Suppress pedantic warning caused by statement expression (swbz#21242)
- x86-64: Use _dl_runtime_resolve_opt only with AVX512F (swbz#21871)
- powerpc: Fix logbl on power7 (swbz#21280)
- Avoid .symver on common symbols (swbz#21666)
- aarch64: Use hidden __GI__dl_argv in rtld startup code
2017-08-16 11:41:13 +02:00
Florian Weimer 77cd17d274 Disable multi-arch (IFUNC string functions) on i686 (#1471427) 2017-08-16 11:34:52 +02:00
Florian Weimer 2d4666e460 Use upstream default for multi-arch support
Drop binutils run-time conflict.  If we still want those, they should
be on glibc-devel, not the main package.
2017-08-16 11:34:27 +02:00
Florian Weimer 669790c2cf Auto-sync with upstream release/2.25/master
Upstream commit: 49f97e641e4e84a42246655d30adbc4756e67114

- x86-64: Align the stack in __tls_get_addr (#1440287)
2017-07-06 15:07:54 +02:00
Florian Weimer a2f7bb7876 Resolves: #1462820
Auto-sync with upstream release/2.25/master

Upstream commit: adc7e06fb412a2a1ee52f8cb788caf436335b9f3

- CVE-2017-1000366: Avoid large allocas in the dynamic linker (#1462820)
- Ignore and remove LD_HWCAP_MASK for AT_SECURE programs (swbz#21209)
- Correct collation rules for Malayalam (swbz#19922, swbz#19919)
- fork: Remove bogus parent PID assertions (swbz#21386)
2017-06-20 06:33:51 +02:00
Arjun Shankar 190fd58e63 Auto-sync with upstream release/2.25/master
Upstream commit: 34b6f41c14d09fe627c6a6224880d76d0959079e
2017-06-05 15:33:31 +02:00
Florian Weimer e43c7ab809 Auto-sync with upstream release/2.25/master
Upstream commit: 69e0a87cc4c570e3b7218392fc3e743b5bddcce2
2017-03-02 20:34:13 +01:00
71 changed files with 16101 additions and 565 deletions

View File

@ -0,0 +1,29 @@
commit d54bb9b1d3fd25779fba2c403003c5097ba9af73
Author: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
Date: Mon Jun 26 09:55:41 2017 -0300
Prevent an implicit int promotion in malloc/tst-alloc_buffer.c
According to ISO C11, section 6.5.3.3 "Unary arithmetic operators", the
result of the ~ operator is the bitwise complement of its (promoted)
operand.
This can lead to a comparison of a char with another integer type.
Tested on powerpc, powerpc64 and powerpc64le.
* malloc/tst-alloc_buffer.c (test_misaligned): Cast to char
before comparing with another char.
diff --git a/malloc/tst-alloc_buffer.c b/malloc/tst-alloc_buffer.c
index 1c143999c70180f7..9b2bd2046a12c0f2 100644
--- a/malloc/tst-alloc_buffer.c
+++ b/malloc/tst-alloc_buffer.c
@@ -429,7 +429,7 @@ test_misaligned (char pad)
}
/* Verify that padding was not overwritten. */
- TEST_VERIFY (backing[0] == ~pad);
+ TEST_VERIFY (backing[0] == (char) ~pad);
TEST_VERIFY (backing[SIZE + 1] == pad);
free (backing);
}

View File

@ -0,0 +1,17 @@
Add <bits/types/res_state.h> to simplify backports.
Introduced upstream as part of this commit:
commit 500b3a499fff61157db464a99f459c772d7eb6c0
Author: Zack Weinberg <zackw@panix.com>
Date: Wed Mar 22 09:55:25 2017 -0400
Remove __need_list_t and __need_res_state.
diff --git a/include/bits/types/res_state.h b/include/bits/types/res_state.h
new file mode 100644
index 0000000000000000..172103878d28a7ee
--- /dev/null
+++ b/include/bits/types/res_state.h
@@ -0,0 +1 @@
+#include <resolv.h>

View File

@ -21,10 +21,11 @@
# elf/rtld.c | 4 ----
# 4 files changed, 7 insertions(+), 10 deletions(-)
#
diff -urN glibc-2.20-205-ga39208b/elf/dl-init.c glibc-2.20-205-ga39208b.mod/elf/dl-init.c
--- glibc-2.20-205-ga39208b/elf/dl-init.c 2014-11-21 16:08:32.744913590 -0500
+++ glibc-2.20-205-ga39208b.mod/elf/dl-init.c 2014-11-21 16:09:42.485708197 -0500
@@ -119,8 +119,6 @@
Index: b/elf/dl-init.c
===================================================================
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -119,8 +119,6 @@ _dl_init (struct link_map *main_map, int
while (i-- > 0)
call_init (main_map->l_initfini[i], argc, argv, env);
@ -33,10 +34,11 @@ diff -urN glibc-2.20-205-ga39208b/elf/dl-init.c glibc-2.20-205-ga39208b.mod/elf/
_dl_starting_up = 0;
-#endif
}
diff -urN glibc-2.20-205-ga39208b/elf/dl-support.c glibc-2.20-205-ga39208b.mod/elf/dl-support.c
--- glibc-2.20-205-ga39208b/elf/dl-support.c 2014-11-19 14:35:03.000000000 -0500
+++ glibc-2.20-205-ga39208b.mod/elf/dl-support.c 2014-11-21 16:09:54.829671843 -0500
@@ -118,10 +118,8 @@
Index: b/elf/dl-support.c
===================================================================
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -117,10 +117,8 @@ struct r_scope_elem _dl_initial_searchli
.r_nlist = 1,
};
@ -47,18 +49,19 @@ diff -urN glibc-2.20-205-ga39208b/elf/dl-support.c glibc-2.20-205-ga39208b.mod/e
/* Random data provided by the kernel. */
void *_dl_random;
diff -urN glibc-2.20-205-ga39208b/elf/rtld.c glibc-2.20-205-ga39208b.mod/elf/rtld.c
--- glibc-2.20-205-ga39208b/elf/rtld.c 2014-11-21 16:08:32.745913587 -0500
+++ glibc-2.20-205-ga39208b.mod/elf/rtld.c 2014-11-21 16:09:05.614816785 -0500
@@ -107,7 +107,6 @@
struct audit_list *next;
} *audit_list;
Index: b/elf/rtld.c
===================================================================
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -214,7 +214,6 @@ audit_list_iter_next (struct audit_list_
return iter->previous->name;
}
-#ifndef HAVE_INLINED_SYSCALLS
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
must not be initialized to nonzero, because the unused dynamic
@@ -117,7 +116,6 @@
@@ -224,7 +223,6 @@ audit_list_iter_next (struct audit_list_
never be called. */
int _dl_starting_up = 0;
rtld_hidden_def (_dl_starting_up)
@ -66,7 +69,7 @@ diff -urN glibc-2.20-205-ga39208b/elf/rtld.c glibc-2.20-205-ga39208b.mod/elf/rtl
/* This is the structure which defines all variables global to ld.so
(except those which cannot be added for some reason). */
@@ -776,10 +774,8 @@
@@ -898,10 +896,8 @@ dl_main (const ElfW(Phdr) *phdr,
/* Process the environment variable which control the behaviour. */
process_envvars (&mode);

View File

@ -1,37 +0,0 @@
Builds with gcc 7.0 fail with:
../test-skeleton.c: In function legacy_test_function:
cc1: error: assuming signed overflow does not occur when \
assuming that (X - c) <= X is always true [-Werror=strict-overflow]
Ignoring this warning until the test or compiler is adjusted.
Disabled with -Wno-strict-overflow. Attempted -Wstrict-overflow=1,
but it still results in the same warning.
Index: glibc-2.24-661-g5653ab1/string/Makefile
===================================================================
--- glibc-2.24-661-g5653ab1.orig/string/Makefile
+++ glibc-2.24-661-g5653ab1/string/Makefile
@@ -71,7 +71,9 @@ include ../Rules
CFLAGS-inl-tester.c = -fno-builtin
CFLAGS-noinl-tester.c = -fno-builtin
CFLAGS-tst-strlen.c = -fno-builtin
-CFLAGS-stratcliff.c = -fno-builtin
+# Added '-Wno-strict-overflow' for gcc 7.0 until the test or compiler
+# is adjusted.
+CFLAGS-stratcliff.c = -fno-builtin -Wno-strict-overflow
CFLAGS-test-ffs.c = -fno-builtin
CFLAGS-tst-inlcall.c = -fno-builtin
CFLAGS-tst-xbzero-opt.c = -O3
Index: glibc-2.24-661-g5653ab1/wcsmbs/Makefile
===================================================================
--- glibc-2.24-661-g5653ab1.orig/wcsmbs/Makefile
+++ glibc-2.24-661-g5653ab1/wcsmbs/Makefile
@@ -102,3 +102,7 @@ CPPFLAGS += $(libio-mtsafe)
CPPFLAGS-wcstold_l.c = -I../stdlib
$(objpfx)tst-wcstod-nan-locale: $(libm)
+
+# Added '-Wno-strict-overflow' for gcc 7.0 until the test or compiler
+# is adjusted.
+CFLAGS-wcsatcliff.c = -Wno-strict-overflow

17
glibc-libc_diag.patch Normal file
View File

@ -0,0 +1,17 @@
Add <libc-diag.h> to simplify backports.
Added upstream as part of this commit:
commit e15f7de60c26bb75fe1923b17c5f0461164d1a41
Author: Zack Weinberg <zackw@panix.com>
Date: Sun Nov 20 20:46:30 2016 -0500
Split DIAG_* macros to new header libc-diag.h.
diff --git a/include/libc-diag.h b/include/libc-diag.h
new file mode 100644
index 0000000000000000..5876a41e8e5fcc15
--- /dev/null
+++ b/include/libc-diag.h
@@ -0,0 +1 @@
+#include <libc-internal.h>

View File

@ -0,0 +1,70 @@
commit 1e9522c61c7a544d59db32cb7fbbd42e6793d848
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Oct 5 18:14:27 2017 +0200
nscd: Eliminate compilation time dependency in the build output
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
index feb1c98ac31edcb8..b1bc81bd6d7d7fd1 100644
--- a/nscd/nscd_stat.c
+++ b/nscd/nscd_stat.c
@@ -35,9 +35,23 @@
# include <selinux/avc.h>
#endif /* HAVE_SELINUX */
+/* We use this to make sure the receiver is the same. The lower 16
+ bits are reserved for flags indicating compilation variants. This
+ version needs to be updated if the definition of struct statdata
+ changes. */
+#define STATDATA_VERSION 0x01020000U
-/* We use this to make sure the receiver is the same. */
-static const char compilation[21] = __DATE__ " " __TIME__;
+#ifdef HAVE_SELINUX
+# define STATDATA_VERSION_SELINUX_FLAG 0x0001U
+#else
+# define STATDATA_VERSION_SELINUX_FLAG 0x0000U
+#endif
+
+/* All flags affecting the struct statdata layout. */
+#define STATDATA_VERSION_FLAGS STATDATA_VERSION_SELINUX_FLAG
+
+/* The full version number for struct statdata. */
+#define STATDATA_VERSION_FULL (STATDATA_VERSION | STATDATA_VERSION_FLAGS)
/* Statistic data for one database. */
struct dbstat
@@ -68,10 +82,11 @@ struct dbstat
uintmax_t addfailed;
};
-/* Record for transmitting statistics. */
+/* Record for transmitting statistics. If this definition changes,
+ update STATDATA_VERSION above. */
struct statdata
{
- char version[sizeof (compilation)];
+ unsigned int version; /* Must be STATDATA_VERSION_FULL. */
int debug_level;
time_t runtime;
unsigned long int client_queued;
@@ -96,7 +111,7 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
memset (&data, 0, sizeof (data));
- memcpy (data.version, compilation, sizeof (compilation));
+ data.version = STATDATA_VERSION_FULL;
data.debug_level = debug_level;
data.runtime = time (NULL) - start_time;
data.client_queued = client_queued;
@@ -196,7 +211,7 @@ receive_print_stats (void)
/* Read as much data as we expect. */
if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
- || (memcmp (data.version, compilation, sizeof (compilation)) != 0
+ || (data.version != STATDATA_VERSION_FULL
/* Yes, this is an assignment! */
&& (errno = EINVAL)))
{

448
glibc-nss_compat.patch Normal file
View File

@ -0,0 +1,448 @@
commit 64d1e08ea822bf47cb2796ad0f727136227f983c
Author: Andreas Schwab <schwab@suse.de>
Date: Mon Oct 2 14:30:46 2017 +0200
Move nss_compat from nis to nss subdir and install it unconditionally
This has been tested that local lookup still works with and
without an installed libnss_nis, and that NIS lookup works when
libnss_nis is available.
diff --git a/nis/Makefile b/nis/Makefile
index d6be9e27fd8e90bc..81a51b6d7fc7cf55 100644
--- a/nis/Makefile
+++ b/nis/Makefile
@@ -34,7 +34,7 @@ databases = proto service hosts network grp pwd rpc ethers \
spwd netgrp alias publickey
# Specify rules for the nss_* modules.
-services := nis nisplus compat
+services := nis nisplus
extra-libs = libnsl $(services:%=libnss_%)
# These libraries will be built in the `others' pass rather than
@@ -57,9 +57,6 @@ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
nis_findserv nis_callback nis_clone_dir nis_clone_obj\
nis_clone_res nss-default
-libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups)
-libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
-
libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \
nss-nis
libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes))
@@ -71,7 +68,6 @@ libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes))
include ../Rules
-$(objpfx)libnss_compat.so: $(objpfx)libnsl.so$(libnsl.so-version)
$(objpfx)libnss_nis.so: $(objpfx)libnsl.so$(libnsl.so-version) \
$(common-objpfx)nss/libnss_files.so
$(objpfx)libnss_nisplus.so: $(objpfx)libnsl.so$(libnsl.so-version)
diff --git a/nis/Versions b/nis/Versions
index ef9a5124174ec0e8..90d3d9dfaa3d853b 100644
--- a/nis/Versions
+++ b/nis/Versions
@@ -63,17 +63,6 @@ libnsl {
}
}
-libnss_compat {
- GLIBC_PRIVATE {
- _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent;
- _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r;
- _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r;
- _nss_compat_getspent_r; _nss_compat_getspnam_r;
- _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent;
- _nss_compat_initgroups_dyn;
- }
-}
-
libnss_nis {
GLIBC_PRIVATE {
_nss_nis_endaliasent; _nss_nis_endetherent; _nss_nis_endgrent;
diff --git a/nss/Makefile b/nss/Makefile
index de6c47a1dbab9879..f0a6e4877fac6bf7 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -61,7 +61,7 @@ tests += tst-cancel-getpwuid_r
endif
# Specify rules for the nss_* modules. We have some services.
-services := files db
+services := files db compat
extra-libs = $(services:%=libnss_%)
# These libraries will be built in the `others' pass rather than
@@ -84,11 +84,15 @@ libnss_db-routines := $(libnss_db-dbs) db-open db-init hash-string
generated += $(filter-out db-alias.c db-netgrp.c, \
$(addsuffix .c,$(libnss_db-dbs)))
+libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) \
+ nisdomain
+
install-others += $(inst_vardbdir)/Makefile
# Build static module into libc if requested
libnss_files-inhibit-o = $(filter-out .os,$(object-suffixes))
libnss_db-inhibit-o = $(filter-out .os,$(object-suffixes))
+libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
ifeq ($(build-static-nss),yes)
routines += $(libnss_files-routines)
static-only-routines += $(libnss_files-routines)
diff --git a/nss/Versions b/nss/Versions
index f8ababccc74d1dd2..14c2571468169e4d 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -160,3 +160,14 @@ libnss_db {
_nss_db_init;
}
}
+
+libnss_compat {
+ GLIBC_PRIVATE {
+ _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent;
+ _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r;
+ _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r;
+ _nss_compat_getspent_r; _nss_compat_getspnam_r;
+ _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent;
+ _nss_compat_initgroups_dyn;
+ }
+}
diff --git a/nis/nss_compat/compat-grp.c b/nss/nss_compat/compat-grp.c
similarity index 97%
rename from nis/nss_compat/compat-grp.c
rename to nss/nss_compat/compat-grp.c
index e830a2f0a2a1f169..fecbd35f270a7943 100644
--- a/nis/nss_compat/compat-grp.c
+++ b/nss/nss_compat/compat-grp.c
@@ -24,7 +24,6 @@
#include <nsswitch.h>
#include <stdio_ext.h>
#include <string.h>
-#include <rpc/types.h>
#include <libc-lock.h>
#include <kernel-features.h>
@@ -58,14 +57,14 @@ struct blacklist_t
struct ent_t
{
- bool_t files;
+ bool files;
enum nss_status setent_status;
FILE *stream;
struct blacklist_t blacklist;
};
typedef struct ent_t ent_t;
-static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
+static ent_t ext_ent = { true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
/* Protect global state against multiple changers. */
__libc_lock_define_initialized (static, lock)
@@ -85,7 +84,7 @@ int __compat_have_cloexec;
/* Prototypes for local functions. */
static void blacklist_store_name (const char *, ent_t *);
-static int in_blacklist (const char *, int, ent_t *);
+static bool in_blacklist (const char *, int, ent_t *);
/* Initialize the NSS interface/functions. The calling function must
hold the lock. */
@@ -107,7 +106,7 @@ internal_setgrent (ent_t *ent, int stayopen, int needent)
{
enum nss_status status = NSS_STATUS_SUCCESS;
- ent->files = TRUE;
+ ent->files = true;
if (ent->blacklist.data != NULL)
{
@@ -369,7 +368,7 @@ getgrent_next_file (struct group *result, ent_t *ent,
/* +:... */
if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
{
- ent->files = FALSE;
+ ent->files = false;
return getgrent_next_nss (result, ent, buffer, buflen, errnop);
}
@@ -514,7 +513,7 @@ enum nss_status
_nss_compat_getgrnam_r (const char *name, struct group *grp,
char *buffer, size_t buflen, int *errnop)
{
- ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
+ ent_t ent = { true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
enum nss_status result;
if (name[0] == '-' || name[0] == '+')
@@ -646,7 +645,7 @@ enum nss_status
_nss_compat_getgrgid_r (gid_t gid, struct group *grp,
char *buffer, size_t buflen, int *errnop)
{
- ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
+ ent_t ent = { true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
enum nss_status result;
__libc_lock_lock (lock);
@@ -713,15 +712,15 @@ blacklist_store_name (const char *name, ent_t *ent)
return;
}
-/* returns TRUE if ent->blacklist contains name, else FALSE */
-static bool_t
+/* Return whether ent->blacklist contains name. */
+static bool
in_blacklist (const char *name, int namelen, ent_t *ent)
{
char buf[namelen + 3];
char *cp;
if (ent->blacklist.data == NULL)
- return FALSE;
+ return false;
buf[0] = '|';
cp = stpcpy (&buf[1], name);
diff --git a/nis/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c
similarity index 98%
rename from nis/nss_compat/compat-initgroups.c
rename to nss/nss_compat/compat-initgroups.c
index cc3db7889ba289db..a603a33e13dec134 100644
--- a/nis/nss_compat/compat-initgroups.c
+++ b/nss/nss_compat/compat-initgroups.c
@@ -24,7 +24,6 @@
#include <stdio_ext.h>
#include <string.h>
#include <unistd.h>
-#include <rpc/types.h>
#include <sys/param.h>
#include <nsswitch.h>
#include <libc-lock.h>
@@ -93,7 +92,7 @@ extern int __compat_have_cloexec;
/* Prototypes for local functions. */
static void blacklist_store_name (const char *, ent_t *);
-static int in_blacklist (const char *, int, ent_t *);
+static bool in_blacklist (const char *, int, ent_t *);
/* Initialize the NSS interface/functions. The calling function must
hold the lock. */
@@ -602,15 +601,15 @@ blacklist_store_name (const char *name, ent_t *ent)
return;
}
-/* returns TRUE if ent->blacklist contains name, else FALSE */
-static bool_t
+/* Return whether ent->blacklist contains name. */
+static bool
in_blacklist (const char *name, int namelen, ent_t *ent)
{
char buf[namelen + 3];
char *cp;
if (ent->blacklist.data == NULL)
- return FALSE;
+ return false;
buf[0] = '|';
cp = stpcpy (&buf[1], name);
diff --git a/nis/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c
similarity index 99%
rename from nis/nss_compat/compat-pwd.c
rename to nss/nss_compat/compat-pwd.c
index 28ae7fba84db8617..577af3a0fd8b50c3 100644
--- a/nis/nss_compat/compat-pwd.c
+++ b/nss/nss_compat/compat-pwd.c
@@ -25,12 +25,11 @@
#include <pwd.h>
#include <stdio_ext.h>
#include <string.h>
-#include <rpc/types.h>
-#include <rpcsvc/ypclnt.h>
#include <libc-lock.h>
#include <kernel-features.h>
#include "netgroup.h"
+#include "nisdomain.h"
static service_user *ni;
static enum nss_status (*nss_setpwent) (int stayopen);
@@ -95,7 +94,7 @@ extern int __compat_have_cloexec;
/* Prototypes for local functions. */
static void blacklist_store_name (const char *, ent_t *);
-static int in_blacklist (const char *, int, ent_t *);
+static bool in_blacklist (const char *, int, ent_t *);
/* Initialize the NSS interface/functions. The calling function must
hold the lock. */
@@ -394,7 +393,7 @@ getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent,
if (domain != NULL)
{
if (curdomain == NULL
- && yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
+ && __nss_get_default_domain (&curdomain) != 0)
{
__internal_endnetgrent (&ent->netgrdata);
ent->netgroup = false;
@@ -1162,15 +1161,15 @@ blacklist_store_name (const char *name, ent_t *ent)
return;
}
-/* Returns TRUE if ent->blacklist contains name, else FALSE. */
-static bool_t
+/* Returns whether ent->blacklist contains name. */
+static bool
in_blacklist (const char *name, int namelen, ent_t *ent)
{
char buf[namelen + 3];
char *cp;
if (ent->blacklist.data == NULL)
- return FALSE;
+ return false;
buf[0] = '|';
cp = stpcpy (&buf[1], name);
diff --git a/nis/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c
similarity index 98%
rename from nis/nss_compat/compat-spwd.c
rename to nss/nss_compat/compat-spwd.c
index 550444cd800743bb..b96328a7dcb82953 100644
--- a/nis/nss_compat/compat-spwd.c
+++ b/nss/nss_compat/compat-spwd.c
@@ -25,12 +25,11 @@
#include <shadow.h>
#include <stdio_ext.h>
#include <string.h>
-#include <rpc/types.h>
-#include <rpcsvc/ypclnt.h>
#include <libc-lock.h>
#include <kernel-features.h>
#include "netgroup.h"
+#include "nisdomain.h"
static service_user *ni;
static enum nss_status (*nss_setspent) (int stayopen);
@@ -92,7 +91,7 @@ extern int __compat_have_cloexec;
/* Prototypes for local functions. */
static void blacklist_store_name (const char *, ent_t *);
-static int in_blacklist (const char *, int, ent_t *);
+static bool in_blacklist (const char *, int, ent_t *);
/* Initialize the NSS interface/functions. The calling function must
hold the lock. */
@@ -354,7 +353,7 @@ getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
if (domain != NULL)
{
if (curdomain == NULL
- && yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
+ && __nss_get_default_domain (&curdomain) != 0)
{
__internal_endnetgrent (&ent->netgrdata);
ent->netgroup = false;
@@ -888,8 +887,8 @@ blacklist_store_name (const char *name, ent_t *ent)
}
-/* Returns TRUE if ent->blacklist contains name, else FALSE. */
-static bool_t
+/* Returns whether ent->blacklist contains name. */
+static bool
in_blacklist (const char *name, int namelen, ent_t *ent)
{
char buf[namelen + 3];
diff --git a/nss/nss_compat/nisdomain.c b/nss/nss_compat/nisdomain.c
new file mode 100644
index 0000000000000000..220ae27234705855
--- /dev/null
+++ b/nss/nss_compat/nisdomain.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libc-lock.h>
+#include "nisdomain.h"
+
+#define MAXDOMAINNAMELEN 1024
+
+static char domainname[MAXDOMAINNAMELEN];
+
+__libc_lock_define_initialized (static, domainname_lock)
+
+int
+__nss_get_default_domain (char **outdomain)
+{
+ int result = 0;
+ *outdomain = NULL;
+
+ __libc_lock_lock (domainname_lock);
+
+ if (domainname[0] != '\0')
+ {
+ if (getdomainname (domainname, MAXDOMAINNAMELEN) < 0)
+ result = errno;
+ else if (strcmp (domainname, "(none)") == 0)
+ {
+ /* If domainname is not set, some systems will return "(none)" */
+ domainname[0] = '\0';
+ result = ENOENT;
+ }
+ else
+ *outdomain = domainname;
+ }
+ else
+ *outdomain = domainname;
+
+ __libc_lock_unlock (domainname_lock);
+
+ return result;
+}
diff --git a/nss/nss_compat/nisdomain.h b/nss/nss_compat/nisdomain.h
new file mode 100644
index 0000000000000000..314f3f7c069835af
--- /dev/null
+++ b/nss/nss_compat/nisdomain.h
@@ -0,0 +1,20 @@
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Set OUTDOMAIN to a pointer to the current NIS domain name, or NULL if
+ not set. Return zero on success, an error number on failure. */
+extern int __nss_get_default_domain (char **outdomain);

271
glibc-rh1315108-glob.patch Normal file
View File

@ -0,0 +1,271 @@
commit 5a79f97554af6f2eb0a654f844b3d1f56937064d
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon Sep 4 17:00:03 2017 -0300
posix: Fix getpwnam_r usage (BZ #1062)
This patch fixes longstanding misuse of errno after getpwnam_r,
which returns an error number rather than setting errno. This is
sync with gnulib commit 5db9301.
Checked on x86_64-linux-gnu and on a build using build-many-glibcs.py
for all major architectures.
[BZ #1062]
* posix/glob.c (glob): Port recent patches to platforms
lacking getpwnam_r.
(glob): Fix longstanding misuse of errno after getpwnam_r, which
returns an error number rather than setting errno.
diff --git a/posix/glob.c b/posix/glob.c
index c761c0861ddb49ea..70434745f57f8ff5 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -15,10 +15,6 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#ifndef _LIBC
-# include <config.h>
-#endif
-
#include <glob.h>
#include <errno.h>
@@ -39,10 +35,6 @@
#endif
#include <errno.h>
-#ifndef __set_errno
-# define __set_errno(val) errno = (val)
-#endif
-
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
@@ -78,12 +70,8 @@
#include <flexmember.h>
#include <glob_internal.h>
+#include <scratch_buffer.h>
-#ifdef _SC_GETPW_R_SIZE_MAX
-# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
-#else
-# define GETPW_R_SIZE_MAX() (-1)
-#endif
#ifdef _SC_LOGIN_NAME_MAX
# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX)
#else
@@ -651,97 +639,36 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
if (success)
{
struct passwd *p;
- char *malloc_pwtmpbuf = NULL;
- char *pwtmpbuf;
+ struct scratch_buffer pwtmpbuf;
+ scratch_buffer_init (&pwtmpbuf);
# if defined HAVE_GETPWNAM_R || defined _LIBC
- long int pwbuflenmax = GETPW_R_SIZE_MAX ();
- size_t pwbuflen = pwbuflenmax;
struct passwd pwbuf;
- int save = errno;
-# ifndef _LIBC
- if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
- /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
- Try a moderate value. */
- pwbuflen = 1024;
-# endif
- if (glob_use_alloca (alloca_used, pwbuflen))
- pwtmpbuf = alloca_account (pwbuflen, alloca_used);
- else
+ while (getpwnam_r (name, &pwbuf,
+ pwtmpbuf.data, pwtmpbuf.length, &p)
+ == ERANGE)
{
- pwtmpbuf = malloc (pwbuflen);
- if (pwtmpbuf == NULL)
+ if (!scratch_buffer_grow (&pwtmpbuf))
{
- if (__glibc_unlikely (malloc_name))
- free (name);
retval = GLOB_NOSPACE;
goto out;
}
- malloc_pwtmpbuf = pwtmpbuf;
- }
-
- while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
- != 0)
- {
- size_t newlen;
- bool v;
- if (errno != ERANGE)
- {
- p = NULL;
- break;
- }
- v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
- if (!v && malloc_pwtmpbuf == NULL
- && glob_use_alloca (alloca_used, newlen))
- pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
- newlen, alloca_used);
- else
- {
- char *newp = (v ? NULL
- : realloc (malloc_pwtmpbuf, newlen));
- if (newp == NULL)
- {
- free (malloc_pwtmpbuf);
- if (__glibc_unlikely (malloc_name))
- free (name);
- retval = GLOB_NOSPACE;
- goto out;
- }
- malloc_pwtmpbuf = pwtmpbuf = newp;
- }
- pwbuflen = newlen;
- __set_errno (save);
}
# else
p = getpwnam (name);
# endif
- if (__glibc_unlikely (malloc_name))
- free (name);
if (p != NULL)
{
- if (malloc_pwtmpbuf == NULL)
- home_dir = p->pw_dir;
- else
+ home_dir = strdup (p->pw_dir);
+ malloc_home_dir = 1;
+ if (home_dir == NULL)
{
- size_t home_dir_len = strlen (p->pw_dir) + 1;
- if (glob_use_alloca (alloca_used, home_dir_len))
- home_dir = alloca_account (home_dir_len,
- alloca_used);
- else
- {
- home_dir = malloc (home_dir_len);
- if (home_dir == NULL)
- {
- free (pwtmpbuf);
- retval = GLOB_NOSPACE;
- goto out;
- }
- malloc_home_dir = 1;
- }
- memcpy (home_dir, p->pw_dir, home_dir_len);
+ scratch_buffer_free (&pwtmpbuf);
+ retval = GLOB_NOSPACE;
+ goto out;
}
}
- free (malloc_pwtmpbuf);
+ scratch_buffer_free (&pwtmpbuf);
}
else
{
@@ -878,61 +805,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
/* Look up specific user's home directory. */
{
struct passwd *p;
- char *malloc_pwtmpbuf = NULL;
+ struct scratch_buffer pwtmpbuf;
+ scratch_buffer_init (&pwtmpbuf);
+
# if defined HAVE_GETPWNAM_R || defined _LIBC
- long int buflenmax = GETPW_R_SIZE_MAX ();
- size_t buflen = buflenmax;
- char *pwtmpbuf;
struct passwd pwbuf;
- int save = errno;
-
-# ifndef _LIBC
- if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
- /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
- moderate value. */
- buflen = 1024;
-# endif
- if (glob_use_alloca (alloca_used, buflen))
- pwtmpbuf = alloca_account (buflen, alloca_used);
- else
+
+ while (getpwnam_r (user_name, &pwbuf,
+ pwtmpbuf.data, pwtmpbuf.length, &p)
+ == ERANGE)
{
- pwtmpbuf = malloc (buflen);
- if (pwtmpbuf == NULL)
+ if (!scratch_buffer_grow (&pwtmpbuf))
{
- nomem_getpw:
- if (__glibc_unlikely (malloc_user_name))
- free (user_name);
retval = GLOB_NOSPACE;
goto out;
}
- malloc_pwtmpbuf = pwtmpbuf;
- }
-
- while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
- {
- size_t newlen;
- bool v;
- if (errno != ERANGE)
- {
- p = NULL;
- break;
- }
- v = size_add_wrapv (buflen, buflen, &newlen);
- if (!v && malloc_pwtmpbuf == NULL
- && glob_use_alloca (alloca_used, newlen))
- pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
- newlen, alloca_used);
- else
- {
- char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
- if (newp == NULL)
- {
- free (malloc_pwtmpbuf);
- goto nomem_getpw;
- }
- malloc_pwtmpbuf = pwtmpbuf = newp;
- }
- __set_errno (save);
}
# else
p = getpwnam (user_name);
@@ -959,7 +846,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
dirname = malloc (home_len + rest_len + 1);
if (dirname == NULL)
{
- free (malloc_pwtmpbuf);
+ scratch_buffer_free (&pwtmpbuf);
retval = GLOB_NOSPACE;
goto out;
}
@@ -970,13 +857,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
dirlen = home_len + rest_len;
dirname_modified = 1;
-
- free (malloc_pwtmpbuf);
}
else
{
- free (malloc_pwtmpbuf);
-
if (flags & GLOB_TILDE_CHECK)
{
/* We have to regard it as an error if we cannot find the
@@ -985,6 +868,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
goto out;
}
}
+ scratch_buffer_free (&pwtmpbuf);
}
#endif /* !WINDOWS32 */
}

View File

@ -156,16 +156,6 @@ Date: Sun Mar 1 19:48:31 2015 +0100
* posix/wordexp.c (parse_tilde): Use struct scratch_buffer
instead of extend_alloca.
commit 7b4c16db30304b83a5d1e913d1a8f7e90a8c398c
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:49:50 2015 +0100
glob: Rewrite to use struct scratch_buffer instead of extend_alloca
[BZ #18023]
* posix/glob.c (glob): Use struct scratch_buffer instead of
extend_alloca.
commit 683543bbb3e2c1b17554c4096d00c2980f39a802
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 23:22:45 2015 +0100
@ -249,8 +239,9 @@ Date: Sun Mar 1 23:22:45 2015 +0100
[BZ #18023]
* include/alloca.h (stackinfo_alloca_round, extend_alloca,
extend_alloca_account): Remove.
Index: b/elf/dl-deps.c
===================================================================
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 1b8bac65932a7713..bc59f0ff7b4d7c61 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -27,6 +27,7 @@
@ -261,7 +252,7 @@ Index: b/elf/dl-deps.c
#include <dl-dst.h>
@@ -184,9 +185,8 @@ _dl_map_object_deps (struct link_map *ma
@@ -184,9 +185,8 @@ _dl_map_object_deps (struct link_map *map,
/* Pointer to last unique object. */
tail = &known[nlist - 1];
@ -273,7 +264,7 @@ Index: b/elf/dl-deps.c
/* Process each element of the search list, loading each of its
auxiliary objects and immediate dependencies. Auxiliary objects
@@ -217,13 +217,12 @@ _dl_map_object_deps (struct link_map *ma
@@ -217,13 +217,12 @@ _dl_map_object_deps (struct link_map *map,
if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
&& l != map && l->l_ldnum > 0)
{
@ -293,7 +284,7 @@ Index: b/elf/dl-deps.c
}
if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
@@ -463,8 +462,11 @@ _dl_map_object_deps (struct link_map *ma
@@ -463,8 +462,11 @@ _dl_map_object_deps (struct link_map *map,
struct link_map **l_initfini = (struct link_map **)
malloc ((2 * nneeded + 1) * sizeof needed[0]);
if (l_initfini == NULL)
@ -307,7 +298,7 @@ Index: b/elf/dl-deps.c
l_initfini[0] = l;
memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
memcpy (&l_initfini[nneeded + 1], l_initfini,
@@ -482,6 +484,8 @@ _dl_map_object_deps (struct link_map *ma
@@ -482,6 +484,8 @@ _dl_map_object_deps (struct link_map *map,
}
out:
@ -316,8 +307,8 @@ Index: b/elf/dl-deps.c
if (errno == 0 && errno_saved != 0)
__set_errno (errno_saved);
Index: b/include/alloca.h
===================================================================
diff --git a/include/alloca.h b/include/alloca.h
index fd90664f0a17cd6d..c0b83954436ed4c1 100644
--- a/include/alloca.h
+++ b/include/alloca.h
@@ -23,57 +23,17 @@ libc_hidden_proto (__libc_alloca_cutoff)
@ -378,11 +369,11 @@ Index: b/include/alloca.h
#endif
# endif /* !_ISOMAC */
Index: b/nis/nss_compat/compat-initgroups.c
===================================================================
diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c
index 1b37e0c295f481df..cc3db7889ba289db 100644
--- a/nis/nss_compat/compat-initgroups.c
+++ b/nis/nss_compat/compat-initgroups.c
@@ -310,7 +310,6 @@ getgrent_next_nss (ent_t *ent, char *buf
@@ -310,7 +310,6 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
overwrite the pointer with one to a bigger buffer. */
char *tmpbuf = buffer;
size_t tmplen = buflen;
@ -390,7 +381,7 @@ Index: b/nis/nss_compat/compat-initgroups.c
for (int i = 0; i < mystart; i++)
{
@@ -319,29 +318,26 @@ getgrent_next_nss (ent_t *ent, char *buf
@@ -319,29 +318,26 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
== NSS_STATUS_TRYAGAIN
&& *errnop == ERANGE)
{
@ -440,7 +431,7 @@ Index: b/nis/nss_compat/compat-initgroups.c
}
if (__builtin_expect (status != NSS_STATUS_NOTFOUND, 1))
@@ -369,7 +365,7 @@ getgrent_next_nss (ent_t *ent, char *buf
@@ -369,7 +365,7 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
status = NSS_STATUS_NOTFOUND;
done:
@ -449,8 +440,8 @@ Index: b/nis/nss_compat/compat-initgroups.c
free (tmpbuf);
}
Index: b/nis/nss_nis/nis-initgroups.c
===================================================================
diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c
index 3784c101f7ee31aa..c872b32e15f55e3d 100644
--- a/nis/nss_nis/nis-initgroups.c
+++ b/nis/nss_nis/nis-initgroups.c
@@ -16,7 +16,6 @@
@ -469,7 +460,7 @@ Index: b/nis/nss_nis/nis-initgroups.c
#include "nss-nis.h"
#include <libnsl.h>
@@ -120,27 +120,30 @@ internal_getgrent_r (struct group *grp,
@@ -120,27 +120,30 @@ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
static int
get_uid (const char *user, uid_t *uidp)
{
@ -504,7 +495,7 @@ Index: b/nis/nss_nis/nis-initgroups.c
return 1;
}
@@ -254,8 +257,6 @@ _nss_nis_initgroups_dyn (const char *use
@@ -254,8 +257,6 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
}
struct group grpbuf, *g;
@ -513,7 +504,7 @@ Index: b/nis/nss_nis/nis-initgroups.c
enum nss_status status;
intern_t intern = { NULL, NULL, 0 };
gid_t *groups = *groupsp;
@@ -264,15 +265,21 @@ _nss_nis_initgroups_dyn (const char *use
@@ -264,15 +265,21 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
if (status != NSS_STATUS_SUCCESS)
return status;
@ -546,8 +537,8 @@ Index: b/nis/nss_nis/nis-initgroups.c
return status;
}
Index: b/nscd/aicache.c
===================================================================
diff --git a/nscd/aicache.c b/nscd/aicache.c
index 7bf4131979451040..ea29b1c3d99bb530 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -27,6 +27,7 @@
@ -558,7 +549,7 @@ Index: b/nscd/aicache.c
#include "dbg_log.h"
#include "nscd.h"
@@ -113,10 +114,13 @@ addhstaiX (struct database_dyn *db, int
@@ -113,10 +114,13 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
int old_res_options = _res.options;
_res.options &= ~DEPRECATED_RES_USE_INET6;
@ -576,7 +567,7 @@ Index: b/nscd/aicache.c
int32_t ttl = INT32_MAX;
ssize_t total = 0;
char *key_copy = NULL;
@@ -129,6 +133,7 @@ addhstaiX (struct database_dyn *db, int
@@ -129,6 +133,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
int naddrs = 0;
size_t addrslen = 0;
@ -584,7 +575,7 @@ Index: b/nscd/aicache.c
char *canon = NULL;
size_t canonlen;
@@ -143,12 +148,17 @@ addhstaiX (struct database_dyn *db, int
@@ -143,12 +148,17 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
at = &atmem;
rc6 = 0;
herrno = 0;
@ -604,7 +595,7 @@ Index: b/nscd/aicache.c
}
if (rc6 != 0 && herrno == NETDB_INTERNAL)
@@ -226,41 +236,38 @@ addhstaiX (struct database_dyn *db, int
@@ -226,41 +236,38 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
while (1)
{
rc6 = 0;
@ -662,7 +653,7 @@ Index: b/nscd/aicache.c
}
if (rc4 != 0 && herrno == NETDB_INTERNAL)
@@ -286,13 +293,11 @@ addhstaiX (struct database_dyn *db, int
@@ -286,13 +293,11 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
cfct = __nss_lookup_function (nip, "getcanonname_r");
if (cfct != NULL)
{
@ -678,7 +669,7 @@ Index: b/nscd/aicache.c
== NSS_STATUS_SUCCESS)
canon = s;
else
@@ -321,18 +326,20 @@ addhstaiX (struct database_dyn *db, int
@@ -321,18 +326,20 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
addrfamily = AF_INET6;
}
@ -715,11 +706,11 @@ Index: b/nscd/aicache.c
return timeout;
}
Index: b/nscd/connections.c
===================================================================
diff --git a/nscd/connections.c b/nscd/connections.c
index 26d2c0091b8f320d..9615c159285f0044 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1353,64 +1353,83 @@ request from '%s' [%ld] not handled due
@@ -1353,64 +1353,83 @@ request from '%s' [%ld] not handled due to missing permission"),
}
}
@ -739,20 +730,19 @@ Index: b/nscd/connections.c
- size_t readlen = 0;
int fd = open ("/proc/self/cmdline", O_RDONLY);
- if (fd == -1)
- {
- dbg_log (_("\
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
- strerror (errno));
-
- paranoia = 0;
- return;
+ if (fd < 0)
+ return NULL;
+ size_t current = 0;
+ size_t limit = 1024;
+ char *buffer = malloc (limit);
+ if (buffer == NULL)
+ {
{
- dbg_log (_("\
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
- strerror (errno));
-
- paranoia = 0;
- return;
+ close (fd);
+ errno = ENOMEM;
+ return NULL;
@ -842,7 +832,7 @@ Index: b/nscd/connections.c
{
argv[argc++] = cp;
cp = (char *) rawmemchr (cp, '\0') + 1;
@@ -1427,6 +1446,7 @@ cannot change to old UID: %s; disabling
@@ -1427,6 +1446,7 @@ cannot change to old UID: %s; disabling paranoia mode"),
strerror (errno));
paranoia = 0;
@ -850,7 +840,7 @@ Index: b/nscd/connections.c
return;
}
@@ -1438,6 +1458,7 @@ cannot change to old GID: %s; disabling
@@ -1438,6 +1458,7 @@ cannot change to old GID: %s; disabling paranoia mode"),
ignore_value (setuid (server_uid));
paranoia = 0;
@ -858,7 +848,7 @@ Index: b/nscd/connections.c
return;
}
}
@@ -1455,6 +1476,7 @@ cannot change to old working directory:
@@ -1455,6 +1476,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
ignore_value (setgid (server_gid));
}
paranoia = 0;
@ -866,7 +856,7 @@ Index: b/nscd/connections.c
return;
}
@@ -1503,6 +1525,7 @@ cannot change to old working directory:
@@ -1503,6 +1525,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
dbg_log (_("cannot change current working directory to \"/\": %s"),
strerror (errno));
paranoia = 0;
@ -874,8 +864,8 @@ Index: b/nscd/connections.c
/* Reenable the databases. */
time_t now = time (NULL);
Index: b/nscd/grpcache.c
===================================================================
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index d2ad53509db97bdf..a71036512048dd81 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -16,7 +16,6 @@
@ -894,7 +884,7 @@ Index: b/nscd/grpcache.c
#include "nscd.h"
#include "dbg_log.h"
@@ -448,12 +448,12 @@ addgrbyX (struct database_dyn *db, int f
@@ -448,12 +448,12 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
look again in the table whether the dataset is now available. We
simply insert it. It does not matter if it is in there twice. The
pruning function only will look at the timestamp. */
@ -910,7 +900,7 @@ Index: b/nscd/grpcache.c
if (__glibc_unlikely (debug_level > 0))
{
@@ -463,43 +463,24 @@ addgrbyX (struct database_dyn *db, int f
@@ -463,43 +463,24 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
}
@ -969,8 +959,8 @@ Index: b/nscd/grpcache.c
return timeout;
}
Index: b/nscd/hstcache.c
===================================================================
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index 9f6ce979ac333265..d0af99893dd17b9f 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -34,6 +34,7 @@
@ -981,7 +971,7 @@ Index: b/nscd/hstcache.c
#include "nscd.h"
#include "dbg_log.h"
@@ -463,11 +464,8 @@ addhstbyX (struct database_dyn *db, int
@@ -463,11 +464,8 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
look again in the table whether the dataset is now available. We
simply insert it. It does not matter if it is in there twice. The
pruning function only will look at the timestamp. */
@ -993,7 +983,7 @@ Index: b/nscd/hstcache.c
int errval = 0;
int32_t ttl = INT32_MAX;
@@ -487,46 +485,30 @@ addhstbyX (struct database_dyn *db, int
@@ -487,46 +485,30 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
}
@ -1059,8 +1049,8 @@ Index: b/nscd/hstcache.c
return timeout;
}
Index: b/nscd/pwdcache.c
===================================================================
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index 721f4c617b0bb74a..9349b54df4241ad5 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -16,7 +16,6 @@
@ -1079,7 +1069,7 @@ Index: b/nscd/pwdcache.c
#include "nscd.h"
#include "dbg_log.h"
@@ -426,12 +426,11 @@ addpwbyX (struct database_dyn *db, int f
@@ -426,12 +426,11 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
look again in the table whether the dataset is now available. We
simply insert it. It does not matter if it is in there twice. The
pruning function only will look at the timestamp. */
@ -1094,7 +1084,7 @@ Index: b/nscd/pwdcache.c
if (__glibc_unlikely (debug_level > 0))
{
@@ -441,45 +440,26 @@ addpwbyX (struct database_dyn *db, int f
@@ -441,45 +440,26 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
dbg_log (_("Reloading \"%s\" in password cache!"), keystr);
}
@ -1155,8 +1145,8 @@ Index: b/nscd/pwdcache.c
return timeout;
}
Index: b/nscd/servicescache.c
===================================================================
diff --git a/nscd/servicescache.c b/nscd/servicescache.c
index 131ba6ddcc1a5f7a..549e9a446816d760 100644
--- a/nscd/servicescache.c
+++ b/nscd/servicescache.c
@@ -16,7 +16,6 @@
@ -1175,7 +1165,7 @@ Index: b/nscd/servicescache.c
#include "nscd.h"
#include "dbg_log.h"
@@ -374,12 +374,11 @@ addservbyX (struct database_dyn *db, int
@@ -374,12 +374,11 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
look again in the table whether the dataset is now available. We
simply insert it. It does not matter if it is in there twice. The
pruning function only will look at the timestamp. */
@ -1190,7 +1180,7 @@ Index: b/nscd/servicescache.c
if (__glibc_unlikely (debug_level > 0))
{
@@ -389,43 +388,24 @@ addservbyX (struct database_dyn *db, int
@@ -389,43 +388,24 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
dbg_log (_("Reloading \"%s\" in services cache!"), key);
}
@ -1249,8 +1239,8 @@ Index: b/nscd/servicescache.c
return timeout;
}
Index: b/nss/getent.c
===================================================================
diff --git a/nss/getent.c b/nss/getent.c
index 8f8c3fe80a2cfea6..5654c5f67c4f118c 100644
--- a/nss/getent.c
+++ b/nss/getent.c
@@ -39,6 +39,7 @@
@ -1303,7 +1293,7 @@ Index: b/nss/getent.c
printf ("%-21s", key[i]);
for (int j = 0; j < n; ++j)
if (grps[j] != -1)
@@ -508,6 +513,8 @@ initgroups_keys (int number, char *key[]
@@ -508,6 +513,8 @@ initgroups_keys (int number, char *key[])
putchar_unlocked ('\n');
}
@ -1312,111 +1302,8 @@ Index: b/nss/getent.c
return 0;
}
Index: b/nss/nss_files/files-hosts.c
===================================================================
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -22,7 +22,7 @@
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv/resolv-internal.h>
-
+#include <scratch_buffer.h>
/* Get implementation for some internal functions. */
#include "../resolv/mapv4v6addr.h"
@@ -145,15 +145,12 @@ _nss_files_gethostbyname3_r (const char
&& _res_hconf.flags & HCONF_FLAG_MULTI)
{
/* We have to get all host entries from the file. */
- size_t tmp_buflen = MIN (buflen, 4096);
- char tmp_buffer_stack[tmp_buflen]
- __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));
- char *tmp_buffer = tmp_buffer_stack;
struct hostent tmp_result_buf;
int naddrs = 1;
int naliases = 0;
char *bufferend;
- bool tmp_buffer_malloced = false;
+ struct scratch_buffer tmpbuf;
+ scratch_buffer_init (&tmpbuf);
while (result->h_aliases[naliases] != NULL)
++naliases;
@@ -161,9 +158,9 @@ _nss_files_gethostbyname3_r (const char
bufferend = (char *) &result->h_aliases[naliases + 1];
again:
- while ((status = internal_getent (stream, &tmp_result_buf, tmp_buffer,
- tmp_buflen, errnop, herrnop, af,
- flags))
+ while ((status = internal_getent (stream, &tmp_result_buf,
+ tmpbuf.data, tmpbuf.length,
+ errnop, herrnop, af, flags))
== NSS_STATUS_SUCCESS)
{
int matches = 1;
@@ -287,54 +284,13 @@ _nss_files_gethostbyname3_r (const char
}
}
- if (status == NSS_STATUS_TRYAGAIN)
- {
- size_t newsize = 2 * tmp_buflen;
- if (tmp_buffer_malloced)
- {
- char *newp = realloc (tmp_buffer, newsize);
- if (newp != NULL)
- {
- assert ((((uintptr_t) newp)
- & (__alignof__ (struct hostent_data) - 1))
- == 0);
- tmp_buffer = newp;
- tmp_buflen = newsize;
- goto again;
- }
- }
- else if (!__libc_use_alloca (buflen + newsize))
- {
- tmp_buffer = malloc (newsize);
- if (tmp_buffer != NULL)
- {
- assert ((((uintptr_t) tmp_buffer)
- & (__alignof__ (struct hostent_data) - 1))
- == 0);
- tmp_buffer_malloced = true;
- tmp_buflen = newsize;
- goto again;
- }
- }
- else
- {
- tmp_buffer
- = extend_alloca (tmp_buffer, tmp_buflen,
- newsize
- + __alignof__ (struct hostent_data));
- tmp_buffer = (char *) (((uintptr_t) tmp_buffer
- + __alignof__ (struct hostent_data)
- - 1)
- & ~(__alignof__ (struct hostent_data)
- - 1));
- goto again;
- }
- }
+ if (status == NSS_STATUS_TRYAGAIN
+ && scratch_buffer_grow (&tmpbuf))
+ goto again;
else
status = NSS_STATUS_SUCCESS;
out:
- if (tmp_buffer_malloced)
- free (tmp_buffer);
+ scratch_buffer_free (&tmpbuf);
}
internal_endent (&stream);
Index: b/nss/nss_files/files-initgroups.c
===================================================================
diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c
index 27cd8ece40434f5c..8a88f1b62357d3bd 100644
--- a/nss/nss_files/files-initgroups.c
+++ b/nss/nss_files/files-initgroups.c
@@ -16,7 +16,6 @@
@ -1435,7 +1322,7 @@ Index: b/nss/nss_files/files-initgroups.c
enum nss_status
_nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
@@ -46,9 +46,8 @@ _nss_files_initgroups_dyn (const char *u
@@ -46,9 +46,8 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
enum nss_status status = NSS_STATUS_SUCCESS;
bool any = false;
@ -1447,7 +1334,7 @@ Index: b/nss/nss_files/files-initgroups.c
gid_t *groups = *groupsp;
@@ -67,26 +66,16 @@ _nss_files_initgroups_dyn (const char *u
@@ -67,26 +66,16 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
}
struct group grp;
@ -1480,7 +1367,7 @@ Index: b/nss/nss_files/files-initgroups.c
/* Reread current line, the parser has clobbered it. */
fsetpos (stream, &pos);
continue;
@@ -132,8 +121,7 @@ _nss_files_initgroups_dyn (const char *u
@@ -132,8 +121,7 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
out:
/* Free memory. */
@ -1490,241 +1377,8 @@ Index: b/nss/nss_files/files-initgroups.c
free (line);
fclose (stream);
Index: b/posix/glob.c
===================================================================
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -27,6 +27,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <scratch_buffer.h>
/* Outcomment the following line for production quality code. */
/* #define NDEBUG 1 */
@@ -293,7 +294,7 @@ glob (const char *pattern, int flags, in
glob_t dirs;
int retval = 0;
#ifdef _LIBC
- size_t alloca_used = 0;
+ size_t alloca_used = sizeof (struct scratch_buffer);
#endif
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
@@ -637,33 +638,13 @@ glob (const char *pattern, int flags, in
{
struct passwd *p;
# if defined HAVE_GETPWNAM_R || defined _LIBC
- long int pwbuflen = GETPW_R_SIZE_MAX ();
- char *pwtmpbuf;
struct passwd pwbuf;
- int malloc_pwtmpbuf = 0;
int save = errno;
+ struct scratch_buffer pwtmpbuf;
+ scratch_buffer_init (&pwtmpbuf);
-# ifndef _LIBC
- if (pwbuflen == -1)
- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
- Try a moderate value. */
- pwbuflen = 1024;
-# endif
- if (__libc_use_alloca (alloca_used + pwbuflen))
- pwtmpbuf = alloca_account (pwbuflen, alloca_used);
- else
- {
- pwtmpbuf = malloc (pwbuflen);
- if (pwtmpbuf == NULL)
- {
- retval = GLOB_NOSPACE;
- goto out;
- }
- malloc_pwtmpbuf = 1;
- }
-
- while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
- != 0)
+ while (getpwnam_r (name, &pwbuf,
+ pwtmpbuf.data, pwtmpbuf.length, &p) != 0)
{
if (errno != ERANGE)
{
@@ -671,67 +652,37 @@ glob (const char *pattern, int flags, in
break;
}
- if (!malloc_pwtmpbuf
- && __libc_use_alloca (alloca_used
- + 2 * pwbuflen))
- pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
- 2 * pwbuflen,
- alloca_used);
- else
+ if (!scratch_buffer_grow (&pwtmpbuf))
{
- char *newp = realloc (malloc_pwtmpbuf
- ? pwtmpbuf : NULL,
- 2 * pwbuflen);
- if (newp == NULL)
- {
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
- retval = GLOB_NOSPACE;
- goto out;
- }
- pwtmpbuf = newp;
- pwbuflen = 2 * pwbuflen;
- malloc_pwtmpbuf = 1;
+ retval = GLOB_NOSPACE;
+ goto out;
}
__set_errno (save);
}
# else
- p = getpwnam (name);
+ p = getpwnam (namebuf.data);
# endif
if (p != NULL)
{
- if (!malloc_pwtmpbuf)
- home_dir = p->pw_dir;
- else
+ home_dir = strdup (p->pw_dir);
+ malloc_home_dir = 1;
+ if (home_dir == NULL)
{
- size_t home_dir_len = strlen (p->pw_dir) + 1;
- if (__libc_use_alloca (alloca_used + home_dir_len))
- home_dir = alloca_account (home_dir_len,
- alloca_used);
- else
- {
- home_dir = malloc (home_dir_len);
- if (home_dir == NULL)
- {
- free (pwtmpbuf);
- retval = GLOB_NOSPACE;
- goto out;
- }
- malloc_home_dir = 1;
- }
- memcpy (home_dir, p->pw_dir, home_dir_len);
-
- free (pwtmpbuf);
+ scratch_buffer_free (&pwtmpbuf);
+ retval = GLOB_NOSPACE;
+ goto out;
}
}
+ scratch_buffer_free (&pwtmpbuf);
}
}
if (home_dir == NULL || home_dir[0] == '\0')
{
+ if (malloc_home_dir)
+ free (home_dir);
+ malloc_home_dir = 0;
if (flags & GLOB_TILDE_CHECK)
{
- if (__glibc_unlikely (malloc_home_dir))
- free (home_dir);
retval = GLOB_NOMATCH;
goto out;
}
@@ -852,57 +803,24 @@ glob (const char *pattern, int flags, in
{
struct passwd *p;
# if defined HAVE_GETPWNAM_R || defined _LIBC
- long int buflen = GETPW_R_SIZE_MAX ();
- char *pwtmpbuf;
- int malloc_pwtmpbuf = 0;
struct passwd pwbuf;
int save = errno;
+ struct scratch_buffer pwtmpbuf;
+ scratch_buffer_init (&pwtmpbuf);
-# ifndef _LIBC
- if (buflen == -1)
- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
- moderate value. */
- buflen = 1024;
-# endif
- if (__libc_use_alloca (alloca_used + buflen))
- pwtmpbuf = alloca_account (buflen, alloca_used);
- else
- {
- pwtmpbuf = malloc (buflen);
- if (pwtmpbuf == NULL)
- {
- nomem_getpw:
- if (__glibc_unlikely (malloc_user_name))
- free (user_name);
- retval = GLOB_NOSPACE;
- goto out;
- }
- malloc_pwtmpbuf = 1;
- }
-
- while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+ while (getpwnam_r (user_name, &pwbuf,
+ pwtmpbuf.data, pwtmpbuf.length, &p) != 0)
{
if (errno != ERANGE)
{
p = NULL;
break;
}
- if (!malloc_pwtmpbuf
- && __libc_use_alloca (alloca_used + 2 * buflen))
- pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
- 2 * buflen, alloca_used);
- else
+
+ if (!scratch_buffer_grow (&pwtmpbuf))
{
- char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
- 2 * buflen);
- if (newp == NULL)
- {
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
- goto nomem_getpw;
- }
- pwtmpbuf = newp;
- malloc_pwtmpbuf = 1;
+ retval = GLOB_NOSPACE;
+ goto out;
}
__set_errno (save);
}
@@ -931,8 +849,7 @@ glob (const char *pattern, int flags, in
dirname = malloc (home_len + rest_len + 1);
if (dirname == NULL)
{
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ scratch_buffer_free (&pwtmpbuf);
retval = GLOB_NOSPACE;
goto out;
}
@@ -944,13 +861,11 @@ glob (const char *pattern, int flags, in
dirlen = home_len + rest_len;
dirname_modified = 1;
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ scratch_buffer_free (&pwtmpbuf);
}
else
{
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ scratch_buffer_free (&pwtmpbuf);
if (flags & GLOB_TILDE_CHECK)
/* We have to regard it as an error if we cannot find the
Index: b/posix/wordexp.c
===================================================================
diff --git a/posix/wordexp.c b/posix/wordexp.c
index ba3f3ed4b66a6507..c4a6a209f416a9fb 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -17,7 +17,6 @@
@ -1743,7 +1397,7 @@ Index: b/posix/wordexp.c
#include <libc-lock.h>
#include <_itoa.h>
@@ -308,12 +308,7 @@ parse_tilde (char **word, size_t *word_l
@@ -308,12 +308,7 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
if (i == 1 + *offset)
{
/* Tilde appears on its own */
@ -1756,7 +1410,7 @@ Index: b/posix/wordexp.c
/* POSIX.2 says ~ expands to $HOME and if HOME is unset the
results are unspecified. We do a lookup on the uid if
@@ -328,25 +323,38 @@ parse_tilde (char **word, size_t *word_l
@@ -328,25 +323,38 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
}
else
{
@ -1802,7 +1456,7 @@ Index: b/posix/wordexp.c
}
}
else
@@ -354,13 +362,15 @@ parse_tilde (char **word, size_t *word_l
@@ -354,13 +362,15 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
/* Look up user name in database to get home directory */
char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
struct passwd pwd, *tpwd;
@ -1822,7 +1476,7 @@ Index: b/posix/wordexp.c
if (result == 0 && tpwd != NULL && pwd.pw_dir)
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
@@ -372,6 +382,8 @@ parse_tilde (char **word, size_t *word_l
@@ -372,6 +382,8 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
*word = w_addstr (*word, word_length, max_length, user);
}
@ -1831,8 +1485,8 @@ Index: b/posix/wordexp.c
*offset = i - 1;
}
return *word ? 0 : WRDE_NOSPACE;
Index: b/sysdeps/unix/sysv/linux/gethostid.c
===================================================================
diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c
index cc108aa2d64b616a..3529cf6fe509cfd1 100644
--- a/sysdeps/unix/sysv/linux/gethostid.c
+++ b/sysdeps/unix/sysv/linux/gethostid.c
@@ -63,13 +63,12 @@ sethostid (long int id)
@ -1885,8 +1539,8 @@ Index: b/sysdeps/unix/sysv/linux/gethostid.c
/* For the return value to be not exactly the IP address we do some
bit fiddling. */
return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
Index: b/sysdeps/unix/sysv/linux/getlogin_r.c
===================================================================
diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c
index 05ac36b49186b29e..37a9255e03657728 100644
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
@@ -18,6 +18,7 @@
@ -1897,7 +1551,7 @@ Index: b/sysdeps/unix/sysv/linux/getlogin_r.c
#define STATIC static
static int getlogin_r_fd0 (char *name, size_t namesize);
@@ -54,28 +55,19 @@ __getlogin_r_loginuid (char *name, size_
@@ -54,28 +55,19 @@ __getlogin_r_loginuid (char *name, size_t namesize)
endp == uidbuf || *endp != '\0'))
return -1;
@ -1933,7 +1587,7 @@ Index: b/sysdeps/unix/sysv/linux/getlogin_r.c
}
if (res != 0 || tpwd == NULL)
@@ -95,9 +87,7 @@ __getlogin_r_loginuid (char *name, size_
@@ -95,9 +87,7 @@ __getlogin_r_loginuid (char *name, size_t namesize)
memcpy (name, pwd.pw_name, needed);
out:

440
glibc-rh1416405.patch Normal file
View File

@ -0,0 +1,440 @@
commit 799c8d6905433ad56f26ccab4855b36f1d1ddbfc
Author: Mike FABIAN <mfabian@redhat.com>
Date: Thu Sep 7 15:28:28 2017 +0200
Add new codepage charmaps/IBM858 [BZ #21084]
This code page is identical to code page 850 except that X'D5'
has been changed from LI61 (dotless i) to SC20 (euro symbol).
The code points from /x01 to /x1f in the /localedata/charmaps/IBM858
file have the same mapping as those in localedata/charmaps/ANSI_X3.4-1968.
That means they disagree with with
ftp://ftp.software.ibm.com/software/globalization/gcoc/attachments/CP00858.txt
in that range.
For example, localedata/charmaps/IBM858 and localedata/charmaps/ANSI_X3.4-1968 have:
“<U0001> /x01 START OF HEADING (SOH)”
whereas CP00858.txt has:
“01 SS000000 Smiling Face”
That means that CP00858.txt is not really ASCII-compatible and to make
it ASCII-compatible we deviate fro CP00858.txt in the code points from /x01
to /x1f.
[BZ #21084]
* benchtests/strcoll-inputs/filelist#en_US.UTF-8: Add IBM858 and ibm858.c.
* iconvdata/Makefile: Add IBM858.
* iconvdata/gconv-modules: Add IBM858.
* iconvdata/ibm858.c: New file.
* iconvdata/tst-tables.sh: Add IBM858
* localedata/charmaps/IBM858: New file.
diff --git a/benchtests/strcoll-inputs/filelist#en_US.UTF-8 b/benchtests/strcoll-inputs/filelist#en_US.UTF-8
index b7b38017d836aee8..4fd74821feb0f22b 100644
--- a/benchtests/strcoll-inputs/filelist#en_US.UTF-8
+++ b/benchtests/strcoll-inputs/filelist#en_US.UTF-8
@@ -11233,6 +11233,7 @@ ISO-8859-9E
UTF-8
ISO-8859-2
IBM850
+IBM858
EUC-TW
KOI8-U
IBM903
@@ -13922,6 +13923,7 @@ ibm12712.c
ibm1145.h
ibm932.c
ibm850.c
+ibm858.c
ibm437.c
ibm1399.c
stdio-common
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index e4845871f559b406..6975b46fbba422bd 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -36,9 +36,9 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \
IBM874 CP737 CP775 ISO-2022-KR HP-TURKISH8 HP-THAI8 HP-GREEK8 \
KOI8-R LATIN-GREEK LATIN-GREEK-1 IBM256 IBM273 IBM277 IBM278 \
IBM280 IBM281 IBM284 IBM285 IBM290 IBM297 IBM420 IBM424 \
- IBM437 IBM850 IBM851 IBM852 IBM855 IBM857 IBM860 IBM861 \
- IBM862 IBM863 IBM864 IBM865 IBM868 IBM869 IBM875 IBM880 \
- IBM866 CP1258 IBM922 IBM1124 IBM1129 IBM932 IBM943 \
+ IBM437 IBM850 IBM851 IBM852 IBM855 IBM857 IBM858 IBM860 \
+ IBM861 IBM862 IBM863 IBM864 IBM865 IBM868 IBM869 IBM875 \
+ IBM880 IBM866 CP1258 IBM922 IBM1124 IBM1129 IBM932 IBM943 \
IBM856 IBM930 IBM933 IBM935 IBM937 IBM939 IBM1046 \
IBM1132 IBM1133 IBM1160 IBM1161 IBM1162 IBM1163 IBM1164 \
IBM918 IBM1004 IBM1026 CP1125 CP1250 CP1251 CP1252 CP1253 \
@@ -153,11 +153,11 @@ gen-8bit-modules := iso8859-2 iso8859-3 iso8859-4 iso8859-6 iso8859-9 koi-8 \
gen-8bit-gap-modules := koi8-r latin-greek latin-greek-1 ibm256 ibm273 \
ibm277 ibm278 ibm280 ibm281 ibm284 ibm285 ibm290 \
ibm297 ibm420 ibm424 ibm437 ibm850 ibm851 ibm852 \
- ibm855 ibm857 ibm860 ibm861 ibm862 ibm863 ibm864 \
- ibm865 ibm868 ibm869 ibm875 ibm880 ibm918 ibm1004 \
- ibm1026 cp1125 cp1250 cp1251 cp1252 cp1253 cp1254 \
- cp1256 cp1257 ibm866 iso8859-5 iso8859-7 iso8859-8 \
- iso8859-10 macintosh iec_p27-1 asmo_449 \
+ ibm855 ibm857 ibm858 ibm860 ibm861 ibm862 ibm863 \
+ ibm864 ibm865 ibm868 ibm869 ibm875 ibm880 ibm918 \
+ ibm1004 ibm1026 cp1125 cp1250 cp1251 cp1252 cp1253 \
+ cp1254 cp1256 cp1257 ibm866 iso8859-5 iso8859-7 \
+ iso8859-8 iso8859-10 macintosh iec_p27-1 asmo_449 \
csn_369103 cwi dec-mcs ecma-cyrillic gost_19768-74 \
greek-ccitt greek7 greek7-old inis inis-8 \
inis-cyrillic iso_2033 iso_5427 iso_5427-ext \
diff --git a/iconvdata/gconv-modules b/iconvdata/gconv-modules
index e959f16ad9b6dd3c..7d988c8ad9972858 100644
--- a/iconvdata/gconv-modules
+++ b/iconvdata/gconv-modules
@@ -744,6 +744,13 @@ module IBM850// INTERNAL IBM850 1
module INTERNAL IBM850// IBM850 1
# from to module cost
+alias CP858// IBM858//
+alias 858// IBM858//
+alias CSPC858MULTILINGUAL// IBM858//
+module IBM858// INTERNAL IBM858 1
+module INTERNAL IBM858// IBM858 1
+
+# from to module cost
alias CP851// IBM851//
alias 851// IBM851//
alias CSIBM851// IBM851//
diff --git a/iconvdata/ibm858.c b/iconvdata/ibm858.c
new file mode 100644
index 0000000000000000..ed2a48e3cf79e2b9
--- /dev/null
+++ b/iconvdata/ibm858.c
@@ -0,0 +1,27 @@
+/* Conversion from and to IBM858.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+
+/* Get the conversion table. */
+#define TABLES <ibm858.h>
+
+#define CHARSET_NAME "IBM858//"
+#define HAS_HOLES 1 /* Not all 256 character are defined. */
+
+#include <8bit-gap.c>
diff --git a/iconvdata/tst-tables.sh b/iconvdata/tst-tables.sh
index a027f5df5b27b904..77338f05149ccb98 100755
--- a/iconvdata/tst-tables.sh
+++ b/iconvdata/tst-tables.sh
@@ -125,6 +125,7 @@ cat <<EOF |
IBM855
IBM856
IBM857
+ IBM858
IBM860
IBM861
IBM862
diff --git a/localedata/charmaps/IBM858 b/localedata/charmaps/IBM858
new file mode 100644
index 0000000000000000..d8600e2456c87b48
--- /dev/null
+++ b/localedata/charmaps/IBM858
@@ -0,0 +1,281 @@
+<code_set_name> IBM858
+<comment_char> %
+<escape_char> /
+% version: 1.0
+% source: ftp://ftp.software.ibm.com/software/globalization/gcoc/attachments/CP00858.txt, 1998
+
+% source: UNICODE 1.0
+
+% This code page is identical to code page 850 except that X'D5'
+% has been changed from LI61 (dotless i) to SC20 (euro symbol).
+
+% The code points from /x01 to /x1f in this file have the same mapping
+% as those in ANSI_X3.4-1968. That means they disagree with with CP00858.txt
+% in that range. For example, this file and ANSI_X3.4-1968 have:
+% “<U0001> /x01 START OF HEADING (SOH)”
+% whereas CP00858.txt has:
+% “01 SS000000 Smiling Face”
+% That means that CP00858.txt is not really ASCII-compatible and to make
+% it ASCII-compatible we deviate fro CP00858.txt in the code points from /x01
+% to /x1f.
+
+% alias CP858
+% alias 858
+CHARMAP
+<U0000> /x00 NULL (NUL)
+<U0001> /x01 START OF HEADING (SOH)
+<U0002> /x02 START OF TEXT (STX)
+<U0003> /x03 END OF TEXT (ETX)
+<U0004> /x04 END OF TRANSMISSION (EOT)
+<U0005> /x05 ENQUIRY (ENQ)
+<U0006> /x06 ACKNOWLEDGE (ACK)
+<U0007> /x07 BELL (BEL)
+<U0008> /x08 BACKSPACE (BS)
+<U0009> /x09 CHARACTER TABULATION (HT)
+<U000A> /x0a LINE FEED (LF)
+<U000B> /x0b LINE TABULATION (VT)
+<U000C> /x0c FORM FEED (FF)
+<U000D> /x0d CARRIAGE RETURN (CR)
+<U000E> /x0e SHIFT OUT (SO)
+<U000F> /x0f SHIFT IN (SI)
+<U0010> /x10 DATALINK ESCAPE (DLE)
+<U0011> /x11 DEVICE CONTROL ONE (DC1)
+<U0012> /x12 DEVICE CONTROL TWO (DC2)
+<U0013> /x13 DEVICE CONTROL THREE (DC3)
+<U0014> /x14 DEVICE CONTROL FOUR (DC4)
+<U0015> /x15 NEGATIVE ACKNOWLEDGE (NAK)
+<U0016> /x16 SYNCHRONOUS IDLE (SYN)
+<U0017> /x17 END OF TRANSMISSION BLOCK (ETB)
+<U0018> /x18 CANCEL (CAN)
+<U0019> /x19 END OF MEDIUM (EM)
+<U001A> /x1a SUBSTITUTE (SUB)
+<U001B> /x1b ESCAPE (ESC)
+<U001C> /x1c FILE SEPARATOR (IS4)
+<U001D> /x1d GROUP SEPARATOR (IS3)
+<U001E> /x1e RECORD SEPARATOR (IS2)
+<U001F> /x1f UNIT SEPARATOR (IS1)
+<U0020> /x20 SPACE
+<U0021> /x21 EXCLAMATION MARK
+<U0022> /x22 QUOTATION MARK
+<U0023> /x23 NUMBER SIGN
+<U0024> /x24 DOLLAR SIGN
+<U0025> /x25 PERCENT SIGN
+<U0026> /x26 AMPERSAND
+<U0027> /x27 APOSTROPHE
+<U0028> /x28 LEFT PARENTHESIS
+<U0029> /x29 RIGHT PARENTHESIS
+<U002A> /x2a ASTERISK
+<U002B> /x2b PLUS SIGN
+<U002C> /x2c COMMA
+<U002D> /x2d HYPHEN-MINUS
+<U002E> /x2e FULL STOP
+<U002F> /x2f SOLIDUS
+<U0030> /x30 DIGIT ZERO
+<U0031> /x31 DIGIT ONE
+<U0032> /x32 DIGIT TWO
+<U0033> /x33 DIGIT THREE
+<U0034> /x34 DIGIT FOUR
+<U0035> /x35 DIGIT FIVE
+<U0036> /x36 DIGIT SIX
+<U0037> /x37 DIGIT SEVEN
+<U0038> /x38 DIGIT EIGHT
+<U0039> /x39 DIGIT NINE
+<U003A> /x3a COLON
+<U003B> /x3b SEMICOLON
+<U003C> /x3c LESS-THAN SIGN
+<U003D> /x3d EQUALS SIGN
+<U003E> /x3e GREATER-THAN SIGN
+<U003F> /x3f QUESTION MARK
+<U0040> /x40 COMMERCIAL AT
+<U0041> /x41 LATIN CAPITAL LETTER A
+<U0042> /x42 LATIN CAPITAL LETTER B
+<U0043> /x43 LATIN CAPITAL LETTER C
+<U0044> /x44 LATIN CAPITAL LETTER D
+<U0045> /x45 LATIN CAPITAL LETTER E
+<U0046> /x46 LATIN CAPITAL LETTER F
+<U0047> /x47 LATIN CAPITAL LETTER G
+<U0048> /x48 LATIN CAPITAL LETTER H
+<U0049> /x49 LATIN CAPITAL LETTER I
+<U004A> /x4a LATIN CAPITAL LETTER J
+<U004B> /x4b LATIN CAPITAL LETTER K
+<U004C> /x4c LATIN CAPITAL LETTER L
+<U004D> /x4d LATIN CAPITAL LETTER M
+<U004E> /x4e LATIN CAPITAL LETTER N
+<U004F> /x4f LATIN CAPITAL LETTER O
+<U0050> /x50 LATIN CAPITAL LETTER P
+<U0051> /x51 LATIN CAPITAL LETTER Q
+<U0052> /x52 LATIN CAPITAL LETTER R
+<U0053> /x53 LATIN CAPITAL LETTER S
+<U0054> /x54 LATIN CAPITAL LETTER T
+<U0055> /x55 LATIN CAPITAL LETTER U
+<U0056> /x56 LATIN CAPITAL LETTER V
+<U0057> /x57 LATIN CAPITAL LETTER W
+<U0058> /x58 LATIN CAPITAL LETTER X
+<U0059> /x59 LATIN CAPITAL LETTER Y
+<U005A> /x5a LATIN CAPITAL LETTER Z
+<U005B> /x5b LEFT SQUARE BRACKET
+<U005C> /x5c REVERSE SOLIDUS
+<U005D> /x5d RIGHT SQUARE BRACKET
+<U005E> /x5e CIRCUMFLEX ACCENT
+<U005F> /x5f LOW LINE
+<U0060> /x60 GRAVE ACCENT
+<U0061> /x61 LATIN SMALL LETTER A
+<U0062> /x62 LATIN SMALL LETTER B
+<U0063> /x63 LATIN SMALL LETTER C
+<U0064> /x64 LATIN SMALL LETTER D
+<U0065> /x65 LATIN SMALL LETTER E
+<U0066> /x66 LATIN SMALL LETTER F
+<U0067> /x67 LATIN SMALL LETTER G
+<U0068> /x68 LATIN SMALL LETTER H
+<U0069> /x69 LATIN SMALL LETTER I
+<U006A> /x6a LATIN SMALL LETTER J
+<U006B> /x6b LATIN SMALL LETTER K
+<U006C> /x6c LATIN SMALL LETTER L
+<U006D> /x6d LATIN SMALL LETTER M
+<U006E> /x6e LATIN SMALL LETTER N
+<U006F> /x6f LATIN SMALL LETTER O
+<U0070> /x70 LATIN SMALL LETTER P
+<U0071> /x71 LATIN SMALL LETTER Q
+<U0072> /x72 LATIN SMALL LETTER R
+<U0073> /x73 LATIN SMALL LETTER S
+<U0074> /x74 LATIN SMALL LETTER T
+<U0075> /x75 LATIN SMALL LETTER U
+<U0076> /x76 LATIN SMALL LETTER V
+<U0077> /x77 LATIN SMALL LETTER W
+<U0078> /x78 LATIN SMALL LETTER X
+<U0079> /x79 LATIN SMALL LETTER Y
+<U007A> /x7a LATIN SMALL LETTER Z
+<U007B> /x7b LEFT CURLY BRACKET
+<U007C> /x7c VERTICAL LINE
+<U007D> /x7d RIGHT CURLY BRACKET
+<U007E> /x7e TILDE
+<U007F> /x7f DELETE (DEL)
+<U00C7> /x80 LATIN CAPITAL LETTER C WITH CEDILLA
+<U00FC> /x81 LATIN SMALL LETTER U WITH DIAERESIS
+<U00E9> /x82 LATIN SMALL LETTER E WITH ACUTE
+<U00E2> /x83 LATIN SMALL LETTER A WITH CIRCUMFLEX
+<U00E4> /x84 LATIN SMALL LETTER A WITH DIAERESIS
+<U00E0> /x85 LATIN SMALL LETTER A WITH GRAVE
+<U00E5> /x86 LATIN SMALL LETTER A WITH RING ABOVE
+<U00E7> /x87 LATIN SMALL LETTER C WITH CEDILLA
+<U00EA> /x88 LATIN SMALL LETTER E WITH CIRCUMFLEX
+<U00EB> /x89 LATIN SMALL LETTER E WITH DIAERESIS
+<U00E8> /x8a LATIN SMALL LETTER E WITH GRAVE
+<U00EF> /x8b LATIN SMALL LETTER I WITH DIAERESIS
+<U00EE> /x8c LATIN SMALL LETTER I WITH CIRCUMFLEX
+<U00EC> /x8d LATIN SMALL LETTER I WITH GRAVE
+<U00C4> /x8e LATIN CAPITAL LETTER A WITH DIAERESIS
+<U00C5> /x8f LATIN CAPITAL LETTER A WITH RING ABOVE
+<U00C9> /x90 LATIN CAPITAL LETTER E WITH ACUTE
+<U00E6> /x91 LATIN SMALL LETTER AE
+<U00C6> /x92 LATIN CAPITAL LETTER AE
+<U00F4> /x93 LATIN SMALL LETTER O WITH CIRCUMFLEX
+<U00F6> /x94 LATIN SMALL LETTER O WITH DIAERESIS
+<U00F2> /x95 LATIN SMALL LETTER O WITH GRAVE
+<U00FB> /x96 LATIN SMALL LETTER U WITH CIRCUMFLEX
+<U00F9> /x97 LATIN SMALL LETTER U WITH GRAVE
+<U00FF> /x98 LATIN SMALL LETTER Y WITH DIAERESIS
+<U00D6> /x99 LATIN CAPITAL LETTER O WITH DIAERESIS
+<U00DC> /x9a LATIN CAPITAL LETTER U WITH DIAERESIS
+<U00F8> /x9b LATIN SMALL LETTER O WITH STROKE
+<U00A3> /x9c POUND SIGN
+<U00D8> /x9d LATIN CAPITAL LETTER O WITH STROKE
+<U00D7> /x9e MULTIPLICATION SIGN
+<U0192> /x9f LATIN SMALL LETTER F WITH HOOK
+<U00E1> /xa0 LATIN SMALL LETTER A WITH ACUTE
+<U00ED> /xa1 LATIN SMALL LETTER I WITH ACUTE
+<U00F3> /xa2 LATIN SMALL LETTER O WITH ACUTE
+<U00FA> /xa3 LATIN SMALL LETTER U WITH ACUTE
+<U00F1> /xa4 LATIN SMALL LETTER N WITH TILDE
+<U00D1> /xa5 LATIN CAPITAL LETTER N WITH TILDE
+<U00AA> /xa6 FEMININE ORDINAL INDICATOR
+<U00BA> /xa7 MASCULINE ORDINAL INDICATOR
+<U00BF> /xa8 INVERTED QUESTION MARK
+<U00AE> /xa9 REGISTERED SIGN
+<U00AC> /xaa NOT SIGN
+<U00BD> /xab VULGAR FRACTION ONE HALF
+<U00BC> /xac VULGAR FRACTION ONE QUARTER
+<U00A1> /xad INVERTED EXCLAMATION MARK
+<U00AB> /xae LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+<U00BB> /xaf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+<U2591> /xb0 LIGHT SHADE
+<U2592> /xb1 MEDIUM SHADE
+<U2593> /xb2 DARK SHADE
+<U2502> /xb3 BOX DRAWINGS LIGHT VERTICAL
+<U2524> /xb4 BOX DRAWINGS LIGHT VERTICAL AND LEFT
+<U00C1> /xb5 LATIN CAPITAL LETTER A WITH ACUTE
+<U00C2> /xb6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+<U00C0> /xb7 LATIN CAPITAL LETTER A WITH GRAVE
+<U00A9> /xb8 COPYRIGHT SIGN
+<U2563> /xb9 BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+<U2551> /xba BOX DRAWINGS DOUBLE VERTICAL
+<U2557> /xbb BOX DRAWINGS DOUBLE DOWN AND LEFT
+<U255D> /xbc BOX DRAWINGS DOUBLE UP AND LEFT
+<U00A2> /xbd CENT SIGN
+<U00A5> /xbe YEN SIGN
+<U2510> /xbf BOX DRAWINGS LIGHT DOWN AND LEFT
+<U2514> /xc0 BOX DRAWINGS LIGHT UP AND RIGHT
+<U2534> /xc1 BOX DRAWINGS LIGHT UP AND HORIZONTAL
+<U252C> /xc2 BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+<U251C> /xc3 BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+<U2500> /xc4 BOX DRAWINGS LIGHT HORIZONTAL
+<U253C> /xc5 BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+<U00E3> /xc6 LATIN SMALL LETTER A WITH TILDE
+<U00C3> /xc7 LATIN CAPITAL LETTER A WITH TILDE
+<U255A> /xc8 BOX DRAWINGS DOUBLE UP AND RIGHT
+<U2554> /xc9 BOX DRAWINGS DOUBLE DOWN AND RIGHT
+<U2569> /xca BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+<U2566> /xcb BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+<U2560> /xcc BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+<U2550> /xcd BOX DRAWINGS DOUBLE HORIZONTAL
+<U256C> /xce BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+<U00A4> /xcf CURRENCY SIGN
+<U00F0> /xd0 LATIN SMALL LETTER ETH (Icelandic)
+<U00D0> /xd1 LATIN CAPITAL LETTER ETH (Icelandic)
+<U00CA> /xd2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+<U00CB> /xd3 LATIN CAPITAL LETTER E WITH DIAERESIS
+<U00C8> /xd4 LATIN CAPITAL LETTER E WITH GRAVE
+<U20AC> /xd5 EURO SIGN
+<U00CD> /xd6 LATIN CAPITAL LETTER I WITH ACUTE
+<U00CE> /xd7 LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+<U00CF> /xd8 LATIN CAPITAL LETTER I WITH DIAERESIS
+<U2518> /xd9 BOX DRAWINGS LIGHT UP AND LEFT
+<U250C> /xda BOX DRAWINGS LIGHT DOWN AND RIGHT
+<U2588> /xdb FULL BLOCK
+<U2584> /xdc LOWER HALF BLOCK
+<U00A6> /xdd BROKEN BAR
+<U00CC> /xde LATIN CAPITAL LETTER I WITH GRAVE
+<U2580> /xdf UPPER HALF BLOCK
+<U00D3> /xe0 LATIN CAPITAL LETTER O WITH ACUTE
+<U00DF> /xe1 LATIN SMALL LETTER SHARP S (German)
+<U00D4> /xe2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+<U00D2> /xe3 LATIN CAPITAL LETTER O WITH GRAVE
+<U00F5> /xe4 LATIN SMALL LETTER O WITH TILDE
+<U00D5> /xe5 LATIN CAPITAL LETTER O WITH TILDE
+<U00B5> /xe6 MICRO SIGN
+<U00FE> /xe7 LATIN SMALL LETTER THORN (Icelandic)
+<U00DE> /xe8 LATIN CAPITAL LETTER THORN (Icelandic)
+<U00DA> /xe9 LATIN CAPITAL LETTER U WITH ACUTE
+<U00DB> /xea LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+<U00D9> /xeb LATIN CAPITAL LETTER U WITH GRAVE
+<U00FD> /xec LATIN SMALL LETTER Y WITH ACUTE
+<U00DD> /xed LATIN CAPITAL LETTER Y WITH ACUTE
+<U00AF> /xee MACRON
+<U00B4> /xef ACUTE ACCENT
+<U00AD> /xf0 SOFT HYPHEN
+<U00B1> /xf1 PLUS-MINUS SIGN
+<U2017> /xf2 DOUBLE LOW LINE
+<U00BE> /xf3 VULGAR FRACTION THREE QUARTERS
+<U00B6> /xf4 PILCROW SIGN
+<U00A7> /xf5 SECTION SIGN
+<U00F7> /xf6 DIVISION SIGN
+<U00B8> /xf7 CEDILLA
+<U00B0> /xf8 DEGREE SIGN
+<U00A8> /xf9 DIAERESIS
+<U00B7> /xfa MIDDLE DOT
+<U00B9> /xfb SUPERSCRIPT ONE
+<U00B3> /xfc SUPERSCRIPT THREE
+<U00B2> /xfd SUPERSCRIPT TWO
+<U25A0> /xfe BLACK SQUARE
+<U00A0> /xff NO-BREAK SPACE
+END CHARMAP

View File

@ -0,0 +1,201 @@
commit e6b4e2de6dd91efdcac80b79149c596de8a26b70
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jun 27 09:26:46 2017 +0200
resolv: Call _res_hconf_init from __res_vinit
Many callers of __res_maybe_init also call _res_hconf_init.
Additional calls to the latter do not hurt because the function
does its work only once. (/etc/hosts.conf is not reloaded or
even checked for changes.) This means that we can simplify the
code by calling _res_hconf_init directly from __res_vinit.
diff --git a/inet/gethstbyad_r.c b/inet/gethstbyad_r.c
index 88f428c1dbd3c177..6b5c13105059dd35 100644
--- a/inet/gethstbyad_r.c
+++ b/inet/gethstbyad_r.c
@@ -18,7 +18,7 @@
#include <netdb.h>
#include <string.h>
-
+#include <resolv/res_hconf.h>
#define LOOKUP_TYPE struct hostent
#define FUNCTION_NAME gethostbyaddr
@@ -27,7 +27,6 @@
#define ADD_VARIABLES addr, len, type
#define NEED_H_ERRNO 1
#define NEED__RES 1
-#define NEED__RES_HCONF 1
/* If the addr parameter is the IPv6 unspecified address no query must
be performed. */
#define PREPROCESS \
diff --git a/inet/gethstbynm2_r.c b/inet/gethstbynm2_r.c
index 57047979900accfc..580ba6d1cfbd63ec 100644
--- a/inet/gethstbynm2_r.c
+++ b/inet/gethstbynm2_r.c
@@ -22,7 +22,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
-
+#include <resolv/res_hconf.h>
#define LOOKUP_TYPE struct hostent
#define FUNCTION_NAME gethostbyname2
@@ -30,7 +30,7 @@
#define ADD_PARAMS const char *name, int af
#define ADD_VARIABLES name, af
#define NEED_H_ERRNO 1
-#define NEED__RES_HCONF 1
+#define NEED__RES 1
#define POSTPROCESS \
if (status == NSS_STATUS_SUCCESS) \
_res_hconf_reorder_addrs (resbuf);
diff --git a/inet/gethstbynm_r.c b/inet/gethstbynm_r.c
index 3758a9dde8e016f4..8f464b5ff1914b86 100644
--- a/inet/gethstbynm_r.c
+++ b/inet/gethstbynm_r.c
@@ -22,7 +22,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
-
+#include <resolv/res_hconf.h>
#define LOOKUP_TYPE struct hostent
#define FUNCTION_NAME gethostbyname
@@ -30,7 +30,7 @@
#define ADD_PARAMS const char *name
#define ADD_VARIABLES name
#define NEED_H_ERRNO 1
-#define NEED__RES_HCONF 1
+#define NEED__RES 1
#define POSTPROCESS \
if (status == NSS_STATUS_SUCCESS) \
_res_hconf_reorder_addrs (resbuf);
diff --git a/nscd/aicache.c b/nscd/aicache.c
index ea29b1c3d99bb530..358945140e04b2a9 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -26,7 +26,6 @@
#include <unistd.h>
#include <sys/mman.h>
#include <resolv/resolv-internal.h>
-#include <resolv/res_hconf.h>
#include <scratch_buffer.h>
#include "dbg_log.h"
@@ -103,7 +102,6 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
nip = hosts_database;
/* Initialize configurations. */
- _res_hconf_init ();
if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;
diff --git a/nscd/gethstbyad_r.c b/nscd/gethstbyad_r.c
index b17f0d2b5100c151..842ced2ec64048ea 100644
--- a/nscd/gethstbyad_r.c
+++ b/nscd/gethstbyad_r.c
@@ -28,7 +28,6 @@
#define EXTRA_VARIABLES , ttlp
#define NEED_H_ERRNO 1
#define NEED__RES 1
-#define NEED__RES_HCONF 1
/* We are nscd, so we don't want to be talking to ourselves. */
#undef USE_NSCD
diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c
index 41bb26845d7b9592..2ab75e469eca1589 100644
--- a/nscd/gethstbynm3_r.c
+++ b/nscd/gethstbynm3_r.c
@@ -32,7 +32,7 @@
#define ADD_VARIABLES name, af
#define EXTRA_VARIABLES , ttlp, canonp
#define NEED_H_ERRNO 1
-#define NEED__RES_HCONF 1
+#define NEED__RES 1
#define HANDLE_DIGITS_DOTS 1
#define HAVE_LOOKUP_BUFFER 1
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
index 5962475737dee6ba..7cab825cf05503f6 100644
--- a/nss/getXXbyYY_r.c
+++ b/nss/getXXbyYY_r.c
@@ -25,9 +25,6 @@
#ifdef USE_NSCD
# include <nscd/nscd_proto.h>
#endif
-#ifdef NEED__RES_HCONF
-# include <resolv/res_hconf.h>
-#endif
#ifdef NEED__RES
# include <resolv.h>
#endif
@@ -273,9 +270,6 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
return errno;
}
#endif /* need _res */
-#ifdef NEED__RES_HCONF
- _res_hconf_init ();
-#endif /* need _res_hconf */
void *tmp_ptr = fct.l;
#ifdef PTR_MANGLE
diff --git a/resolv/res_hconf.h b/resolv/res_hconf.h
index 6eaf4039f3451511..209f76a0d6ef8193 100644
--- a/resolv/res_hconf.h
+++ b/resolv/res_hconf.h
@@ -46,7 +46,7 @@ struct hconf
};
extern struct hconf _res_hconf;
-extern void _res_hconf_init (void);
+extern void _res_hconf_init (void) attribute_hidden;
extern void _res_hconf_trim_domain (char *domain);
extern void _res_hconf_trim_domains (struct hostent *hp);
extern void _res_hconf_reorder_addrs (struct hostent *hp);
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 9aa907ee199f01a6..821f06061b4c3fb1 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -85,6 +85,7 @@
#include <ctype.h>
#include <netdb.h>
#include <resolv/resolv-internal.h>
+#include <res_hconf.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
@@ -430,6 +431,9 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
int
__res_vinit (res_state statp, int preinit)
{
+ /* Ensure that /etc/hosts.conf has been loaded (once). */
+ _res_hconf_init ();
+
FILE *fp = fopen (_PATH_RESCONF, "rce");
if (fp == NULL)
switch (errno)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 91e0a76c5cfa027f..4fb1eaef79bc66a3 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -80,7 +80,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <not-cancel.h>
#include <nscd/nscd-client.h>
#include <nscd/nscd_proto.h>
-#include <resolv/res_hconf.h>
#include <scratch_buffer.h>
#include <inet/net-internal.h>
@@ -767,7 +766,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
nip = __nss_hosts_database;
/* Initialize configurations. */
- _res_hconf_init ();
if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;

View File

@ -0,0 +1,45 @@
commit b1e7c13cc58572600809d5173fed2c00c38af2e7
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 23 17:52:55 2017 +0200
resolv: Clean up declarations of the __res_initstamp variable
diff --git a/resolv/res_init.c b/resolv/res_init.c
index ed5a4d4804a792de..9aa907ee199f01a6 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -105,7 +105,7 @@
static void res_setoptions (res_state, const char *, const char *);
static uint32_t net_mask (struct in_addr);
-unsigned long long int __res_initstamp attribute_hidden;
+unsigned long long int __res_initstamp;
int
res_ninit (res_state statp)
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index 3ef885762e890a40..5202b756ff17518a 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -25,8 +25,8 @@
#include <arpa/nameser.h>
#include <resolv.h>
#include <libc-lock.h>
+#include <resolv-internal.h>
-extern unsigned long long int __res_initstamp attribute_hidden;
/* We have atomic increment operations on 64-bit platforms. */
#if __WORDSIZE == 64
# define atomicinclock(lock) (void) 0
diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
index 9afaa07d8b03d31f..5a9faf8de975f316 100644
--- a/resolv/resolv-internal.h
+++ b/resolv/resolv-internal.h
@@ -65,4 +65,7 @@ int __res_nopt (res_state, int n0, unsigned char *buf, int buflen,
int __inet_pton_length (int af, const char *src, size_t srclen, void *);
libc_hidden_proto (__inet_pton_length)
+/* Used to propagate the effect of res_init calls across threads. */
+extern unsigned long long int __res_initstamp attribute_hidden;
+
#endif /* _RESOLV_INTERNAL_H */

View File

@ -0,0 +1,162 @@
commit 89f6307c5d270ed4f11cee373031fa9f2222f2b9
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jul 4 11:18:34 2017 +0200
resolv: Fix improper assert in __resolv_conf_attach
diff --git a/resolv/Makefile b/resolv/Makefile
index c1fcf341746cf1a8..e80583c72b96efb4 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -51,6 +51,7 @@ tests += \
tst-resolv-basic \
tst-resolv-edns \
tst-resolv-network \
+ tst-resolv-res_init-multi \
tst-resolv-search \
# These tests need libdl.
@@ -160,6 +161,8 @@ $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-res_init: $(libdl) $(objpfx)libresolv.so
+$(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
+ $(shared-thread-library)
$(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index b98cf92890a121f9..0ed36cde02608f2d 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -58,8 +58,10 @@ struct resolv_conf_global
the array element is overwritten with NULL. */
struct resolv_conf_array array;
- /* Start of the free list in the array. The MSB is set if this
- field has been initialized. */
+ /* Start of the free list in the array. Zero if the free list is
+ empty. Otherwise, free_list_start >> 1 is the first element of
+ the free list (and the free list entries all have their LSB set
+ and are shifted one to the left). */
uintptr_t free_list_start;
/* Cached current configuration object for /etc/resolv.conf. */
@@ -567,11 +569,7 @@ decrement_at_index (struct resolv_conf_global *global_copy, size_t index)
struct resolv_conf *conf = (struct resolv_conf *) *slot;
conf_decrement (conf);
/* Put the slot onto the free list. */
- if (global_copy->free_list_start == 0)
- /* Not yet initialized. */
- *slot = 1;
- else
- *slot = global_copy->free_list_start;
+ *slot = global_copy->free_list_start;
global_copy->free_list_start = (index << 1) | 1;
}
}
@@ -598,7 +596,8 @@ __resolv_conf_attach (struct __res_state *resp, struct resolv_conf *conf)
index = global_copy->free_list_start >> 1;
uintptr_t *slot = resolv_conf_array_at (&global_copy->array, index);
global_copy->free_list_start = *slot;
- assert (global_copy->free_list_start & 1);
+ assert (global_copy->free_list_start == 0
+ || global_copy->free_list_start & 1);
/* Install the configuration pointer. */
*slot = (uintptr_t) conf;
}
diff --git a/resolv/tst-resolv-res_init-multi.c b/resolv/tst-resolv-res_init-multi.c
new file mode 100644
index 0000000000000000..bdc68a5a33f7f017
--- /dev/null
+++ b/resolv/tst-resolv-res_init-multi.c
@@ -0,0 +1,89 @@
+/* Multi-threaded test for resolver initialization.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+/* Whether name lookups succeed does not really matter. We use this
+ to trigger initialization of the resolver. */
+static const char *test_hostname = "www.gnu.org";
+
+/* The different initialization methods. */
+enum test_type { init, byname, gai };
+enum { type_count = 3 };
+
+/* Thread function. Perform a few resolver options. */
+static void *
+thread_func (void *closure)
+{
+ enum test_type *ptype = closure;
+ /* Perform a few calls to the requested operation. */
+ TEST_VERIFY (*ptype >= 0);
+ TEST_VERIFY (*ptype < (int) type_count);
+ for (int i = 0; i < 3; ++i)
+ switch (*ptype)
+ {
+ case init:
+ res_init ();
+ break;
+ case byname:
+ gethostbyname (test_hostname);
+ break;
+ case gai:
+ {
+ struct addrinfo hints = { 0, };
+ struct addrinfo *ai = NULL;
+ if (getaddrinfo (test_hostname, "80", &hints, &ai) == 0)
+ freeaddrinfo (ai);
+ }
+ break;
+ }
+ free (ptype);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ /* Start a small number of threads which perform resolver
+ operations. */
+ enum { thread_count = 30 };
+
+ pthread_t threads[thread_count];
+ for (int i = 0; i < thread_count; ++i)
+ {
+ enum test_type *ptype = xmalloc (sizeof (*ptype));
+ *ptype = i % type_count;
+ threads[i] = xpthread_create (NULL, thread_func, ptype);
+ }
+ for (int i = 0; i < type_count; ++i)
+ {
+ enum test_type *ptype = xmalloc (sizeof (*ptype));
+ *ptype = i;
+ thread_func (ptype);
+ }
+ for (int i = 0; i < thread_count; ++i)
+ xpthread_join (threads[i]);
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,24 @@
commit 27233446a62ca35ce0b54566279a99a6774d4210
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Sep 6 15:47:27 2017 +0200
resolv: __resolv_conf_attach must not free passed conf object [BZ #22096]
(cherry picked from commit a83047308196e3e54716a39dd85c0a08b198d6bd)
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index f391d30c277bb348..e0f296d02e061a89 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -600,10 +600,7 @@ __resolv_conf_attach (struct __res_state *resp, struct resolv_conf *conf)
struct resolv_conf_global *global_copy = get_locked_global ();
if (global_copy == NULL)
- {
- free (conf);
- return false;
- }
+ return false;
/* Try to find an unused index in the array. */
size_t index;

View File

@ -0,0 +1,63 @@
Partial backport of:
commit 6781d8e693eb9e1251875222db5c9885d7ebb596
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:41 2017 +0200
resolv: Turn _res_opcodes into a compatibility symbol
The backport avoids depending on the GLIBC_2.26 symbol version.
diff --git a/include/resolv.h b/include/resolv.h
index 4d5b51e873ad62a1..2938506d75ee5d43 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -90,8 +90,5 @@ libresolv_hidden_proto (__b64_ntop)
libresolv_hidden_proto (__dn_count_labels)
libresolv_hidden_proto (__p_secstodate)
-extern const char *_res_opcodes[];
-libresolv_hidden_proto (_res_opcodes)
-
# endif /* _RESOLV_H_ && !_ISOMAC */
#endif
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index 182aeefa1f8683f4..b26c38bae0a1674b 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -106,6 +106,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <shlib-compat.h>
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
@@ -115,7 +116,8 @@
extern const char *_res_sectioncodes[] attribute_hidden;
-const char *_res_opcodes[] =
+/* _res_opcodes was exported by accident as a variable. */
+static const char *res_opcodes[] =
{
"QUERY",
"IQUERY",
@@ -134,7 +136,7 @@ const char *_res_opcodes[] =
"ZONEINIT",
"ZONEREF",
};
-libresolv_hidden_data_def (_res_opcodes)
+strong_alias (res_opcodes, _res_opcodes)
static const char *p_section(int section, int opcode);
@@ -259,7 +261,7 @@ fp_nquery (const unsigned char *msg, int len, FILE *file)
if ((!pfcode) || (pfcode & RES_PRF_HEADX) || rcode)
fprintf(file,
";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
- _res_opcodes[opcode], p_rcode(rcode), id);
+ res_opcodes[opcode], p_rcode(rcode), id);
if ((!pfcode) || (pfcode & RES_PRF_HEADX))
putc(';', file);
if ((!pfcode) || (pfcode & RES_PRF_HEAD2)) {

View File

@ -0,0 +1,21 @@
commit a0704b1ac7e8dc26f0e0feac58468958305ae844
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Apr 19 19:34:42 2017 +0200
nss_dns: Correct parentheses for the __glibc_unlikely argument
This fixes commit bee05c9d58a34ec5886faf3b56ecaa56355d94bf.
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 7099d093f357e16c..f121aa3de73704ea 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -633,7 +633,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
packtmp, sizeof packtmp);
if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
{
- if (__glibc_unlikely (errno) == EMSGSIZE)
+ if (__glibc_unlikely (errno == EMSGSIZE))
goto too_small;
n = -1;

View File

@ -0,0 +1,206 @@
commit bee05c9d58a34ec5886faf3b56ecaa56355d94bf
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Apr 19 14:29:11 2017 +0200
resolv: Replace __builtin_expect with __glibc_unlikely/__glibc_likely
diff --git a/resolv/gai_suspend.c b/resolv/gai_suspend.c
index 3ee6a08b4fd9f2fb..a86bd4360d6b03e8 100644
--- a/resolv/gai_suspend.c
+++ b/resolv/gai_suspend.c
@@ -141,7 +141,7 @@ gai_suspend (const struct gaicb *const list[], int ent,
/* An error occurred. Possibly it's EINTR. We have to translate
the timeout error report of `pthread_cond_timedwait' to the
form expected from `gai_suspend'. */
- if (__builtin_expect (result, ETIMEDOUT) == ETIMEDOUT)
+ if (__glibc_likely (result == ETIMEDOUT))
result = EAI_AGAIN;
else if (result == EINTR)
result = EAI_INTR;
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 705b3c9c078c41bf..7099d093f357e16c 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -619,7 +619,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
ancount = ntohs (hp->ancount);
qdcount = ntohs (hp->qdcount);
cp = answer->buf + HFIXEDSZ;
- if (__builtin_expect (qdcount, 1) != 1)
+ if (__glibc_unlikely (qdcount != 1))
{
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
@@ -633,7 +633,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
packtmp, sizeof packtmp);
if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
{
- if (__builtin_expect (errno, 0) == EMSGSIZE)
+ if (__glibc_unlikely (errno) == EMSGSIZE)
goto too_small;
n = -1;
@@ -642,13 +642,19 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
if (n > 0 && bp[0] == '.')
bp[0] = '\0';
- if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
- 0))
+ if (__glibc_unlikely (n < 0))
{
*errnop = errno;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
+ if (__glibc_unlikely (name_ok (bp) == 0))
+ {
+ errno = EBADMSG;
+ *errnop = EBADMSG;
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_UNAVAIL;
+ }
cp += n + QFIXEDSZ;
if (qtype == T_A || qtype == T_AAAA)
@@ -690,7 +696,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
packtmp, sizeof packtmp);
if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
{
- if (__builtin_expect (errno, 0) == EMSGSIZE)
+ if (__glibc_unlikely (errno == EMSGSIZE))
goto too_small;
n = -1;
@@ -750,7 +756,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
/* Store alias. */
*ap++ = bp;
n = strlen (bp) + 1; /* For the \0. */
- if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
+ if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
{
++had_error;
continue;
@@ -761,7 +767,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
n = strlen (tbuf) + 1; /* For the \0. */
if (__glibc_unlikely (n > linebuflen))
goto too_small;
- if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
+ if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
{
++had_error;
continue;
@@ -789,7 +795,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
n = strlen (tbuf) + 1; /* For the \0. */
if (__glibc_unlikely (n > linebuflen))
goto too_small;
- if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
+ if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
{
++had_error;
continue;
@@ -821,7 +827,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
packtmp, sizeof packtmp);
if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
{
- if (__builtin_expect (errno, 0) == EMSGSIZE)
+ if (__glibc_unlikely (errno == EMSGSIZE))
goto too_small;
n = -1;
@@ -854,7 +860,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
return NSS_STATUS_SUCCESS;
case T_A:
case T_AAAA:
- if (__builtin_expect (strcasecmp (result->h_name, bp), 0) != 0)
+ if (__glibc_unlikely (strcasecmp (result->h_name, bp) != 0))
{
cp += n;
continue; /* XXX - had_error++ ? */
@@ -975,7 +981,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
it later. */
if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
{
- if (__builtin_expect (errno, 0) == EMSGSIZE)
+ if (__glibc_unlikely (errno == EMSGSIZE))
{
too_small:
*errnop = ERANGE;
@@ -986,13 +992,19 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
n = -1;
}
- if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
- && (errno = EBADMSG)), 0))
+ if (__glibc_unlikely (n < 0))
{
*errnop = errno;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
+ if (__glibc_unlikely (res_hnok (buffer) == 0))
+ {
+ errno = EBADMSG;
+ *errnop = EBADMSG;
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_UNAVAIL;
+ }
cp += n + QFIXEDSZ;
int haveanswer = 0;
@@ -1014,7 +1026,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
if (n != -1 &&
(h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
{
- if (__builtin_expect (errno, 0) == EMSGSIZE)
+ if (__glibc_unlikely (errno == EMSGSIZE))
goto too_small;
n = -1;
@@ -1128,8 +1140,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
buffer += pad;
buflen = buflen > pad ? buflen - pad : 0;
- if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
- 0))
+ if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
goto too_small;
*pat = (struct gaih_addrtuple *) buffer;
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 923724f86d6a0edc..23676e994dd58be7 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -356,7 +356,7 @@ __res_vinit(res_state statp, int preinit) {
statp->nsort = nsort;
(void) fclose(fp);
}
- if (__builtin_expect(statp->nscount == 0, 0)) {
+ if (__glibc_unlikely (statp->nscount == 0)) {
statp->nsaddr.sin_addr = __inet_makeaddr(IN_LOOPBACKNET, 1);
statp->nsaddr.sin_family = AF_INET;
statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
diff --git a/resolv/res_query.c b/resolv/res_query.c
index ec65bab04153c2ff..0ca3a650282ec7f0 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -199,7 +199,7 @@ __libc_res_nquery(res_state statp,
nquery1 = n;
}
- if (__builtin_expect (n <= 0, 0) && !use_malloc) {
+ if (__glibc_unlikely (n <= 0) && !use_malloc) {
/* Retry just in case res_nmkquery failed because of too
short buffer. Shouldn't happen. */
bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET;
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 440da90a0b381b84..1835ec7ee507d215 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -424,7 +424,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
* Some resolvers want to even out the load on their nameservers.
* Note that RES_BLAST overrides RES_ROTATE.
*/
- if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0)) {
+ if (__glibc_unlikely ((statp->options & RES_ROTATE) != 0)) {
struct sockaddr_in ina;
struct sockaddr_in6 *inp;
int lastns = statp->nscount - 1;

View File

@ -0,0 +1,230 @@
commit d85f99679d89fb47426301620b7a980388fddcfd
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:35 2017 +0200
resolv: Move fp_nquery, fp_query, p_query, _res_opcodes
From res_data.c to res_debug.c.
Also drop the unnecessary _res initialization from fp_nquery.
diff --git a/include/resolv.h b/include/resolv.h
index 37e4047ac40c6ae1..4d5b51e873ad62a1 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -32,8 +32,6 @@ extern struct hostent *_gethtbyname2 (const char *__name, int __af);
struct hostent *_gethtbyaddr (const char *addr, size_t __len, int __af);
extern uint32_t _getlong (const unsigned char *__src);
extern uint16_t _getshort (const unsigned char *__src);
-extern void res_pquery (const res_state __statp, const unsigned char *__msg,
- int __len, FILE *__file);
extern int res_ourserver_p (const res_state __statp,
const struct sockaddr_in6 *__inp);
extern void __res_iclose (res_state statp, bool free_addr);
diff --git a/resolv/res_data.c b/resolv/res_data.c
index d907bfc9bd8a55fd..d05389e1347a57ab 100644
--- a/resolv/res_data.c
+++ b/resolv/res_data.c
@@ -32,46 +32,6 @@
#include <string.h>
#include <unistd.h>
-const char *_res_opcodes[] = {
- "QUERY",
- "IQUERY",
- "CQUERYM",
- "CQUERYU", /* experimental */
- "NOTIFY", /* experimental */
- "UPDATE",
- "6",
- "7",
- "8",
- "9",
- "10",
- "11",
- "12",
- "13",
- "ZONEINIT",
- "ZONEREF",
-};
-libresolv_hidden_data_def (_res_opcodes)
-
-void
-p_query(const u_char *msg) {
- fp_query(msg, stdout);
-}
-
-void
-fp_query(const u_char *msg, FILE *file) {
- fp_nquery(msg, PACKETSZ, file);
-}
-libresolv_hidden_def (fp_query)
-
-void
-fp_nquery(const u_char *msg, int len, FILE *file) {
- if (__res_maybe_init (&_res, 0) == -1)
- return;
-
- res_pquery(&_res, msg, len, file);
-}
-libresolv_hidden_def (fp_nquery)
-
int
res_query(const char *name, /* domain name */
int class, int type, /* class and type of query */
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index e23559bad3d92e71..182aeefa1f8683f4 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -115,6 +115,27 @@
extern const char *_res_sectioncodes[] attribute_hidden;
+const char *_res_opcodes[] =
+ {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU", /* experimental */
+ "NOTIFY", /* experimental */
+ "UPDATE",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "ZONEINIT",
+ "ZONEREF",
+ };
+libresolv_hidden_data_def (_res_opcodes)
+
static const char *p_section(int section, int opcode);
/*
@@ -132,9 +153,7 @@ fp_resstat(const res_state statp, FILE *file) {
}
static void
-do_section(const res_state statp,
- ns_msg *handle, ns_sect section,
- int pflag, FILE *file)
+do_section (int pfcode, ns_msg *handle, ns_sect section, int pflag, FILE *file)
{
int n, sflag, rrnum;
static int buflen = 2048;
@@ -145,8 +164,8 @@ do_section(const res_state statp,
/*
* Print answer records.
*/
- sflag = (statp->pfcode & pflag);
- if (statp->pfcode && !sflag)
+ sflag = (pfcode & pflag);
+ if (pfcode && !sflag)
return;
buf = malloc(buflen);
@@ -163,11 +182,11 @@ do_section(const res_state statp,
fprintf(file, ";; ns_parserr: %s\n",
strerror(errno));
else if (rrnum > 0 && sflag != 0 &&
- (statp->pfcode & RES_PRF_HEAD1))
+ (pfcode & RES_PRF_HEAD1))
putc('\n', file);
goto cleanup;
}
- if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
+ if (rrnum == 0 && sflag != 0 && (pfcode & RES_PRF_HEAD1))
fprintf(file, ";; %s SECTION:\n",
p_section(section, opcode));
if (section == ns_s_qd)
@@ -209,11 +228,19 @@ do_section(const res_state statp,
* This is intended to be primarily a debugging routine.
*/
void
-res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
+fp_nquery (const unsigned char *msg, int len, FILE *file)
+{
ns_msg handle;
int qdcount, ancount, nscount, arcount;
u_int opcode, rcode, id;
+ /* There is no need to initialize _res: If _res is not yet
+ initialized, _res.pfcode is zero. But initialization will
+ leave it at zero, too. _res.pfcode is an unsigned long,
+ but the code here assumes that the flags fit into an int,
+ so use that. */
+ int pfcode = _res.pfcode;
+
if (ns_initparse(msg, len, &handle) < 0) {
fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
return;
@@ -229,13 +256,13 @@ res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
/*
* Print header fields.
*/
- if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
+ if ((!pfcode) || (pfcode & RES_PRF_HEADX) || rcode)
fprintf(file,
";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
_res_opcodes[opcode], p_rcode(rcode), id);
- if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
+ if ((!pfcode) || (pfcode & RES_PRF_HEADX))
putc(';', file);
- if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
+ if ((!pfcode) || (pfcode & RES_PRF_HEAD2)) {
fprintf(file, "; flags:");
if (ns_msg_getflag(handle, ns_f_qr))
fprintf(file, " qr");
@@ -254,7 +281,7 @@ res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
if (ns_msg_getflag(handle, ns_f_cd))
fprintf(file, " cd");
}
- if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
+ if ((!pfcode) || (pfcode & RES_PRF_HEAD1)) {
fprintf(file, "; %s: %d",
p_section(ns_s_qd, opcode), qdcount);
fprintf(file, ", %s: %d",
@@ -264,21 +291,35 @@ res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
fprintf(file, ", %s: %d",
p_section(ns_s_ar, opcode), arcount);
}
- if ((!statp->pfcode) || (statp->pfcode &
+ if ((!pfcode) || (pfcode &
(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
putc('\n',file);
}
/*
* Print the various sections.
*/
- do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
- do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
- do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
- do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
+ do_section (pfcode, &handle, ns_s_qd, RES_PRF_QUES, file);
+ do_section (pfcode, &handle, ns_s_an, RES_PRF_ANS, file);
+ do_section (pfcode, &handle, ns_s_ns, RES_PRF_AUTH, file);
+ do_section (pfcode, &handle, ns_s_ar, RES_PRF_ADD, file);
if (qdcount == 0 && ancount == 0 &&
nscount == 0 && arcount == 0)
putc('\n', file);
}
+libresolv_hidden_def (fp_nquery)
+
+void
+fp_query (const unsigned char *msg, FILE *file)
+{
+ fp_nquery (msg, PACKETSZ, file);
+}
+libresolv_hidden_def (fp_query)
+
+void
+p_query (const unsigned char *msg)
+{
+ fp_query (msg, stdout);
+}
const u_char *
p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {

View File

@ -0,0 +1,21 @@
This change happened upstream in this commit:
commit ae65d4f3c3995279ca458c460ebf8bab1885fa03
Author: Wilco Dijkstra <wdijkstr@arm.com>
Date: Mon Mar 13 18:42:35 2017 +0000
Remove the str(n)dup inlines from string/bits/string2.h.
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 317413c9ef1559e6..b3d0a5ca74d926bb 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1106,7 +1106,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
canonbuf = NULL;
else
{
- canon = strdup (canon);
+ canon = __strdup (canon);
if (canon == NULL)
{
result = -EAI_MEMORY;

View File

@ -0,0 +1,33 @@
commit 513a71a420e74270a6a9702ec916e807be51350a
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Jun 24 16:51:31 2017 +0200
resolv/tst-resolv-basic: Add test cases for bug 21295
diff --git a/resolv/tst-resolv-basic.c b/resolv/tst-resolv-basic.c
index 66a0e8a1659219b4..95aea1bcfb266017 100644
--- a/resolv/tst-resolv-basic.c
+++ b/resolv/tst-resolv-basic.c
@@ -495,6 +495,22 @@ do_test (void)
test_bug_21295 ();
test_nodata_nxdomain ();
+ /* Test for bug 21295. */
+ check_ai_hints ("www.example", "80",
+ (struct addrinfo) { .ai_family = AF_INET6,
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_V4MAPPED | AI_ALL, },
+ "flags: AI_V4MAPPED AI_ALL\n"
+ "address: STREAM/TCP 2001:db8::1 80\n"
+ "address: STREAM/TCP ::ffff:192.0.2.17 80\n");
+ check_ai_hints ("t.www.example", "80",
+ (struct addrinfo) { .ai_family = AF_INET6,
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_V4MAPPED | AI_ALL, },
+ "flags: AI_V4MAPPED AI_ALL\n"
+ "address: STREAM/TCP 2001:db8::3 80\n"
+ "address: STREAM/TCP ::ffff:192.0.2.19 80\n");
+
resolv_test_end (aux);
return 0;

View File

@ -0,0 +1,33 @@
commit f768b450204f54b080ea5dc5c2071940604b424c
Author: Benjamin Cama <b.cama@kerlink.fr>
Date: Thu Jun 22 15:49:28 2017 +0200
inet: __inet6_scopeid_pton should accept node-local addresses [BZ #21657]
diff --git a/inet/inet6_scopeid_pton.c b/inet/inet6_scopeid_pton.c
index f842ffcadb391960..e09b1cb34dcc9424 100644
--- a/inet/inet6_scopeid_pton.c
+++ b/inet/inet6_scopeid_pton.c
@@ -33,6 +33,7 @@ __inet6_scopeid_pton (const struct in6_addr *address, const char *scope,
uint32_t *result)
{
if (IN6_IS_ADDR_LINKLOCAL (address)
+ || IN6_IS_ADDR_MC_NODELOCAL (address)
|| IN6_IS_ADDR_MC_LINKLOCAL (address))
{
uint32_t number = __if_nametoindex (scope);
diff --git a/inet/tst-inet6_scopeid_pton.c b/inet/tst-inet6_scopeid_pton.c
index a1bafa9021c5cf3b..8225b3b80abe6331 100644
--- a/inet/tst-inet6_scopeid_pton.c
+++ b/inet/tst-inet6_scopeid_pton.c
@@ -218,9 +218,9 @@ do_test (void)
{
expect_success ("fe80::1", interface_name, interface_index);
expect_success ("ff02::1", interface_name, interface_index);
+ expect_success ("ff01::1", interface_name, interface_index);
expect_failure ("::", interface_name);
expect_failure ("::1", interface_name);
- expect_failure ("ff01::1", interface_name);
expect_failure ("2001:db8::1", interface_name);
}

View File

@ -0,0 +1,111 @@
commit 9a0cc8c1bd7645bf3c988890ffb59639c07a5812
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 23 22:51:00 2017 +0200
inet_pton: Reject IPv6 addresses with many leading zeros [BZ #16637]
2001:db8:00001::f is not a valid IPv6 address according to RFC 2373.
diff --git a/resolv/inet_pton.c b/resolv/inet_pton.c
index b95da47c17ef8afc..16ee33e0c0dfb015 100644
--- a/resolv/inet_pton.c
+++ b/resolv/inet_pton.c
@@ -144,7 +144,8 @@ inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
{
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *curtok;
- int ch, saw_xdigit;
+ int ch;
+ size_t xdigits_seen; /* Number of hex digits since colon. */
unsigned int val;
tp = memset (tmp, '\0', NS_IN6ADDRSZ);
@@ -162,7 +163,7 @@ inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
}
curtok = src;
- saw_xdigit = 0;
+ xdigits_seen = 0;
val = 0;
while (src < src_endp)
{
@@ -170,17 +171,19 @@ inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
int digit = hex_digit_value (ch);
if (digit >= 0)
{
+ if (xdigits_seen == 4)
+ return 0;
val <<= 4;
val |= digit;
if (val > 0xffff)
return 0;
- saw_xdigit = 1;
+ ++xdigits_seen;
continue;
}
if (ch == ':')
{
curtok = src;
- if (!saw_xdigit)
+ if (xdigits_seen == 0)
{
if (colonp)
return 0;
@@ -193,7 +196,7 @@ inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
return 0;
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
- saw_xdigit = 0;
+ xdigits_seen = 0;
val = 0;
continue;
}
@@ -201,12 +204,12 @@ inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
&& inet_pton4 (curtok, src_endp, tp) > 0)
{
tp += NS_INADDRSZ;
- saw_xdigit = 0;
+ xdigits_seen = 0;
break; /* '\0' was seen by inet_pton4. */
}
return 0;
}
- if (saw_xdigit)
+ if (xdigits_seen > 0)
{
if (tp + NS_INT16SZ > endp)
return 0;
diff --git a/resolv/tst-inet_pton.c b/resolv/tst-inet_pton.c
index 7fffb24cdf9eb1f4..4bb9f8119378b467 100644
--- a/resolv/tst-inet_pton.c
+++ b/resolv/tst-inet_pton.c
@@ -226,13 +226,7 @@ const struct test_case test_cases[] =
},
{.input = "2", },
{.input = "2.", },
- {.input = "2001:db8:00001::f",
- .ipv6_ok = true,
- .ipv6_expected = {
- 0x20, 0x1, 0xd, 0xb8, 0x0, 0x1, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf
- },
- },
+ {.input = "2001:db8:00001::f", },
{.input = "2001:db8:10000::f", },
{.input = "2001:db8:1234:5678:abcd:ef01:2345:67",
.ipv6_ok = true,
@@ -454,13 +448,7 @@ const struct test_case test_cases[] =
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
},
},
- {.input = "::00001",
- .ipv6_ok = true,
- .ipv6_expected = {
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1
- },
- },
+ {.input = "::00001", },
{.input = "::1",
.ipv6_ok = true,
.ipv6_expected = {

View File

@ -0,0 +1,20 @@
commit 60149b28590be28051f99d0a343d7fbe002f2a8c
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jun 21 13:09:08 2017 +0200
__inet_pton_length: Implement new internal helper function
diff --git a/resolv/Makefile b/resolv/Makefile
index 3854ff4ad4156c15..692b2322cf7a3cab 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -65,6 +65,9 @@ tests += \
endif
+# This test accesses __inet_ntop_range, an internal libc function.
+tests += tst-inet_pton
+
# This test sends millions of packets and is rather slow.
xtests += tst-resolv-qtypes
endif

View File

@ -0,0 +1,52 @@
commit 94f094f22b50a20de9042cb1e78c7299992a91c9
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 13:19:00 2017 +0200
resolv: Introduce is_sort_mask and call it from res_vinit
diff --git a/resolv/res_init.c b/resolv/res_init.c
index eb24fca3a6ecef9a..eb8e308fdaa899ef 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -85,9 +85,6 @@
static void res_setoptions (res_state, const char *, const char *)
internal_function;
-
-static const char sort_mask_chars[] = "/&";
-#define ISSORTMASK(ch) (strchr(sort_mask_chars, ch) != NULL)
static u_int32_t net_mask (struct in_addr) __THROW;
unsigned long long int __res_initstamp attribute_hidden;
@@ -109,6 +106,14 @@ res_ninit(res_state statp) {
}
libc_hidden_def (__res_ninit)
+/* Return true if CH separates the netmask in the "sortlist"
+ directive. */
+static inline bool
+is_sort_mask (char ch)
+{
+ return ch == '/' || ch == '&';
+}
+
/* This function has to be reachable by res_data.c but not publically. */
int
__res_vinit(res_state statp, int preinit) {
@@ -305,14 +310,14 @@ __res_vinit(res_state statp, int preinit) {
if (*cp == '\0' || *cp == '\n' || *cp == ';')
break;
net = cp;
- while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+ while (*cp && !is_sort_mask (*cp) && *cp != ';' &&
isascii(*cp) && !isspace(*cp))
cp++;
n = *cp;
*cp = 0;
if (__inet_aton(net, &a)) {
statp->sort_list[nsort].addr = a;
- if (ISSORTMASK(n)) {
+ if (is_sort_mask (n)) {
*cp++ = n;
net = cp;
while (*cp && *cp != ';' &&

View File

@ -0,0 +1,32 @@
commit 75b3a15e077dbfdfd8cbb3449369379e700b9972
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Apr 4 14:13:03 2017 +0200
nss_dns: Remove superfluous dn_expand call from network handling
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index 45f7f1805701e0a4..fd8c5656c0cedd27 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -324,11 +324,8 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
while (--answer_count >= 0 && cp < end_of_message)
{
- int n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
- int type, class;
-
- n = __ns_name_unpack (answer->buf, end_of_message, cp,
- packtmp, sizeof packtmp);
+ int n = __ns_name_unpack (answer->buf, end_of_message, cp,
+ packtmp, sizeof packtmp);
if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
{
if (errno == EMSGSIZE)
@@ -350,6 +347,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
return NSS_STATUS_UNAVAIL;
}
+ int type, class;
GETSHORT (type, cp);
GETSHORT (class, cp);
cp += INT32SZ; /* TTL */

View File

@ -0,0 +1,289 @@
commit 3005466abe8fb80ad4ff51865f1e28dd81c43347
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Sep 6 15:11:44 2017 +0200
nss_dns: Remove dead PTR IPv4-to-IPv6 mapping code
(cherry picked from commit c77eb96925b719001237ca7c9e3cef40d795d66b)
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 7cd54ab5048dcd37..1e85e4f08ffc8600 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -889,19 +889,6 @@ getanswer_r (struct resolv_context *ctx,
/* bind would put multiple PTR records as aliases, but we don't do
that. */
result->h_name = bp;
- if (have_to_map)
- {
- n = strlen (bp) + 1; /* for the \0 */
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
- {
- ++had_error;
- break;
- }
- bp += n;
- linebuflen -= n;
- if (map_v4v6_hostent (result, &bp, &linebuflen))
- goto too_small;
- }
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
case T_A:
diff --git a/resolv/tst-res_use_inet6.c b/resolv/tst-res_use_inet6.c
index 1522d5c5f5e4d860..d819f921d6e6746d 100644
--- a/resolv/tst-res_use_inet6.c
+++ b/resolv/tst-res_use_inet6.c
@@ -16,31 +16,101 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <ctype.h>
#include <netdb.h>
#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <support/check.h>
#include <support/check_nss.h>
#include <support/resolv_test.h>
+#include <support/support.h>
#include <support/xthread.h>
+/* Handle IPv4 reverse lookup responses. Product a PTR record
+ A-B-C-D.v4.example. */
+static void
+response_ptr_v4 (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ int bytes[4];
+ int offset = -1;
+ TEST_VERIFY (sscanf (qname, "%d.%d.%d.%d.in-addr.arpa%n",
+ bytes + 0, bytes + 1, bytes + 2, bytes + 3,
+ &offset) == 4);
+ TEST_VERIFY (offset == strlen (qname));
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, T_PTR, 0);
+ char *name = xasprintf ("%d-%d-%d-%d.v4.example",
+ bytes[3], bytes[2], bytes[1], bytes[0]);
+ resolv_response_add_name (b, name);
+ free (name);
+ resolv_response_close_record (b);
+}
+
+/* Handle IPv6 reverse lookup responses. Produce a PTR record
+ <32 hex digits>.v6.example. */
+static void
+response_ptr_v6 (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+
+ TEST_VERIFY_EXIT (strlen (qname) > 64);
+
+ char bytes[33];
+ for (int i = 0; i < 64; ++i)
+ if ((i % 2) == 0)
+ {
+ TEST_VERIFY (isxdigit ((unsigned char) qname[i]));
+ bytes[31 - i / 2] = qname[i];
+ }
+ else
+ TEST_VERIFY_EXIT (qname[i] == '.');
+ bytes[32] = '\0';
+
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, T_PTR, 0);
+ char *name = xasprintf ("%s.v6.example", bytes);
+ resolv_response_add_name (b, name);
+ free (name);
+ resolv_response_close_record (b);
+}
+
/* Produce a response based on QNAME: Certain characters in the first
label of QNAME trigger the inclusion of resource records:
'a' A record (IPv4 address)
'q' AAAA record (quad A record, IPv6 address)
+ 'p' PTR record
'm' record type must match QTYPE (no additional records)
+ '6' stop flag processing if QTYPE == AAAA
+
+ For 'a' and 'q', QTYPE is ignored for record type selection if 'm'
+ is not specified.
- QTYPE is ignored for record type selection if 'm' is not
- specified. */
+ in-addr.arpa and ip6.arpa queries are handled separately in
+ response_ptr_v4 and response_ptr_v6. */
static void
response (const struct resolv_response_context *ctx,
struct resolv_response_builder *b,
const char *qname, uint16_t qclass, uint16_t qtype)
{
+ if (strstr (qname, ".in-addr.arpa") != NULL)
+ return response_ptr_v4 (ctx, b, qname, qclass, qtype);
+ else if (strstr (qname, ".ip6.arpa") != NULL)
+ return response_ptr_v6 (ctx, b, qname, qclass, qtype);
+
bool include_a = false;
bool include_aaaa = false;
bool include_match = false;
+ bool include_ptr = false;
for (const char *p = qname; *p != '.' && *p != '\0'; ++p)
{
if (*p == 'a')
@@ -49,6 +119,10 @@ response (const struct resolv_response_context *ctx,
include_aaaa = true;
else if (*p == 'm')
include_match = true;
+ else if (*p == 'p')
+ include_ptr = true;
+ else if (*p == '6' && qtype == T_AAAA)
+ break;
}
if (include_match)
{
@@ -70,11 +144,17 @@ response (const struct resolv_response_context *ctx,
}
if (include_aaaa)
{
- char ipv6[16]
- = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
- resolv_response_open_record (b, qname, qclass, T_AAAA, 0);
- resolv_response_add_data (b, &ipv6, sizeof (ipv6));
- resolv_response_close_record (b);
+ char ipv6[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ resolv_response_open_record (b, qname, qclass, T_AAAA, 0);
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+ resolv_response_close_record (b);
+ }
+ if (include_ptr)
+ {
+ resolv_response_open_record (b, qname, qclass, T_PTR, 0);
+ resolv_response_add_name (b, "ptr-target.example");
+ resolv_response_close_record (b);
}
}
@@ -162,6 +242,65 @@ test_gai (void)
}
}
+/* Test gethostbyaddr and getnameinfo. The results are independent of
+ RES_USE_INET6. */
+static void
+test_reverse (void)
+{
+ {
+ char ipv4[4] = { 192, 0, 2, 17 };
+ check_hostent ("gethostbyaddr AF_INET",
+ gethostbyaddr (ipv4, sizeof (ipv4), AF_INET),
+ "name: 192-0-2-17.v4.example\n"
+ "address: 192.0.2.17\n");
+ }
+ {
+ char ipv6[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ check_hostent ("gethostbyaddr AF_INET",
+ gethostbyaddr (ipv6, sizeof (ipv6), AF_INET6),
+ "name: 20010db8000000000000000000000001.v6.example\n"
+ "address: 2001:db8::1\n");
+ }
+
+ {
+ struct sockaddr_in addr =
+ {
+ .sin_family = AF_INET,
+ .sin_addr = { .s_addr = htonl (0xc0000211) },
+ .sin_port = htons (80)
+ };
+ char host[NI_MAXHOST];
+ char service[NI_MAXSERV];
+ int ret = getnameinfo ((struct sockaddr *) &addr, sizeof (addr),
+ host, sizeof (host), service, sizeof (service),
+ NI_NUMERICSERV);
+ TEST_VERIFY (ret == 0);
+ TEST_VERIFY (strcmp (host, "192-0-2-17.v4.example") == 0);
+ TEST_VERIFY (strcmp (service, "80") == 0);
+ }
+ {
+ char ipv6[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ struct sockaddr_in6 addr =
+ {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons (80),
+ };
+ TEST_VERIFY (sizeof (ipv6) == sizeof (addr.sin6_addr));
+ memcpy (&addr.sin6_addr, ipv6, sizeof (addr.sin6_addr));
+ char host[NI_MAXHOST];
+ char service[NI_MAXSERV];
+ int ret = getnameinfo ((struct sockaddr *) &addr, sizeof (addr),
+ host, sizeof (host), service, sizeof (service),
+ NI_NUMERICSERV);
+ TEST_VERIFY (ret == 0);
+ TEST_VERIFY
+ (strcmp (host, "20010db8000000000000000000000001.v6.example") == 0);
+ TEST_VERIFY (strcmp (service, "80") == 0);
+ }
+}
+
/* Test that gethostbyname2 is mostly not influenced by
RES_USE_INET6. */
static void
@@ -207,6 +346,8 @@ test_get2_any (void)
"name: qa.example\n"
"address: 2001:db8::1\n");
/* Additional AF_INET6 tests depend on RES_USE_INET6; see below. */
+
+ test_reverse ();
}
/* gethostbyname2 tests with RES_USE_INET6 disabled. */
@@ -254,6 +395,10 @@ test_no_inet6 (void)
gethostbyname ("am.example"),
"name: am.example\n"
"address: 192.0.2.17\n");
+ check_hostent ("gethostbyname (\"amp.example\")",
+ gethostbyname ("amp.example"),
+ "name: amp.example\n"
+ "address: 192.0.2.17\n");
check_hostent ("gethostbyname (\"qam.example\")",
gethostbyname ("qam.example"),
"name: qam.example\n"
@@ -307,6 +452,28 @@ threadfunc (void *ignored)
gethostbyname ("qm.inet6.example"),
"name: qm.inet6.example\n"
"address: 2001:db8::1\n");
+ check_hostent ("gethostbyname (\"amp.inet6.example\")",
+ gethostbyname ("amp.inet6.example"),
+ "error: NO_RECOVERY\n");
+ check_hostent ("gethostbyname (\"qmp.inet6.example\")",
+ gethostbyname ("qmp.inet6.example"),
+ "name: qmp.inet6.example\n"
+ "address: 2001:db8::1\n");
+ check_hostent ("gethostbyname (\"ap.inet6.example\")",
+ gethostbyname ("ap.inet6.example"),
+ "error: NO_RECOVERY\n");
+ check_hostent ("gethostbyname (\"6ap.inet6.example\")",
+ gethostbyname ("6ap.inet6.example"),
+ "name: 6ap.inet6.example\n"
+ "address: ::ffff:192.0.2.17\n");
+ check_hostent ("gethostbyname (\"am6p.inet6.example\")",
+ gethostbyname ("am6p.inet6.example"),
+ "name: am6p.inet6.example\n"
+ "address: ::ffff:192.0.2.17\n");
+ check_hostent ("gethostbyname (\"qp.inet6.example\")",
+ gethostbyname ("qp.inet6.example"),
+ "name: qp.inet6.example\n"
+ "address: 2001:db8::1\n");
test_get2_inet6 ();
test_get2_inet6 ();
test_gai ();

View File

@ -0,0 +1,72 @@
commit 44f28da7cab271b659551c4fe1a7d2e420803576
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Apr 4 14:36:02 2017 +0200
nss_dns: Replace local declarations with declarations from a header file
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index cd7ab6e925b25687..7a8290e1f26070e0 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -51,6 +51,9 @@ extern const struct _ns_flagdata _ns_flagdata[] attribute_hidden;
extern unsigned int __ns_get16 (const unsigned char *) __THROW;
extern unsigned long __ns_get32 (const unsigned char *) __THROW;
+int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
+int __ns_name_unpack (const unsigned char *, const unsigned char *,
+ const unsigned char *, unsigned char *, size_t) __THROW;
#define ns_msg_getflag(handle, flag) \
(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 01864dc96e639873..705b3c9c078c41bf 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -80,6 +80,7 @@
#include <string.h>
#include "nsswitch.h"
+#include <arpa/nameser.h>
/* Get implementeation for some internal functions. */
#include <resolv/resolv-internal.h>
@@ -106,13 +107,6 @@ typedef union querybuf
u_char buf[MAXPACKET];
} querybuf;
-/* These functions are defined in res_comp.c. */
-#define NS_MAXCDNAME 255 /* maximum compressed domain name */
-extern int __ns_name_ntop (const u_char *, char *, size_t);
-extern int __ns_name_unpack (const u_char *, const u_char *,
- const u_char *, u_char *, size_t);
-
-
static enum nss_status getanswer_r (const querybuf *answer, int anslen,
const char *qname, int qtype,
struct hostent *result, char *buffer,
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index fd8c5656c0cedd27..2be72d33a30f917e 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -66,6 +66,7 @@
#include "nsswitch.h"
#include <arpa/inet.h>
+#include <arpa/nameser.h>
/* Maximum number of aliases we allow. */
#define MAX_NR_ALIASES 48
@@ -92,13 +93,6 @@ typedef union querybuf
u_char buf[MAXPACKET];
} querybuf;
-/* These functions are defined in res_comp.c. */
-#define NS_MAXCDNAME 255 /* maximum compressed domain name */
-extern int __ns_name_ntop (const u_char *, char *, size_t) __THROW;
-extern int __ns_name_unpack (const u_char *, const u_char *,
- const u_char *, u_char *, size_t) __THROW;
-
-
/* Prototypes for local functions. */
static enum nss_status getanswer_r (const querybuf *answer, int anslen,
struct netent *result, char *buffer,

View File

@ -0,0 +1,217 @@
commit 44500cbb25bc6e76723304b9ff39f875c04309f9
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 13 13:22:51 2017 +0200
resolv: Remove EDNS fallback [BZ #21369]
EDNS is disabled by default (so there is interoperability issue), and
the fallback code is problematic because it prevents an application
from obtaining DNSSEC data after a FORMERR response.
diff --git a/resolv/res_query.c b/resolv/res_query.c
index c3ebcbf6b50fcf4b..ec65bab04153c2ff 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -122,7 +122,6 @@ __libc_res_nquery(res_state statp,
HEADER *hp = (HEADER *) answer;
HEADER *hp2;
int n, use_malloc = 0;
- u_int oflags = statp->_flags;
size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE;
u_char *buf = alloca (bufsize);
@@ -145,8 +144,7 @@ __libc_res_nquery(res_state statp,
query1, bufsize);
if (n > 0)
{
- if ((oflags & RES_F_EDNS0ERR) == 0
- && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
+ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
{
/* Use RESOLV_EDNS_BUFFER_SIZE because the receive
buffer can be reallocated. */
@@ -170,7 +168,6 @@ __libc_res_nquery(res_state statp,
n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
NULL, query2, bufsize - nused);
if (n > 0
- && (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
/* Use RESOLV_EDNS_BUFFER_SIZE because the receive
buffer can be reallocated. */
@@ -187,7 +184,6 @@ __libc_res_nquery(res_state statp,
query1, bufsize);
if (n > 0
- && (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
{
/* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
@@ -215,16 +211,6 @@ __libc_res_nquery(res_state statp,
}
}
if (__glibc_unlikely (n <= 0)) {
- /* If the query choked with EDNS0, retry without EDNS0. */
- if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0
- && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
- statp->_flags |= RES_F_EDNS0ERR;
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_nquery: retry without EDNS0\n");
-#endif
- goto again;
- }
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_query: mkquery failed\n");
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 77d59dcc4e3b8d23..98968d6239d0c8f7 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -1321,26 +1321,6 @@ send_dg(res_state statp,
? *thisanssizp : *thisresplenp);
goto wait;
}
-#ifdef RES_USE_EDNS0
- if (anhp->rcode == FORMERR
- && (statp->options & RES_USE_EDNS0) != 0U) {
- /*
- * Do not retry if the server does not understand
- * EDNS0. The case has to be captured here, as
- * FORMERR packet do not carry query section, hence
- * res_queriesmatch() returns 0.
- */
- DprintQ(statp->options & RES_DEBUG,
- (stdout,
- "server rejected query with EDNS0:\n"),
- *thisansp,
- (*thisresplenp > *thisanssizp)
- ? *thisanssizp : *thisresplenp);
- /* record the error */
- statp->_flags |= RES_F_EDNS0ERR;
- return close_and_return_error (statp, resplen2);
- }
-#endif
if (!(statp->options & RES_INSECURE2)
&& (recvresp1 || !res_queriesmatch(buf, buf + buflen,
*thisansp,
diff --git a/resolv/tst-resolv-edns.c b/resolv/tst-resolv-edns.c
index f17dbc3450f52b85..093a4f5f22aaaa51 100644
--- a/resolv/tst-resolv-edns.c
+++ b/resolv/tst-resolv-edns.c
@@ -115,8 +115,23 @@ response (const struct resolv_response_context *ctx,
{
TEST_VERIFY_EXIT (qname != NULL);
- /* The "tcp." prefix can be used to request TCP fallback. */
const char *qname_compare = qname;
+
+ /* The "formerr." prefix can be used to request a FORMERR response on the
+ first server. */
+ bool send_formerr;
+ if (strncmp ("formerr.", qname, strlen ("formerr.")) == 0)
+ {
+ send_formerr = true;
+ qname_compare = qname + strlen ("formerr.");
+ }
+ else
+ {
+ send_formerr = false;
+ qname_compare = qname;
+ }
+
+ /* The "tcp." prefix can be used to request TCP fallback. */
bool force_tcp;
if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0)
{
@@ -132,14 +147,20 @@ response (const struct resolv_response_context *ctx,
else
{
support_record_failure ();
- printf ("error: unexpected QNAME: %s\n", qname);
+ printf ("error: unexpected QNAME: %s (reduced: %s)\n",
+ qname, qname_compare);
return;
}
TEST_VERIFY_EXIT (qclass == C_IN);
- struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp};
+ struct resolv_response_flags flags = { };
+ flags.tc = force_tcp && !ctx->tcp;
+ if (!flags.tc && send_formerr && ctx->server_index == 0)
+ /* Send a FORMERR for the first full response from the first
+ server. */
+ flags.rcode = 1; /* FORMERR */
resolv_response_init (b, flags);
resolv_response_add_question (b, qname, qclass, qtype);
- if (flags.tc)
+ if (flags.tc || flags.rcode != 0)
return;
if (test_verbose)
@@ -466,33 +487,42 @@ do_test (void)
for (int do_edns = 0; do_edns < 2; ++do_edns)
for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec)
for (int do_tcp = 0; do_tcp < 2; ++do_tcp)
- {
- struct resolv_test *aux = resolv_test_start
- ((struct resolv_redirect_config)
- {
- .response_callback = response,
- });
-
- use_edns = do_edns;
- if (do_edns)
- _res.options |= RES_USE_EDNS0;
- use_dnssec = do_dnssec;
- if (do_dnssec)
- _res.options |= RES_USE_DNSSEC;
-
- char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
- if (do_tcp)
- {
- char *n = xasprintf ("tcp.%s", probe_name);
- free (probe_name);
- probe_name = n;
- }
+ for (int do_formerr = 0; do_formerr < 2; ++do_formerr)
+ {
+ struct resolv_test *aux = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response,
+ });
+
+ use_edns = do_edns;
+ if (do_edns)
+ _res.options |= RES_USE_EDNS0;
+ use_dnssec = do_dnssec;
+ if (do_dnssec)
+ _res.options |= RES_USE_DNSSEC;
+
+ char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
+ if (do_tcp)
+ {
+ char *n = xasprintf ("tcp.%s", probe_name);
+ free (probe_name);
+ probe_name = n;
+ }
+ if (do_formerr)
+ {
+ /* Send a garbage query in an attempt to trigger EDNS
+ fallback. */
+ char *n = xasprintf ("formerr.%s", probe_name);
+ gethostbyname (n);
+ free (n);
+ }
- run_test (probe_name);
+ run_test (probe_name);
- free (probe_name);
- resolv_test_end (aux);
- }
+ free (probe_name);
+ resolv_test_end (aux);
+ }
free_response_data ();
return 0;

View File

@ -0,0 +1,35 @@
commit e4e794841e3140875f2aa86b90e2ada3d61e1244
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Apr 7 13:01:21 2017 +0200
resolv: Remove IQUERY support
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 5a0bb1044b55a643..8279d15de4271c84 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -188,24 +188,6 @@ res_nmkquery(res_state statp,
hp->arcount = htons(1);
break;
- case IQUERY:
- /*
- * Initialize answer section
- */
- if (__glibc_unlikely (buflen < 1 + RRFIXEDSZ + datalen))
- return (-1);
- *cp++ = '\0'; /* no domain name */
- NS_PUT16 (type, cp);
- NS_PUT16 (class, cp);
- NS_PUT32 (0, cp);
- NS_PUT16 (datalen, cp);
- if (datalen) {
- memcpy(cp, data, datalen);
- cp += datalen;
- }
- hp->ancount = htons(1);
- break;
-
default:
return (-1);
}

View File

@ -0,0 +1,232 @@
commit e4e5b57d23b4ebdbf773fedba91160158f95af94
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 13:17:49 2017 +0200
resolv: Move _res deallocation functions to their own file
diff --git a/resolv/Makefile b/resolv/Makefile
index c2a8a3a631f6bb2e..f9d8bceb9b4bc8b0 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -28,7 +28,7 @@ headers := resolv.h \
sys/bitypes.h
routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
- res_hconf res_libc res-state res_randomid
+ res_hconf res_libc res-state res_randomid res-close
tests = tst-aton tst-leaks tst-inet_ntop
xtests = tst-leaks2
diff --git a/resolv/res-close.c b/resolv/res-close.c
new file mode 100644
index 0000000000000000..73f18d15256c6f87
--- /dev/null
+++ b/resolv/res-close.c
@@ -0,0 +1,137 @@
+/* Deallocation functions for the resolver state.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <resolv-internal.h>
+#include <not-cancel.h>
+
+/* Close all open sockets. If FREE_ADDR is true, deallocate any
+ separately allocated name server addresses. */
+void
+__res_iclose (res_state statp, bool free_addr)
+{
+ if (statp->_vcsock >= 0)
+ {
+ close_not_cancel_no_status (statp->_vcsock);
+ statp->_vcsock = -1;
+ statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+ }
+ for (int ns = 0; ns < statp->nscount; ns++)
+ if (statp->_u._ext.nsaddrs[ns] != NULL)
+ {
+ if (statp->_u._ext.nssocks[ns] != -1)
+ {
+ close_not_cancel_no_status (statp->_u._ext.nssocks[ns]);
+ statp->_u._ext.nssocks[ns] = -1;
+ }
+ if (free_addr)
+ {
+ free (statp->_u._ext.nsaddrs[ns]);
+ statp->_u._ext.nsaddrs[ns] = NULL;
+ }
+ }
+}
+libc_hidden_def (__res_iclose)
+
+void
+res_nclose (res_state statp)
+{
+ __res_iclose (statp, true);
+}
+libc_hidden_def (__res_nclose)
+
+/* This is called when a thread is exiting to free resources held in _res. */
+static void __attribute__ ((section ("__libc_thread_freeres_fn")))
+res_thread_freeres (void)
+{
+ if (_res.nscount == 0)
+ /* Never called res_ninit. */
+ return;
+
+ __res_iclose (&_res, true); /* Close any VC sockets. */
+
+ /* Make sure we do a full re-initialization the next time. */
+ _res.options = 0;
+}
+text_set_element (__libc_thread_subfreeres, res_thread_freeres);
+text_set_element (__libc_subfreeres, res_thread_freeres);
diff --git a/resolv/res_init.c b/resolv/res_init.c
index ef2e7c0db465dba6..eb380d3d56bc018c 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -83,8 +83,6 @@
#include <sys/types.h>
#include <inet/net-internal.h>
-#include <not-cancel.h>
-
/* Options. Should all be left alone. */
/* #undef DEBUG */
@@ -478,56 +476,3 @@ net_mask (struct in_addr in)
return (htonl(IN_CLASSB_NET));
return (htonl(IN_CLASSC_NET));
}
-
-/*
- * This routine is for closing the socket if a virtual circuit is used and
- * the program wants to close it. This provides support for endhostent()
- * which expects to close the socket.
- *
- * This routine is not expected to be user visible.
- */
-void
-__res_iclose(res_state statp, bool free_addr) {
- int ns;
-
- if (statp->_vcsock >= 0) {
- close_not_cancel_no_status(statp->_vcsock);
- statp->_vcsock = -1;
- statp->_flags &= ~(RES_F_VC | RES_F_CONN);
- }
- for (ns = 0; ns < statp->nscount; ns++)
- if (statp->_u._ext.nsaddrs[ns]) {
- if (statp->_u._ext.nssocks[ns] != -1) {
- close_not_cancel_no_status(statp->_u._ext.nssocks[ns]);
- statp->_u._ext.nssocks[ns] = -1;
- }
- if (free_addr) {
- free (statp->_u._ext.nsaddrs[ns]);
- statp->_u._ext.nsaddrs[ns] = NULL;
- }
- }
-}
-libc_hidden_def (__res_iclose)
-
-void
-res_nclose(res_state statp)
-{
- __res_iclose (statp, true);
-}
-libc_hidden_def (__res_nclose)
-
-/* This is called when a thread is exiting to free resources held in _res. */
-static void __attribute__ ((section ("__libc_thread_freeres_fn")))
-res_thread_freeres (void)
-{
- if (_res.nscount == 0)
- /* Never called res_ninit. */
- return;
-
- __res_iclose (&_res, true); /* Close any VC sockets. */
-
- /* Make sure we do a full re-initialization the next time. */
- _res.options = 0;
-}
-text_set_element (__libc_thread_subfreeres, res_thread_freeres);
-text_set_element (__libc_subfreeres, res_thread_freeres);

View File

@ -0,0 +1,66 @@
commit 6da48ca0b2cf328d9ef43c510e74a858c77a1e96
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:32:04 2017 +0200
resolv: Reformat resolv/res_data.c to GNU style
diff --git a/resolv/res_data.c b/resolv/res_data.c
index 5e7688c706bf8e99..2cafd3805548d8e4 100644
--- a/resolv/res_data.c
+++ b/resolv/res_data.c
@@ -1,3 +1,21 @@
+/* Miscellaneous definitions for libresolv.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
/*
* Copyright (c) 1995-1999 by Internet Software Consortium.
*
@@ -17,18 +35,20 @@
#include <resolv.h>
+/* This function belongs to libresolv, which is why it is not included
+ in res-close.c. */
void
-res_close(void) {
- /*
- * Some stupid programs out there call res_close() before res_init().
- * Since _res._vcsock isn't explicitly initialized, these means that
- * we could do a close(0), which might lead to some security problems.
- * Therefore we check if res_init() was called before by looking at
- * the RES_INIT bit in _res.options. If it hasn't been set we bail out
- * early. */
- if ((_res.options & RES_INIT) == 0)
- return;
- /* We don't free the name server addresses because we never
- did it and it would be done implicitly on shutdown. */
- __res_iclose(&_res, false);
+__res_close (void)
+{
+ /* Some programs call res_close before res_init. Since _res._vcsock
+ isn't explicitly initialized, these means that we could call
+ close (0), which might lead to some security problems. Therefore
+ we check if res_init was called before by looking at the RES_INIT
+ bit in _res.options. If it hasn't been set we bail out
+ early. */
+ if ((_res.options & RES_INIT) == 0)
+ return;
+ /* We don't free the name server addresses because we never did it
+ and it would be done implicitly on shutdown. */
+ __res_iclose (&_res, false);
}

View File

@ -0,0 +1,58 @@
commit 4d4ce84924dbde90294522598212e997b5f719e9
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:29 2017 +0200
resolv: Remove unused resolv/res_debug.h header file
diff --git a/resolv/README b/resolv/README
index c50025168cd2b99e..514e9bb617e710f1 100644
--- a/resolv/README
+++ b/resolv/README
@@ -114,7 +114,6 @@ src/lib/resolv/
res_comp.c
res_data.c
res_debug.c
- res_debug.h
res_init.c
res_mkquery.c
res_query.c
diff --git a/resolv/res_debug.h b/resolv/res_debug.h
deleted file mode 100644
index 2d8ad15d60dc3b79..0000000000000000
--- a/resolv/res_debug.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-#ifndef _RES_DEBUG_H_
-#define _RES_DEBUG_H_
-
-#ifndef DEBUG
-# define Dprint(cond, args) /*empty*/
-# define DprintQ(cond, args, query, size) /*empty*/
-# define Aerror(statp, file, string, error, address) /*empty*/
-# define Perror(statp, file, string, error) /*empty*/
-#else
-# define Dprint(cond, args) if (cond) {fprintf args;} else {}
-# define DprintQ(cond, args, query, size) if (cond) {\
- fprintf args;\
- res_pquery(statp, query, size, stdout);\
- } else {}
-#endif
-
-#endif /* _RES_DEBUG_H_ */

View File

@ -0,0 +1,28 @@
commit 0ad970bb13920b6471ccc4503cf1f0d8b2352f05
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue May 9 12:28:01 2017 +0200
resolv: Use RES_DFLRETRY consistently [BZ #21474]
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index a4b376f15b0b0e98..c52574f895d4f19d 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -65,7 +65,7 @@ res_init(void) {
if (!_res.retrans)
_res.retrans = RES_TIMEOUT;
if (!_res.retry)
- _res.retry = 4;
+ _res.retry = RES_DFLRETRY;
if (!(_res.options & RES_INIT))
_res.options = RES_DEFAULT;
else if (_res.nscount > 0)
@@ -103,7 +103,7 @@ __res_maybe_init (res_state resp, int preinit)
if (!resp->retrans)
resp->retrans = RES_TIMEOUT;
if (!resp->retry)
- resp->retry = 4;
+ resp->retry = RES_DFLRETRY;
resp->options = RES_DEFAULT;
if (!resp->id)
resp->id = res_randomid ();

View File

@ -0,0 +1,691 @@
commit 2714c5f3c95f90977167c1d21326d907fb76b419
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 2 15:50:36 2017 +0200
resolv: Tests for various versions of res_init
diff --git a/resolv/Makefile b/resolv/Makefile
index d41fd4603d7b7d77..0ebb2af795c6fb7b 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -57,6 +57,11 @@ ifeq (yes,$(build-shared))
tests += \
tst-resolv-canonname \
+# uses DEPRECATED_RES_USE_INET6 from <resolv-internal.h>.
+tests += \
+ tst-resolv-res_init \
+ tst-resolv-res_init-thread \
+
endif
# This test sends millions of packets and is rather slow.
@@ -136,6 +141,9 @@ $(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-res_init: $(libdl) $(objpfx)libresolv.so
+$(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
+ $(shared-thread-library)
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-canonname: \
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
new file mode 100644
index 0000000000000000..1d2c475c4b233131
--- /dev/null
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -0,0 +1,601 @@
+/* Test parsing of /etc/resolv.conf. Genric version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Before including this file, TEST_THREAD has to be defined to 0 or
+ 1, depending on whether the threading tests should be compiled
+ in. */
+
+#include <arpa/inet.h>
+#include <gnu/lib-names.h>
+#include <netdb.h>
+#include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/run_diff.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+#if TEST_THREAD
+# include <support/xthread.h>
+#endif
+
+/* This is the host name used to ensure predictable behavior of
+ res_init. */
+static const char *const test_hostname = "www.example.com";
+
+/* Path to the test root directory. */
+static char *path_chroot;
+
+/* Path to resolv.conf under path_chroot (outside the chroot). */
+static char *path_resolv_conf;
+
+static void
+prepare (int argc, char **argv)
+{
+ path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
+ if (mkdtemp (path_chroot) == NULL)
+ FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", path_chroot);
+ add_temp_file (path_chroot);
+
+ /* Create the /etc directory in the chroot environment. */
+ char *path_etc = xasprintf ("%s/etc", path_chroot);
+ xmkdir (path_etc, 0777);
+ add_temp_file (path_etc);
+
+ /* Create an empty resolv.conf file. */
+ path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc);
+ add_temp_file (path_resolv_conf);
+ support_write_file_string (path_resolv_conf, "");
+
+ free (path_etc);
+
+ /* valgrind needs a temporary directory in the chroot. */
+ {
+ char *path_tmp = xasprintf ("%s/tmp", path_chroot);
+ xmkdir (path_tmp, 0777);
+ add_temp_file (path_tmp);
+ free (path_tmp);
+ }
+}
+
+/* Verify that the chroot environment has been set up. */
+static void
+check_chroot_working (void *closure)
+{
+ xchroot (path_chroot);
+ FILE *fp = xfopen (_PATH_RESCONF, "r");
+ xfclose (fp);
+
+ TEST_VERIFY_EXIT (res_init () == 0);
+ TEST_VERIFY (_res.options & RES_INIT);
+
+ char buf[100];
+ if (gethostname (buf, sizeof (buf)) < 0)
+ FAIL_EXIT1 ("gethostname: %m");
+ if (strcmp (buf, test_hostname) != 0)
+ FAIL_EXIT1 ("unexpected host name: %s", buf);
+}
+
+/* If FLAG is set in *OPTIONS, write NAME to FP, and clear it in
+ *OPTIONS. */
+static void
+print_option_flag (FILE *fp, int *options, int flag, const char *name)
+{
+ if (*options & flag)
+ {
+ fprintf (fp, " %s", name);
+ *options &= ~flag;
+ }
+}
+
+/* Write a decoded version of the resolver configuration *RESP to the
+ stream FP. */
+static void
+print_resp (FILE *fp, res_state resp)
+{
+ /* The options directive. */
+ {
+ /* RES_INIT is used internally for tracking initialization. */
+ TEST_VERIFY (resp->options & RES_INIT);
+ /* Also mask out other default flags which cannot be set through
+ the options directive. */
+ int options
+ = resp->options & ~(RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH);
+ if (options != 0
+ || resp->ndots != 1
+ || resp->retrans != RES_TIMEOUT
+ || resp->retry != RES_DFLRETRY)
+ {
+ fputs ("options", fp);
+ if (resp->ndots != 1)
+ fprintf (fp, " ndots:%d", resp->ndots);
+ if (resp->retrans != RES_TIMEOUT)
+ fprintf (fp, " timeout:%d", resp->retrans);
+ if (resp->retry != RES_DFLRETRY)
+ fprintf (fp, " attempts:%d", resp->retry);
+ print_option_flag (fp, &options, RES_USEVC, "use-vc");
+ print_option_flag (fp, &options, DEPRECATED_RES_USE_INET6, "inet6");
+ print_option_flag (fp, &options, RES_ROTATE, "rotate");
+ print_option_flag (fp, &options, RES_USE_EDNS0, "edns0");
+ print_option_flag (fp, &options, RES_SNGLKUP,
+ "single-request");
+ print_option_flag (fp, &options, RES_SNGLKUPREOP,
+ "single-request-reopen");
+ print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query");
+ fputc ('\n', fp);
+ if (options != 0)
+ fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
+ }
+ }
+
+ /* The search and domain directives. */
+ if (resp->dnsrch[0] != NULL)
+ {
+ fputs ("search", fp);
+ for (int i = 0; i < MAXDNSRCH && resp->dnsrch[i] != NULL; ++i)
+ {
+ fputc (' ', fp);
+ fputs (resp->dnsrch[i], fp);
+ }
+ fputc ('\n', fp);
+ }
+ else if (resp->defdname[0] != '\0')
+ fprintf (fp, "domain %s\n", resp->defdname);
+
+ /* The sortlist directive. */
+ if (resp->nsort > 0)
+ {
+ fputs ("sortlist", fp);
+ for (int i = 0; i < resp->nsort && i < MAXRESOLVSORT; ++i)
+ {
+ char net[20];
+ if (inet_ntop (AF_INET, &resp->sort_list[i].addr,
+ net, sizeof (net)) == NULL)
+ FAIL_EXIT1 ("inet_ntop: %m\n");
+ char mask[20];
+ if (inet_ntop (AF_INET, &resp->sort_list[i].mask,
+ mask, sizeof (mask)) == NULL)
+ FAIL_EXIT1 ("inet_ntop: %m\n");
+ fprintf (fp, " %s/%s", net, mask);
+ }
+ fputc ('\n', fp);
+ }
+
+ /* The nameserver directives. */
+ for (size_t i = 0; i < resp->nscount; ++i)
+ {
+ char host[NI_MAXHOST];
+ char service[NI_MAXSERV];
+
+ /* See get_nsaddr in res_send.c. */
+ void *addr;
+ size_t addrlen;
+ if (resp->nsaddr_list[i].sin_family == 0
+ && resp->_u._ext.nsaddrs[i] != NULL)
+ {
+ addr = resp->_u._ext.nsaddrs[i];
+ addrlen = sizeof (*resp->_u._ext.nsaddrs[i]);
+ }
+ else
+ {
+ addr = &resp->nsaddr_list[i];
+ addrlen = sizeof (resp->nsaddr_list[i]);
+ }
+
+ int ret = getnameinfo (addr, addrlen,
+ host, sizeof (host), service, sizeof (service),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (ret != 0)
+ {
+ if (ret == EAI_SYSTEM)
+ fprintf (fp, "; error: getnameinfo: %m\n");
+ else
+ fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
+ }
+ else
+ {
+ fprintf (fp, "nameserver %s\n", host);
+ if (strcmp (service, "53") != 0)
+ fprintf (fp, "; unrepresentable port number %s\n\n", service);
+ }
+ }
+
+ TEST_VERIFY (!ferror (fp));
+}
+
+/* Parameters of one test case. */
+struct test_case
+{
+ /* A short, descriptive name of the test. */
+ const char *name;
+
+ /* The contents of the /etc/resolv.conf file. */
+ const char *conf;
+
+ /* The expected output from print_resp. */
+ const char *expected;
+
+ /* Setting for the LOCALDOMAIN environment variable. NULL if the
+ variable is not to be set. */
+ const char *localdomain;
+
+ /* Setting for the RES_OPTIONS environment variable. NULL if the
+ variable is not to be set. */
+ const char *res_options;
+};
+
+enum test_init
+{
+ test_init,
+ test_ninit,
+ test_mkquery,
+ test_gethostbyname,
+ test_getaddrinfo,
+ test_init_method_last = test_getaddrinfo
+};
+
+/* Closure argument for run_res_init. */
+struct test_context
+{
+ enum test_init init;
+ const struct test_case *t;
+};
+
+static void
+setup_nss_dns_and_chroot (void)
+{
+ /* Load nss_dns outside of the chroot. */
+ if (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) == NULL)
+ FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
+ xchroot (path_chroot);
+ /* Force the use of nss_dns. */
+ __nss_configure_lookup ("hosts", "dns");
+}
+
+/* Run res_ninit or res_init in a subprocess and dump the parsed
+ resolver state to standard output. */
+static void
+run_res_init (void *closure)
+{
+ struct test_context *ctx = closure;
+ TEST_VERIFY (getenv ("LOCALDOMAIN") == NULL);
+ TEST_VERIFY (getenv ("RES_OPTIONS") == NULL);
+ if (ctx->t->localdomain != NULL)
+ setenv ("LOCALDOMAIN", ctx->t->localdomain, 1);
+ if (ctx->t->res_options != NULL)
+ setenv ("RES_OPTIONS", ctx->t->res_options, 1);
+
+ switch (ctx->init)
+ {
+ case test_init:
+ xchroot (path_chroot);
+ TEST_VERIFY (res_init () == 0);
+ print_resp (stdout, &_res);
+ return;
+
+ case test_ninit:
+ xchroot (path_chroot);
+ res_state resp = xmalloc (sizeof (*resp));
+ memset (resp, 0, sizeof (*resp));
+ TEST_VERIFY (res_ninit (resp) == 0);
+ print_resp (stdout, resp);
+ res_nclose (resp);
+ free (resp);
+ return;
+
+ case test_mkquery:
+ xchroot (path_chroot);
+ unsigned char buf[512];
+ TEST_VERIFY (res_mkquery (QUERY, "www.example",
+ C_IN, ns_t_a, NULL, 0,
+ NULL, buf, sizeof (buf)) > 0);
+ print_resp (stdout, &_res);
+ return;
+
+ case test_gethostbyname:
+ setup_nss_dns_and_chroot ();
+ /* Trigger implicit initialization of the _res structure. The
+ actual lookup result is immaterial. */
+ (void )gethostbyname ("www.example");
+ print_resp (stdout, &_res);
+ return;
+
+ case test_getaddrinfo:
+ setup_nss_dns_and_chroot ();
+ /* Trigger implicit initialization of the _res structure. The
+ actual lookup result is immaterial. */
+ struct addrinfo *ai;
+ (void) getaddrinfo ("www.example", NULL, NULL, &ai);
+ print_resp (stdout, &_res);
+ return;
+ }
+
+ FAIL_EXIT1 ("invalid init method %d", ctx->init);
+}
+
+#if TEST_THREAD
+/* Helper function which calls run_res_init from a thread. */
+static void *
+run_res_init_thread_func (void *closure)
+{
+ run_res_init (closure);
+ return NULL;
+}
+
+/* Variant of res_run_init which runs the function on a non-main
+ thread. */
+static void
+run_res_init_on_thread (void *closure)
+{
+ xpthread_join (xpthread_create (NULL, run_res_init_thread_func, closure));
+}
+#endif /* TEST_THREAD */
+
+struct test_case test_cases[] =
+ {
+ {.name = "empty file",
+ .conf = "",
+ .expected = "search example.com\n"
+ "nameserver 127.0.0.1\n"
+ },
+ {.name = "empty file with LOCALDOMAIN",
+ .conf = "",
+ .expected = "search example.net\n"
+ "nameserver 127.0.0.1\n",
+ .localdomain = "example.net",
+ },
+ {.name = "empty file with RES_OPTIONS",
+ .conf = "",
+ .expected = "options attempts:5 edns0\n"
+ "search example.com\n"
+ "nameserver 127.0.0.1\n",
+ .res_options = "edns0 attempts:5",
+ },
+ {.name = "empty file with RES_OPTIONS and LOCALDOMAIN",
+ .conf = "",
+ .expected = "options attempts:5 edns0\n"
+ "search example.org\n"
+ "nameserver 127.0.0.1\n",
+ .localdomain = "example.org",
+ .res_options = "edns0 attempts:5",
+ },
+ {.name = "basic",
+ .conf = "domain example.net\n"
+ "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n"
+ },
+ {.name = "whitespace",
+ .conf = "# This test covers comment and whitespace processing "
+ " (trailing whitespace,\n"
+ "# missing newline at end of file).\n"
+ "\n"
+ "domain example.net\n"
+ ";search commented out\n"
+ "search corp.example.com\texample.com\n"
+ "#nameserver 192.0.2.3\n"
+ "nameserver 192.0.2.1 \n"
+ "nameserver 192.0.2.2", /* No \n at end of file. */
+ .expected = "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n"
+ },
+ {.name = "option values, multiple servers",
+ .conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
+ "domain example.net\n"
+ ";domain comment\n"
+ "search corp.example.com\texample.com\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver ::1\n"
+ "nameserver 192.0.2.2\n",
+ .expected = "options ndots:3 timeout:19 attempts:5 inet6 edns0\n"
+ "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver ::1\n"
+ "nameserver 192.0.2.2\n"
+ },
+ {.name = "out-of-range option vales",
+ .conf = "options use-vc timeout:999 attempts:999 ndots:99\n"
+ "search example.com\n",
+ .expected = "options ndots:15 timeout:30 attempts:5 use-vc\n"
+ "search example.com\n"
+ "nameserver 127.0.0.1\n"
+ },
+ {.name = "repeated directives",
+ .conf = "options ndots:3 use-vc\n"
+ "options edns0 ndots:2\n"
+ "domain corp.example\n"
+ "search example.net corp.example.com example.com\n"
+ "search example.org\n"
+ "search\n",
+ .expected = "options ndots:2 use-vc edns0\n"
+ "search example.org\n"
+ "nameserver 127.0.0.1\n"
+ },
+ {.name = "many name servers, sortlist",
+ .conf = "options single-request\n"
+ "search example.org example.com example.net corp.example.com\n"
+ "sortlist 192.0.2.0/255.255.255.0\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n"
+ "nameserver 192.0.2.3\n"
+ "nameserver 192.0.2.4\n"
+ "nameserver 192.0.2.5\n"
+ "nameserver 192.0.2.6\n"
+ "nameserver 192.0.2.7\n"
+ "nameserver 192.0.2.8\n",
+ .expected = "options single-request\n"
+ "search example.org example.com example.net corp.example.com\n"
+ "sortlist 192.0.2.0/255.255.255.0\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n"
+ "nameserver 192.0.2.3\n"
+ },
+ {.name = "IPv4 and IPv6 nameservers",
+ .conf = "options single-request\n"
+ "search example.org example.com example.net corp.example.com"
+ " legacy.example.com\n"
+ "sortlist 192.0.2.0\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 2001:db8::2\n"
+ "nameserver 192.0.2.3\n"
+ "nameserver 2001:db8::4\n"
+ "nameserver 192.0.2.5\n"
+ "nameserver 2001:db8::6\n"
+ "nameserver 192.0.2.7\n"
+ "nameserver 2001:db8::8\n",
+ .expected = "options single-request\n"
+ "search example.org example.com example.net corp.example.com"
+ " legacy.example.com\n"
+ "sortlist 192.0.2.0/255.255.255.0\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 2001:db8::2\n"
+ "nameserver 192.0.2.3\n"
+ },
+ {.name = "garbage after nameserver",
+ .conf = "nameserver 192.0.2.1 garbage\n"
+ "nameserver 192.0.2.2:5353\n"
+ "nameserver 192.0.2.3 5353\n",
+ .expected = "search example.com\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.3\n"
+ },
+ {.name = "RES_OPTIONS is cummulative",
+ .conf = "options timeout:7 ndots:2 use-vc\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
+ "search example.com\n"
+ "nameserver 192.0.2.1\n",
+ .res_options = "attempts:5 ndots:3 edns0 ",
+ },
+ { NULL }
+ };
+
+/* Run the indicated test case. This function assumes that the chroot
+ contents has already been set up. */
+static void
+test_file_contents (const struct test_case *t)
+{
+#if TEST_THREAD
+ for (int do_thread = 0; do_thread < 2; ++do_thread)
+#endif
+ for (int init_method = 0; init_method <= test_init_method_last;
+ ++init_method)
+ {
+ if (test_verbose > 0)
+ printf ("info: testing init method %d\n", init_method);
+ struct test_context ctx = { .init = init_method, .t = t };
+ void (*func) (void *) = run_res_init;
+#if TEST_THREAD
+ if (do_thread)
+ func = run_res_init_on_thread;
+#endif
+ struct support_capture_subprocess proc
+ = support_capture_subprocess (func, &ctx);
+ if (strcmp (proc.out.buffer, t->expected) != 0)
+ {
+ support_record_failure ();
+ printf ("error: output mismatch for %s\n", t->name);
+ support_run_diff ("expected", t->expected,
+ "actual", proc.out.buffer);
+ }
+ support_capture_subprocess_check (&proc, t->name, 0,
+ sc_allow_stdout);
+ support_capture_subprocess_free (&proc);
+ }
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ support_enter_network_namespace ();
+ if (!support_in_uts_namespace () || !support_can_chroot ())
+ return EXIT_UNSUPPORTED;
+
+ /* We are in an UTS namespace, so we can set the host name without
+ altering the state of the entire system. */
+ if (sethostname (test_hostname, strlen (test_hostname)) != 0)
+ FAIL_EXIT1 ("sethostname: %m");
+
+ /* These environment variables affect resolv.conf parsing. */
+ unsetenv ("LOCALDOMAIN");
+ unsetenv ("RES_OPTIONS");
+
+ /* Ensure that the chroot setup worked. */
+ {
+ struct support_capture_subprocess proc
+ = support_capture_subprocess (check_chroot_working, NULL);
+ support_capture_subprocess_check (&proc, "chroot", 0, sc_allow_none);
+ support_capture_subprocess_free (&proc);
+ }
+
+ for (size_t i = 0; test_cases[i].name != NULL; ++i)
+ {
+ if (test_verbose > 0)
+ printf ("info: running test: %s\n", test_cases[i].name);
+ TEST_VERIFY (test_cases[i].conf != NULL);
+ TEST_VERIFY (test_cases[i].expected != NULL);
+
+ support_write_file_string (path_resolv_conf, test_cases[i].conf);
+
+ test_file_contents (&test_cases[i]);
+
+ /* The expected output from the empty file test is used for
+ further tests. */
+ if (test_cases[i].conf[0] == '\0')
+ {
+ if (test_verbose > 0)
+ printf ("info: special test: missing file\n");
+ TEST_VERIFY (unlink (path_resolv_conf) == 0);
+ test_file_contents (&test_cases[i]);
+
+ if (test_verbose > 0)
+ printf ("info: special test: dangling symbolic link\n");
+ TEST_VERIFY (symlink ("does-not-exist", path_resolv_conf) == 0);
+ test_file_contents (&test_cases[i]);
+ TEST_VERIFY (unlink (path_resolv_conf) == 0);
+
+ if (test_verbose > 0)
+ printf ("info: special test: unreadable file\n");
+ support_write_file_string (path_resolv_conf, "");
+ TEST_VERIFY (chmod (path_resolv_conf, 0) == 0);
+ test_file_contents (&test_cases[i]);
+
+ /* Restore the empty file. */
+ TEST_VERIFY (unlink (path_resolv_conf) == 0);
+ support_write_file_string (path_resolv_conf, "");
+ }
+ }
+
+ free (path_chroot);
+ path_chroot = NULL;
+ free (path_resolv_conf);
+ path_resolv_conf = NULL;
+ return 0;
+}
+
+#define PREPARE prepare
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-res_init-thread.c b/resolv/tst-resolv-res_init-thread.c
new file mode 100644
index 0000000000000000..f47ac34f7fc7a6c8
--- /dev/null
+++ b/resolv/tst-resolv-res_init-thread.c
@@ -0,0 +1,20 @@
+/* Test parsing of /etc/resolv.conf, threading version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define TEST_THREAD 1
+#include "tst-resolv-res_init-skeleton.c"
diff --git a/resolv/tst-resolv-res_init.c b/resolv/tst-resolv-res_init.c
new file mode 100644
index 0000000000000000..40c0154eca7363cb
--- /dev/null
+++ b/resolv/tst-resolv-res_init.c
@@ -0,0 +1,20 @@
+/* Test parsing of /etc/resolv.conf, non-threading version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define TEST_THREAD 0
+#include "tst-resolv-res_init-skeleton.c"

View File

@ -0,0 +1,66 @@
commit ded603542a8af41dc0c45af883d52390683f63aa
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:47 2017 +0200
resolv: Move res_isourserver, res_send from res_data.c to res_send.c
diff --git a/resolv/res_data.c b/resolv/res_data.c
index d05389e1347a57ab..b790b4b725bc9edd 100644
--- a/resolv/res_data.c
+++ b/resolv/res_data.c
@@ -45,22 +45,6 @@ res_query(const char *name, /* domain name */
return (res_nquery(&_res, name, class, type, answer, anslen));
}
-int
-res_isourserver(const struct sockaddr_in *inp) {
- return (res_ourserver_p(&_res, (const struct sockaddr_in6 *) inp));
-}
-
-int
-res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
- if (__res_maybe_init (&_res, 1) == -1) {
- /* errno should have been set by res_init() in this case. */
- return (-1);
- }
-
- return (res_nsend(&_res, buf, buflen, ans, anssiz));
-}
-
-
void
res_close(void) {
/*
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 18308709542da6e6..2e0b6c226105400a 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -244,6 +244,12 @@ res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
return (0);
}
+int
+res_isourserver (const struct sockaddr_in *inp)
+{
+ return res_ourserver_p (&_res, (const struct sockaddr_in6 *) inp);
+}
+
/* int
* res_nameinquery(name, type, class, buf, eom)
* look for (name,type,class) in the query section of packet (buf,eom)
@@ -545,6 +551,15 @@ res_nsend(res_state statp,
}
libresolv_hidden_def (res_nsend)
+int
+res_send (const unsigned char *buf, int buflen, unsigned char *ans, int anssiz)
+{
+ if (__res_maybe_init (&_res, 1) == -1)
+ /* errno should have been set by res_init in this case. */
+ return -1;
+ return res_nsend (&_res, buf, buflen, ans, anssiz);
+}
+
/* Private */
static struct sockaddr *

View File

@ -0,0 +1,184 @@
commit b87d47396f8e036a111fed8816254cfe1cf87cb2
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 23 18:10:41 2017 +0200
resolv/res_libc.c: Reformat to GNU style
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index 5202b756ff17518a..4b979f39a7c8e8ba 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -1,3 +1,21 @@
+/* Definitions related to res_init linked into libc instead of libresolv.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
/*
* Copyright (c) 1995-1999 by Internet Software Consortium.
*
@@ -15,9 +33,6 @@
* SOFTWARE.
*/
-/* This file contains the definitions related to res_init which are
- linked into libc instead of libresolv. */
-
#include <atomic.h>
#include <limits.h>
#include <sys/types.h>
@@ -40,74 +55,78 @@ __libc_lock_define_initialized (static, lock);
#endif
int
-res_init(void) {
- /*
- * These three fields used to be statically initialized. This made
- * it hard to use this code in a shared library. It is necessary,
- * now that we're doing dynamic initialization here, that we preserve
- * the old semantics: if an application modifies one of these three
- * fields of _res before res_init() is called, res_init() will not
- * alter them. Of course, if an application is setting them to
- * _zero_ before calling res_init(), hoping to override what used
- * to be the static default, we can't detect it and unexpected results
- * will follow. Zero for any of these fields would make no sense,
- * so one can safely assume that the applications were already getting
- * unexpected results.
- *
- * _res.options is tricky since some apps were known to diddle the bits
- * before res_init() was first called. We can't replicate that semantic
- * with dynamic initialization (they may have turned bits off that are
- * set in RES_DEFAULT). Our solution is to declare such applications
- * "broken". They could fool us by setting RES_INIT but none do (yet).
- */
- if (!_res.retrans)
- _res.retrans = RES_TIMEOUT;
- if (!_res.retry)
- _res.retry = RES_DFLRETRY;
- if (!(_res.options & RES_INIT))
- _res.options = RES_DEFAULT;
- else if (_res.nscount > 0)
- __res_iclose (&_res, true); /* Close any VC sockets. */
-
- /*
- * This one used to initialize implicitly to zero, so unless the app
- * has set it to something in particular, we can randomize it now.
- */
- if (!_res.id)
- _res.id = res_randomid();
-
- atomicinclock (lock);
- /* Request all threads to re-initialize their resolver states,
- resolv.conf might have changed. */
- atomicinc (__res_initstamp);
- atomicincunlock (lock);
-
- return (__res_vinit(&_res, 1));
+res_init (void)
+{
+ /* These three fields used to be statically initialized. This made
+ it hard to use this code in a shared library. It is necessary,
+ now that we're doing dynamic initialization here, that we
+ preserve the old semantics: if an application modifies one of
+ these three fields of _res before res_init is called,
+ res_init will not alter them. Of course, if an application is
+ setting them to _zero_ before calling res_init, hoping to
+ override what used to be the static default, we can't detect it
+ and unexpected results will follow. Zero for any of these fields
+ would make no sense, so one can safely assume that the
+ applications were already getting unexpected results.
+
+ _res.options is tricky since some apps were known to diddle the
+ bits before res_init was first called. We can't replicate that
+ semantic with dynamic initialization (they may have turned bits
+ off that are set in RES_DEFAULT). Our solution is to declare
+ such applications "broken". They could fool us by setting
+ RES_INIT but none do (yet). */
+ if (!_res.retrans)
+ _res.retrans = RES_TIMEOUT;
+ if (!_res.retry)
+ _res.retry = RES_DFLRETRY;
+ if (!(_res.options & RES_INIT))
+ _res.options = RES_DEFAULT;
+ else if (_res.nscount > 0)
+ __res_iclose (&_res, true); /* Close any VC sockets. */
+
+ /* This one used to initialize implicitly to zero, so unless the app
+ has set it to something in particular, we can randomize it *
+ now. */
+ if (!_res.id)
+ _res.id = res_randomid ();
+
+ atomicinclock (lock);
+ /* Request all threads to re-initialize their resolver states,
+ resolv.conf might have changed. */
+ atomicinc (__res_initstamp);
+ atomicincunlock (lock);
+
+ return __res_vinit (&_res, 1);
}
-/* Initialize resp if RES_INIT is not yet set or if res_init in some other
- thread requested re-initializing. */
+/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
+ res_init in some other thread requested re-initializing. */
int
__res_maybe_init (res_state resp, int preinit)
{
- if (resp->options & RES_INIT) {
- if (__res_initstamp != resp->_u._ext.initstamp) {
- if (resp->nscount > 0)
- __res_iclose (resp, true);
- return __res_vinit (resp, 1);
- }
- return 0;
- } else if (preinit) {
- if (!resp->retrans)
- resp->retrans = RES_TIMEOUT;
- if (!resp->retry)
- resp->retry = RES_DFLRETRY;
- resp->options = RES_DEFAULT;
- if (!resp->id)
- resp->id = res_randomid ();
- return __res_vinit (resp, 1);
- } else
- return __res_ninit (resp);
+ if (resp->options & RES_INIT)
+ {
+ if (__res_initstamp != resp->_u._ext.initstamp)
+ {
+ if (resp->nscount > 0)
+ __res_iclose (resp, true);
+ return __res_vinit (resp, 1);
+ }
+ return 0;
+ }
+ else if (preinit)
+ {
+ if (!resp->retrans)
+ resp->retrans = RES_TIMEOUT;
+ if (!resp->retry)
+ resp->retry = RES_DFLRETRY;
+ resp->options = RES_DEFAULT;
+ if (!resp->id)
+ resp->id = res_randomid ();
+ return __res_vinit (resp, 1);
+ }
+ else
+ return __res_ninit (resp);
}
libc_hidden_def (__res_maybe_init)

View File

@ -0,0 +1,81 @@
commit 7ab27b76d2d47942bc2ed74f674b62c3a51994bb
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:02 2017 +0200
resolv: Remove DEBUG macro from resolv/res_mkquery.c
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 8279d15de4271c84..2e3aa39cf088adf9 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -1,3 +1,21 @@
+/* Creation of DNS query packets.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
/*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
@@ -70,13 +88,9 @@
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv/resolv-internal.h>
-#include <stdio.h>
#include <string.h>
#include <sys/time.h>
-/* Options. Leave them on. */
-/* #define DEBUG */
-
#include <hp-timing.h>
#include <stdint.h>
#if HP_TIMING_AVAIL
@@ -107,11 +121,6 @@ res_nmkquery(res_state statp,
|| type < 0 || type > 65535)
return -1;
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_nmkquery(%s, %s, %s, %s)\n",
- _res_opcodes[op], dname, p_class(class), p_type(type));
-#endif
/*
* Initialize header fields.
*/
@@ -210,11 +219,6 @@ __res_nopt(res_state statp,
{
u_int16_t flags = 0;
-#ifdef DEBUG
- if ((statp->options & RES_DEBUG) != 0U)
- printf(";; res_nopt()\n");
-#endif
-
HEADER *hp = (HEADER *) buf;
u_char *cp = buf + n0;
u_char *ep = buf + buflen;
@@ -253,10 +257,6 @@ __res_nopt(res_state statp,
*cp++ = 0; /* EDNS version */
if (statp->options & RES_USE_DNSSEC) {
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_opt()... ENDS0 DNSSEC\n");
-#endif
flags |= NS_OPT_DNSSEC_OK;
}

View File

@ -0,0 +1,323 @@
commit 74084febc4b668ca2258d88cade6fa5e28364ac6
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:12 2017 +0200
resolv: Reformat resolv/res_mkquery.c to GNU style
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 2e3aa39cf088adf9..a601b6988545a149 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -97,172 +97,168 @@
# define RANDOM_BITS(Var) { uint64_t v64; HP_TIMING_NOW (v64); Var = v64; }
#endif
-/*
- * Form all types of queries.
- * Returns the size of the result or -1.
- */
+/* Form all types of queries. Returns the size of the result or -1 on
+ error.
+
+ STATP points to an initialized resolver state. OP is the opcode of
+ the query. DNAME is the domain. CLASS and TYPE are the DNS query
+ class and type. DATA can be NULL; otherwise, it is a pointer to a
+ domain name which is included in the generated packet (if op ==
+ NS_NOTIFY_OP). BUF must point to the out buffer of BUFLEN bytes.
+
+ DATALEN and NEWRR_IN are currently ignored. */
int
-res_nmkquery(res_state statp,
- int op, /* opcode of query */
- const char *dname, /* domain name */
- int class, int type, /* class and type of query */
- const u_char *data, /* resource record data */
- int datalen, /* length of data */
- const u_char *newrr_in, /* new rr for modify or append */
- u_char *buf, /* buffer to put query */
- int buflen) /* size of buffer */
+res_nmkquery (res_state statp, int op, const char *dname,
+ int class, int type,
+ const unsigned char *data, int datalen,
+ const unsigned char *newrr_in,
+ unsigned char *buf, int buflen)
{
- HEADER *hp;
- u_char *cp;
- int n;
- u_char *dnptrs[20], **dpp, **lastdnptr;
+ HEADER *hp;
+ unsigned char *cp;
+ int n;
+ unsigned char *dnptrs[20], **dpp, **lastdnptr;
- if (class < 0 || class > 65535
- || type < 0 || type > 65535)
- return -1;
+ if (class < 0 || class > 65535 || type < 0 || type > 65535)
+ return -1;
- /*
- * Initialize header fields.
- */
- if ((buf == NULL) || (buflen < HFIXEDSZ))
- return (-1);
- memset(buf, 0, HFIXEDSZ);
- hp = (HEADER *) buf;
- /* We randomize the IDs every time. The old code just
- incremented by one after the initial randomization which
- still predictable if the application does multiple
- requests. */
- int randombits;
- do
- {
+ /* Initialize header fields. */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return -1;
+ memset (buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ /* We randomize the IDs every time. The old code just incremented
+ by one after the initial randomization which still predictable if
+ the application does multiple requests. */
+ int randombits;
+ do
+ {
#ifdef RANDOM_BITS
- RANDOM_BITS (randombits);
+ RANDOM_BITS (randombits);
#else
- struct timeval tv;
- __gettimeofday (&tv, NULL);
- randombits = (tv.tv_sec << 8) ^ tv.tv_usec;
+ struct timeval tv;
+ __gettimeofday (&tv, NULL);
+ randombits = (tv.tv_sec << 8) ^ tv.tv_usec;
#endif
- }
- while ((randombits & 0xffff) == 0);
- statp->id = (statp->id + randombits) & 0xffff;
- hp->id = statp->id;
- hp->opcode = op;
- hp->rd = (statp->options & RES_RECURSE) != 0;
- hp->rcode = NOERROR;
- cp = buf + HFIXEDSZ;
- buflen -= HFIXEDSZ;
- dpp = dnptrs;
- *dpp++ = buf;
- *dpp++ = NULL;
- lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
- /*
- * perform opcode specific processing
- */
- switch (op) {
- case NS_NOTIFY_OP:
- if ((buflen -= QFIXEDSZ + (data == NULL ? 0 : RRFIXEDSZ)) < 0)
- return (-1);
- goto compose;
+ }
+ while ((randombits & 0xffff) == 0);
+
+ statp->id = (statp->id + randombits) & 0xffff;
+ hp->id = statp->id;
+ hp->opcode = op;
+ hp->rd = (statp->options & RES_RECURSE) != 0;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ buflen -= HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
- case QUERY:
- if ((buflen -= QFIXEDSZ) < 0)
- return (-1);
- compose:
- n = ns_name_compress(dname, cp, buflen,
- (const u_char **) dnptrs,
- (const u_char **) lastdnptr);
- if (n < 0)
- return (-1);
- cp += n;
- buflen -= n;
- NS_PUT16 (type, cp);
- NS_PUT16 (class, cp);
- hp->qdcount = htons(1);
- if (op == QUERY || data == NULL)
- break;
- /*
- * Make an additional record for completion domain.
- */
- n = ns_name_compress((char *)data, cp, buflen,
- (const u_char **) dnptrs,
- (const u_char **) lastdnptr);
- if (__glibc_unlikely (n < 0))
- return (-1);
- cp += n;
- buflen -= n;
- NS_PUT16 (T_NULL, cp);
- NS_PUT16 (class, cp);
- NS_PUT32 (0, cp);
- NS_PUT16 (0, cp);
- hp->arcount = htons(1);
- break;
+ /* Perform opcode specific processing. */
+ switch (op)
+ {
+ case NS_NOTIFY_OP:
+ if ((buflen -= QFIXEDSZ + (data == NULL ? 0 : RRFIXEDSZ)) < 0)
+ return -1;
+ goto compose;
- default:
- return (-1);
- }
- return (cp - buf);
+ case QUERY:
+ if ((buflen -= QFIXEDSZ) < 0)
+ return -1;
+ compose:
+ n = ns_name_compress (dname, cp, buflen,
+ (const unsigned char **) dnptrs,
+ (const unsigned char **) lastdnptr);
+ if (n < 0)
+ return -1;
+ cp += n;
+ buflen -= n;
+ NS_PUT16 (type, cp);
+ NS_PUT16 (class, cp);
+ hp->qdcount = htons (1);
+ if (op == QUERY || data == NULL)
+ break;
+
+ /* Make an additional record for completion domain. */
+ n = ns_name_compress ((char *)data, cp, buflen,
+ (const unsigned char **) dnptrs,
+ (const unsigned char **) lastdnptr);
+ if (__glibc_unlikely (n < 0))
+ return -1;
+ cp += n;
+ buflen -= n;
+ NS_PUT16 (T_NULL, cp);
+ NS_PUT16 (class, cp);
+ NS_PUT32 (0, cp);
+ NS_PUT16 (0, cp);
+ hp->arcount = htons (1);
+ break;
+
+ default:
+ return -1;
+ }
+ return cp - buf;
}
libresolv_hidden_def (res_nmkquery)
+/* Create an OPT resource record. Return the length of the final
+ packet, or -1 on error.
-/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
-#ifndef T_OPT
-#define T_OPT 41
-#endif
-
+ STATP must be an initialized resolver state. N0 is the current
+ number of bytes of the packet (already written to BUF by the
+ aller). BUF is the packet being constructed. The array it
+ pointers to must be BUFLEN bytes long. ANSLEN is the advertised
+ EDNS buffer size (to be included in the OPT resource record). */
int
-__res_nopt(res_state statp,
- int n0, /* current offset in buffer */
- u_char *buf, /* buffer to put query */
- int buflen, /* size of buffer */
- int anslen) /* UDP answer buffer size */
+__res_nopt (res_state statp, int n0, unsigned char *buf, int buflen,
+ int anslen)
{
- u_int16_t flags = 0;
-
- HEADER *hp = (HEADER *) buf;
- u_char *cp = buf + n0;
- u_char *ep = buf + buflen;
+ uint16_t flags = 0;
+ HEADER *hp = (HEADER *) buf;
+ unsigned char *cp = buf + n0;
+ unsigned char *ep = buf + buflen;
- if ((ep - cp) < 1 + RRFIXEDSZ)
- return -1;
+ if ((ep - cp) < 1 + RRFIXEDSZ)
+ return -1;
- *cp++ = 0; /* "." */
+ /* Add the root label. */
+ *cp++ = 0;
- NS_PUT16(T_OPT, cp); /* TYPE */
+ NS_PUT16 (T_OPT, cp); /* Record type. */
- /* Lowering the advertised buffer size based on the actual
- answer buffer size is desirable because the server will
- minimize the reply to fit into the UDP packet (and A
- non-minimal response might not fit the buffer).
+ /* Lowering the advertised buffer size based on the actual
+ answer buffer size is desirable because the server will
+ minimize the reply to fit into the UDP packet (and A
+ non-minimal response might not fit the buffer).
- The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
- fallback and a non-minimal response which has to be
- hard-truncated in the stub resolver, but this is price to
- pay for avoiding fragmentation. (This issue does not
- affect the nss_dns functions because they use the stub
- resolver in such a way that it allocates a properly sized
- response buffer.) */
- {
- uint16_t buffer_size;
- if (anslen < 512)
- buffer_size = 512;
- else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
- buffer_size = RESOLV_EDNS_BUFFER_SIZE;
- else
- buffer_size = anslen;
- NS_PUT16 (buffer_size, cp);
- }
+ The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
+ fallback and a non-minimal response which has to be
+ hard-truncated in the stub resolver, but this is price to
+ pay for avoiding fragmentation. (This issue does not
+ affect the nss_dns functions because they use the stub
+ resolver in such a way that it allocates a properly sized
+ response buffer.) */
+ {
+ uint16_t buffer_size;
+ if (anslen < 512)
+ buffer_size = 512;
+ else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
+ buffer_size = RESOLV_EDNS_BUFFER_SIZE;
+ else
+ buffer_size = anslen;
+ NS_PUT16 (buffer_size, cp);
+ }
- *cp++ = NOERROR; /* extended RCODE */
- *cp++ = 0; /* EDNS version */
+ *cp++ = NOERROR; /* Extended RCODE. */
+ *cp++ = 0; /* EDNS version. */
- if (statp->options & RES_USE_DNSSEC) {
- flags |= NS_OPT_DNSSEC_OK;
- }
+ if (statp->options & RES_USE_DNSSEC)
+ flags |= NS_OPT_DNSSEC_OK;
- NS_PUT16(flags, cp);
- NS_PUT16(0, cp); /* RDLEN */
- hp->arcount = htons(ntohs(hp->arcount) + 1);
+ NS_PUT16 (flags, cp);
+ NS_PUT16 (0, cp); /* RDATA length (no options are preent). */
+ hp->arcount = htons (ntohs (hp->arcount) + 1);
- return cp - buf;
+ return cp - buf;
}

View File

@ -0,0 +1,91 @@
commit 5ca4aaea1840b3005c2de4cc73269a55e34ae2c3
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:18 2017 +0200
resolv: Move the res_mkquery function to the resolv/mk_query.c file
diff --git a/resolv/res_data.c b/resolv/res_data.c
index 569ff4c0ea306e74..d907bfc9bd8a55fd 100644
--- a/resolv/res_data.c
+++ b/resolv/res_data.c
@@ -73,25 +73,6 @@ fp_nquery(const u_char *msg, int len, FILE *file) {
libresolv_hidden_def (fp_nquery)
int
-res_mkquery(int op, /* opcode of query */
- const char *dname, /* domain name */
- int class, int type, /* class and type of query */
- const u_char *data, /* resource record data */
- int datalen, /* length of data */
- const u_char *newrr_in, /* new rr for modify or append */
- u_char *buf, /* buffer to put query */
- int buflen) /* size of buffer */
-{
- if (__res_maybe_init (&_res, 1) == -1) {
- RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
- return (-1);
- }
- return (res_nmkquery(&_res, op, dname, class, type,
- data, datalen,
- newrr_in, buf, buflen));
-}
-
-int
res_query(const char *name, /* domain name */
int class, int type, /* class and type of query */
u_char *answer, /* buffer to put answer */
@@ -180,11 +161,9 @@ libresolv_hidden_def (hostalias)
#include <shlib-compat.h>
#if SHLIB_COMPAT(libresolv, GLIBC_2_0, GLIBC_2_2)
-# undef res_mkquery
# undef res_query
# undef res_querydomain
# undef res_search
-weak_alias (__res_mkquery, res_mkquery);
weak_alias (__res_query, res_query);
weak_alias (__res_querydomain, res_querydomain);
weak_alias (__res_search, res_search);
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index a601b6988545a149..9afb410980e47ca7 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -90,6 +90,7 @@
#include <resolv/resolv-internal.h>
#include <string.h>
#include <sys/time.h>
+#include <shlib-compat.h>
#include <hp-timing.h>
#include <stdint.h>
@@ -202,6 +203,21 @@ res_nmkquery (res_state statp, int op, const char *dname,
}
libresolv_hidden_def (res_nmkquery)
+int
+res_mkquery (int op, const char *dname, int class, int type,
+ const unsigned char *data, int datalen,
+ const unsigned char *newrr_in,
+ unsigned char *buf, int buflen)
+{
+ if (__res_maybe_init (&_res, 1) == -1)
+ {
+ RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+ return -1;
+ }
+ return res_nmkquery (&_res, op, dname, class, type,
+ data, datalen, newrr_in, buf, buflen);
+}
+
/* Create an OPT resource record. Return the length of the final
packet, or -1 on error.
@@ -262,3 +278,8 @@ __res_nopt (res_state statp, int n0, unsigned char *buf, int buflen,
return cp - buf;
}
+
+#if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
+# undef res_mkquery
+weak_alias (__res_mkquery, res_mkquery);
+#endif

View File

@ -0,0 +1,46 @@
commit b606c6ce66d4772068bfe3e410c28a247633ee24
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:32:19 2017 +0200
resolv: Remove source argument fron res_options
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 821f06061b4c3fb1..5d8b2c994d8e6f04 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -103,7 +103,7 @@
#include <inet/net-internal.h>
#include <errno.h>
-static void res_setoptions (res_state, const char *, const char *);
+static void res_setoptions (res_state, const char *);
static uint32_t net_mask (struct in_addr);
unsigned long long int __res_initstamp;
@@ -381,7 +381,7 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
}
if (MATCH (*buffer, "options"))
{
- res_setoptions (statp, *buffer + sizeof ("options") - 1, "conf");
+ res_setoptions (statp, *buffer + sizeof ("options") - 1);
continue;
}
}
@@ -417,7 +417,7 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
}
if ((cp = getenv ("RES_OPTIONS")) != NULL)
- res_setoptions (statp, cp, "env");
+ res_setoptions (statp, cp);
statp->options |= RES_INIT;
return true;
}
@@ -469,7 +469,7 @@ __res_vinit (res_state statp, int preinit)
}
static void
-res_setoptions (res_state statp, const char *options, const char *source)
+res_setoptions (res_state statp, const char *options)
{
const char *cp = options;

View File

@ -0,0 +1,95 @@
commit 3f8f1eb6b0ca45205cea3591f27727e21d598f62
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:32:12 2017 +0200
resolv: Remove DEBUG from resolv/res_query.c
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 5312c8e729c39516..760bf324e817c79e 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -80,9 +80,6 @@
#include <string.h>
#include <shlib-compat.h>
-/* Options. Leave them on. */
-/* #undef DEBUG */
-
#if PACKETSZ > 65536
#define MAXPACKET PACKETSZ
#else
@@ -133,11 +130,6 @@ __libc_res_nquery(res_state statp,
again:
hp->rcode = NOERROR; /* default */
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_query(%s, %d, %d)\n", name, class, type);
-#endif
-
if (type == T_QUERY_A_AND_AAAA)
{
n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
@@ -211,10 +203,6 @@ __libc_res_nquery(res_state statp,
}
}
if (__glibc_unlikely (n <= 0)) {
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_query: mkquery failed\n");
-#endif
RES_SET_H_ERRNO(statp, NO_RECOVERY);
if (use_malloc)
free (buf);
@@ -227,10 +215,6 @@ __libc_res_nquery(res_state statp,
if (use_malloc)
free (buf);
if (n < 0) {
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_query: send error\n");
-#endif
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (n);
}
@@ -260,15 +244,6 @@ __libc_res_nquery(res_state statp,
if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
&& (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
-#ifdef DEBUG
- if (statp->options & RES_DEBUG) {
- printf(";; rcode = %d, ancount=%d\n", hp->rcode,
- ntohs(hp->ancount));
- if (hp != hp2)
- printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode,
- ntohs(hp2->ancount));
- }
-#endif
switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
case NXDOMAIN:
if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
@@ -374,12 +349,6 @@ __libc_res_nsearch(res_state statp,
anslen, answerp, answerp2,
nanswerp2, resplen2, answerp2_malloced));
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
- (int)dots,(int)statp->ndots,(int)trailing_dot,name);
-#endif
-
/*
* If there are enough dots in the name, let's just give it a
* try 'as is'. The threshold can be set with the "ndots" option.
@@ -590,11 +559,6 @@ __libc_res_nquerydomain(res_state statp,
const char *longname = nbuf;
size_t n, d;
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
- name, domain?domain:"<Nil>", class, type);
-#endif
if (domain == NULL) {
n = strlen(name);

View File

@ -0,0 +1,197 @@
commit 037751179905c7d6d624f287029237565465fa9a
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:54 2017 +0200
resolv: Move res_query, res_search res_querydomain, hostalias
From res_data.c to query.c
diff --git a/resolv/res_data.c b/resolv/res_data.c
index b790b4b725bc9edd..5e7688c706bf8e99 100644
--- a/resolv/res_data.c
+++ b/resolv/res_data.c
@@ -15,35 +15,7 @@
* SOFTWARE.
*/
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-
-#include <ctype.h>
-#include <netdb.h>
#include <resolv.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int
-res_query(const char *name, /* domain name */
- int class, int type, /* class and type of query */
- u_char *answer, /* buffer to put answer */
- int anslen) /* size of answer buffer */
-{
- if (__res_maybe_init (&_res, 1) == -1) {
- RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
- return (-1);
- }
- return (res_nquery(&_res, name, class, type, answer, anslen));
-}
void
res_close(void) {
@@ -60,55 +32,3 @@ res_close(void) {
did it and it would be done implicitly on shutdown. */
__res_iclose(&_res, false);
}
-
-int
-res_search(const char *name, /* domain name */
- int class, int type, /* class and type of query */
- u_char *answer, /* buffer to put answer */
- int anslen) /* size of answer */
-{
- if (__res_maybe_init (&_res, 1) == -1) {
- RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
- return (-1);
- }
-
- return (res_nsearch(&_res, name, class, type, answer, anslen));
-}
-
-int
-res_querydomain(const char *name,
- const char *domain,
- int class, int type, /* class and type of query */
- u_char *answer, /* buffer to put answer */
- int anslen) /* size of answer */
-{
- if (__res_maybe_init (&_res, 1) == -1) {
- RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
- return (-1);
- }
-
- return (res_nquerydomain(&_res, name, domain,
- class, type,
- answer, anslen));
-}
-
-const char *
-hostalias(const char *name) {
- static char abuf[MAXDNAME];
-
- return (res_hostalias(&_res, name, abuf, sizeof abuf));
-}
-libresolv_hidden_def (hostalias)
-
-
-
-#include <shlib-compat.h>
-
-#if SHLIB_COMPAT(libresolv, GLIBC_2_0, GLIBC_2_2)
-# undef res_query
-# undef res_querydomain
-# undef res_search
-weak_alias (__res_query, res_query);
-weak_alias (__res_querydomain, res_querydomain);
-weak_alias (__res_search, res_search);
-#endif
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 0ca3a650282ec7f0..5312c8e729c39516 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -78,7 +78,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <resolv/resolv-internal.h>
+#include <shlib-compat.h>
/* Options. Leave them on. */
/* #undef DEBUG */
@@ -319,6 +319,18 @@ res_nquery(res_state statp,
}
libresolv_hidden_def (res_nquery)
+int
+res_query (const char *name, int class, int type,
+ unsigned char *answer, int anslen)
+{
+ if (__res_maybe_init (&_res, 1) == -1)
+ {
+ RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+ return -1;
+ }
+ return res_nquery (&_res, name, class, type, answer, anslen);
+}
+
/*
* Formulate a normal query, send, and retrieve answer in supplied buffer.
* Return the size of the response on success, -1 on error.
@@ -545,6 +557,19 @@ res_nsearch(res_state statp,
}
libresolv_hidden_def (res_nsearch)
+int
+res_search (const char *name, int class, int type,
+ unsigned char *answer, int anslen)
+{
+ if (__res_maybe_init (&_res, 1) == -1)
+ {
+ RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+ return -1;
+ }
+
+ return res_nsearch (&_res, name, class, type, answer, anslen);
+}
+
/*
* Perform a call on res_query on the concatenation of name and domain.
*/
@@ -610,6 +635,19 @@ res_nquerydomain(res_state statp,
}
libresolv_hidden_def (res_nquerydomain)
+int
+res_querydomain (const char *name, const char *domain, int class, int type,
+ unsigned char *answer, int anslen)
+{
+ if (__res_maybe_init (&_res, 1) == -1)
+ {
+ RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+ return -1;
+ }
+
+ return res_nquerydomain (&_res, name, domain, class, type, answer, anslen);
+}
+
const char *
res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
char *file, *cp1, *cp2;
@@ -647,3 +685,20 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
return (NULL);
}
libresolv_hidden_def (res_hostalias)
+
+const char *
+hostalias (const char *name)
+{
+ static char abuf[MAXDNAME];
+ return res_hostalias (&_res, name, abuf, sizeof abuf);
+}
+libresolv_hidden_def (hostalias)
+
+#if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
+# undef res_query
+# undef res_querydomain
+# undef res_search
+weak_alias (__res_query, res_query);
+weak_alias (__res_querydomain, res_querydomain);
+weak_alias (__res_search, res_search);
+#endif

View File

@ -0,0 +1,135 @@
commit 26bf5a1029434c98db85947eed11ce3090b2f5db
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 13:17:03 2017 +0200
resolv: Move res_randomid to its own file
diff --git a/resolv/Makefile b/resolv/Makefile
index 0ebb2af795c6fb7b..c2a8a3a631f6bb2e 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -28,7 +28,7 @@ headers := resolv.h \
sys/bitypes.h
routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
- res_hconf res_libc res-state
+ res_hconf res_libc res-state res_randomid
tests = tst-aton tst-leaks tst-inet_ntop
xtests = tst-leaks2
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 57223b470af9ba4d..ef2e7c0db465dba6 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -479,13 +479,6 @@ net_mask (struct in_addr in)
return (htonl(IN_CLASSC_NET));
}
-u_int
-res_randomid(void) {
- return 0xffff & __getpid();
-}
-libc_hidden_def (__res_randomid)
-
-
/*
* This routine is for closing the socket if a virtual circuit is used and
* the program wants to close it. This provides support for endhostent()
diff --git a/resolv/res_randomid.c b/resolv/res_randomid.c
new file mode 100644
index 0000000000000000..e0dbe4c8ff259527
--- /dev/null
+++ b/resolv/res_randomid.c
@@ -0,0 +1,92 @@
+/* Legacy libresolv random number generator.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <resolv.h>
+#include <unistd.h>
+
+unsigned int
+res_randomid (void) {
+ return 0xffff & __getpid ();
+}
+libc_hidden_def (__res_randomid)

View File

@ -0,0 +1,468 @@
commit 5b757a51b514ea163bbec0a53dbbc06bb1b29241
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 10:43:33 2017 +0200
resolv: Make RES_ROTATE start with a random name server [BZ #19570]
Do not copy the actual name server addresses to rotate them. Use a
global rotation offset instead.
diff --git a/resolv/Makefile b/resolv/Makefile
index 88766729087d54cf..79843d0d7ca92ffd 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -69,6 +69,9 @@ tests += tst-inet_pton
# This test sends millions of packets and is rather slow.
xtests += tst-resolv-qtypes
+
+# This test has dropped packet tests and runs for a long time.
+xtests += tst-resolv-rotate
endif
extra-libs-others = $(extra-libs)
libresolv-routines := res_comp res_debug \
@@ -148,6 +151,7 @@ $(objpfx)tst-resolv-res_init: $(libdl) $(objpfx)libresolv.so
$(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-canonname: \
$(libdl) $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 1835ec7ee507d215..1dbe30088167636c 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -109,6 +109,8 @@
#include <unistd.h>
#include <kernel-features.h>
#include <libc-internal.h>
+#include <libc-diag.h>
+#include <hp-timing.h>
#if PACKETSZ > 65536
#define MAXPACKET PACKETSZ
@@ -188,7 +190,7 @@ evNowTime(struct timespec *res) {
/* Forward. */
-static struct sockaddr *get_nsaddr (res_state, int);
+static struct sockaddr *get_nsaddr (res_state, unsigned int);
static int send_vc(res_state, const u_char *, int,
const u_char *, int,
u_char **, int *, int *, int, u_char **,
@@ -291,6 +293,62 @@ res_nameinquery(const char *name, int type, int class,
}
libresolv_hidden_def (res_nameinquery)
+/* Returns a shift value for the name server index. Used to implement
+ RES_ROTATE. */
+static unsigned int
+nameserver_offset (struct __res_state *statp)
+{
+ /* If we only have one name server or rotation is disabled, return
+ offset 0 (no rotation). */
+ unsigned int nscount = statp->nscount;
+ if (nscount <= 1 || !(statp->options & RES_ROTATE))
+ return 0;
+
+ /* Global offset. The lowest bit indicates whether the offset has
+ been initialized with a random value. Use relaxed MO to access
+ global_offset because all we need is a sequence of roughly
+ sequential value. */
+ static unsigned int global_offset;
+ unsigned int offset = atomic_fetch_add_relaxed (&global_offset, 2);
+ if ((offset & 1) == 0)
+ {
+ /* Initialization is required. */
+#if HP_TIMING_AVAIL
+ uint64_t ticks;
+ HP_TIMING_NOW (ticks);
+ offset = ticks;
+#else
+ struct timeval tv;
+ __gettimeofday (&tv, NULL);
+ offset = ((tv.tv_sec << 8) ^ tv.tv_usec);
+#endif
+ /* The lowest bit is the most random. Preserve it. */
+ offset <<= 1;
+
+ /* Store the new starting value. atomic_fetch_add_relaxed
+ returns the old value, so emulate that by storing the new
+ (incremented) value. Concurrent initialization with
+ different random values is harmless. */
+ atomic_store_relaxed (&global_offset, (offset | 1) + 2);
+ }
+
+ /* Remove the initialization bit. */
+ offset >>= 1;
+
+ /* Avoid the division in the most common cases. */
+ switch (nscount)
+ {
+ case 2:
+ return offset & 1;
+ case 3:
+ return offset % 3;
+ case 4:
+ return offset & 3;
+ default:
+ return offset % nscount;
+ }
+}
+
/* int
* res_queriesmatch(buf1, eom1, buf2, eom2)
* is there a 1:1 mapping of (name,type,class)
@@ -352,7 +410,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
int *nansp2, int *resplen2, int *ansp2_malloced)
{
- int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+ int gotsomewhere, terrno, try, v_circuit, resplen, n;
if (statp->nscount == 0) {
__set_errno (ESRCH);
@@ -382,7 +440,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
if (EXT(statp).nscount != statp->nscount)
needclose++;
else
- for (ns = 0; ns < statp->nscount; ns++) {
+ for (unsigned int ns = 0; ns < statp->nscount; ns++) {
if (statp->nsaddr_list[ns].sin_family != 0
&& !sock_eq((struct sockaddr_in6 *)
&statp->nsaddr_list[ns],
@@ -402,7 +460,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
* Maybe initialize our private copy of the ns_addr_list.
*/
if (EXT(statp).nscount == 0) {
- for (ns = 0; ns < statp->nscount; ns++) {
+ for (unsigned int ns = 0; ns < statp->nscount; ns++) {
EXT(statp).nssocks[ns] = -1;
if (statp->nsaddr_list[ns].sin_family == 0)
continue;
@@ -420,35 +478,21 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
EXT(statp).nscount = statp->nscount;
}
- /*
- * Some resolvers want to even out the load on their nameservers.
- * Note that RES_BLAST overrides RES_ROTATE.
- */
- if (__glibc_unlikely ((statp->options & RES_ROTATE) != 0)) {
- struct sockaddr_in ina;
- struct sockaddr_in6 *inp;
- int lastns = statp->nscount - 1;
- int fd;
-
- inp = EXT(statp).nsaddrs[0];
- ina = statp->nsaddr_list[0];
- fd = EXT(statp).nssocks[0];
- for (ns = 0; ns < lastns; ns++) {
- EXT(statp).nsaddrs[ns] = EXT(statp).nsaddrs[ns + 1];
- statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
- EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
- }
- EXT(statp).nsaddrs[lastns] = inp;
- statp->nsaddr_list[lastns] = ina;
- EXT(statp).nssocks[lastns] = fd;
- }
+ /* Name server index offset. Used to implement
+ RES_ROTATE. */
+ unsigned int ns_offset = nameserver_offset (statp);
/*
* Send request, RETRY times, or until successful.
*/
for (try = 0; try < statp->retry; try++) {
- for (ns = 0; ns < statp->nscount; ns++)
+ for (unsigned ns_shift = 0; ns_shift < statp->nscount; ns_shift++)
{
+ /* The actual name server index. This implements
+ RES_ROTATE. */
+ unsigned int ns = ns_shift + ns_offset;
+ if (ns >= statp->nscount)
+ ns -= statp->nscount;
#ifdef DEBUG
char tmpbuf[40];
struct sockaddr *nsap = get_nsaddr (statp, ns);
@@ -544,8 +588,9 @@ libresolv_hidden_def (res_nsend)
/* Private */
static struct sockaddr *
-get_nsaddr (res_state statp, int n)
+get_nsaddr (res_state statp, unsigned int n)
{
+ assert (n < statp->nscount);
if (statp->nsaddr_list[n].sin_family == 0 && EXT(statp).nsaddrs[n] != NULL)
/* EXT(statp).nsaddrs[n] holds an address that is larger than
diff --git a/resolv/tst-resolv-rotate.c b/resolv/tst-resolv-rotate.c
new file mode 100644
index 0000000000000000..d01b85b2fe82930b
--- /dev/null
+++ b/resolv/tst-resolv-rotate.c
@@ -0,0 +1,263 @@
+/* Check that RES_ROTATE works with few nameserver entries (bug 13028).
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/test-driver.h>
+
+static volatile int drop_server = -1;
+static volatile unsigned int query_counts[resolv_max_test_servers];
+
+static const char address_ipv4[4] = {192, 0, 2, 1};
+static const char address_ipv6[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ if (ctx->server_index == drop_server)
+ {
+ resolv_response_drop (b);
+ resolv_response_close (b);
+ return;
+ }
+
+ bool force_tcp = strncmp (qname, "2.", 2) == 0;
+ struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp};
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+ if (flags.tc)
+ return;
+
+ TEST_VERIFY_EXIT (ctx->server_index < resolv_max_test_servers);
+ ++query_counts[ctx->server_index];
+
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, qtype, 0);
+ switch (qtype)
+ {
+ case T_A:
+ {
+ char addr[sizeof (address_ipv4)];
+ memcpy (addr, address_ipv4, sizeof (address_ipv4));
+ addr[3] = 1 + ctx->tcp;
+ resolv_response_add_data (b, addr, sizeof (addr));
+ }
+ break;
+ case T_AAAA:
+ {
+ char addr[sizeof (address_ipv6)];
+ memcpy (addr, address_ipv6, sizeof (address_ipv6));
+ addr[15] = 1 + ctx->tcp;
+ resolv_response_add_data (b, addr, sizeof (addr));
+ }
+ break;
+ case T_PTR:
+ if (force_tcp)
+ resolv_response_add_name (b, "2.host.example");
+ else
+ resolv_response_add_name (b, "host.example");
+ break;
+ default:
+ FAIL_EXIT1 ("unexpected QTYPE: %s/%u/%u", qname, qclass, qtype);
+ }
+ resolv_response_close_record (b);
+}
+
+static void
+check_forward_1 (const char *name, int family)
+{
+ unsigned char lsb;
+ if (strncmp (name, "2.", 2) == 0)
+ lsb = 2;
+ else
+ lsb = 1;
+
+ char expected_hostent_v4[200];
+ snprintf (expected_hostent_v4, sizeof (expected_hostent_v4),
+ "name: %s\naddress: 192.0.2.%d\n", name, lsb);
+ char expected_hostent_v6[200];
+ snprintf (expected_hostent_v6, sizeof (expected_hostent_v6),
+ "name: %s\naddress: 2001:db8::%d\n", name, lsb);
+ char expected_ai[200];
+
+ unsigned char address[16];
+ size_t address_length;
+
+ char *expected_hostent;
+ switch (family)
+ {
+ case AF_INET:
+ expected_hostent = expected_hostent_v4;
+ snprintf (expected_ai, sizeof (expected_ai),
+ "address: STREAM/TCP 192.0.2.%d 80\n", lsb);
+ TEST_VERIFY_EXIT (sizeof (address_ipv4) == sizeof (struct in_addr));
+ memcpy (address, address_ipv4, sizeof (address_ipv4));
+ address_length = sizeof (address_ipv4);
+ break;
+ case AF_INET6:
+ expected_hostent = expected_hostent_v6;
+ snprintf (expected_ai, sizeof (expected_ai),
+ "address: STREAM/TCP 2001:db8::%d 80\n", lsb);
+ TEST_VERIFY_EXIT (sizeof (address_ipv6) == sizeof (struct in6_addr));
+ memcpy (address, address_ipv6, sizeof (address_ipv6));
+ address_length = sizeof (address_ipv6);
+ break;
+ case AF_UNSPEC:
+ expected_hostent = NULL;
+ snprintf (expected_ai, sizeof (expected_ai),
+ "address: STREAM/TCP 192.0.2.%d 80\n"
+ "address: STREAM/TCP 2001:db8::%d 80\n",
+ lsb, lsb);
+ address_length = 0;
+ break;
+ default:
+ FAIL_EXIT1 ("unknown address family %d", family);
+ }
+
+
+ if (family == AF_INET)
+ {
+ struct hostent *e = gethostbyname (name);
+ check_hostent (name, e, expected_hostent_v4);
+ }
+
+ if (family != AF_UNSPEC)
+ {
+ struct hostent *e = gethostbyname2 (name, family);
+ check_hostent (name, e, expected_hostent);
+ }
+
+ if (address_length > 0)
+ {
+ address[address_length - 1] = lsb;
+ struct hostent *e = gethostbyaddr (address, address_length, family);
+ check_hostent (name, e, expected_hostent);
+ }
+
+ struct addrinfo hints =
+ {
+ .ai_family = family,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ };
+ struct addrinfo *ai;
+ int ret = getaddrinfo (name, "80", &hints, &ai);
+ check_addrinfo (name, ai, ret, expected_ai);
+ if (ret == 0)
+ {
+ for (struct addrinfo *p = ai; p != NULL; p = p->ai_next)
+ {
+ char host[200];
+ ret = getnameinfo (p->ai_addr, p->ai_addrlen,
+ host, sizeof (host),
+ NULL, 0, /* service */
+ 0);
+ if (ret != 0)
+ {
+ support_record_failure ();
+ printf ("error: getnameinfo: %d\n", ret);
+ }
+ else
+ {
+ if (lsb == 1)
+ TEST_VERIFY (strcmp (host, "host.example") == 0);
+ else
+ TEST_VERIFY (strcmp (host, "2.host.example") == 0);
+ }
+ }
+ freeaddrinfo (ai);
+ }
+}
+
+static void
+check_forward (int family)
+{
+ check_forward_1 ("host.example", family);
+ check_forward_1 ("2.host.example", family);
+}
+
+static int
+do_test (void)
+{
+ for (int force_tcp = 0; force_tcp < 2; ++force_tcp)
+ for (int nscount = 1; nscount <= 3; ++nscount)
+ for (int disable_server = -1; disable_server < nscount; ++disable_server)
+ for (drop_server = -1; drop_server < nscount; ++drop_server)
+ {
+ /* A disabled server will never receive queries and
+ therefore cannot drop them. */
+ if (drop_server >= 0 && drop_server == disable_server)
+ continue;
+ /* No servers remaining to query, all queries are expected
+ to fail. */
+ int broken_servers = (disable_server >= 0) + (drop_server >= 0);
+ if (nscount <= broken_servers)
+ continue;
+
+ if (test_verbose > 0)
+ printf ("info: tcp=%d nscount=%d disable=%d drop=%d\n",
+ force_tcp, nscount, disable_server, drop_server);
+ struct resolv_redirect_config config =
+ {
+ .response_callback = response,
+ .nscount = nscount
+ };
+ if (disable_server >= 0)
+ {
+ config.servers[disable_server].disable_udp = true;
+ config.servers[disable_server].disable_tcp = true;
+ }
+
+ struct resolv_test *aux = resolv_test_start (config);
+ _res.options |= RES_ROTATE;
+
+ /* Run a few queries to make sure that all of them
+ succeed. We always perform more than nscount queries,
+ so we cover all active servers due to RES_ROTATE. */
+ for (size_t i = 0; i < resolv_max_test_servers; ++i)
+ query_counts[i] = 0;
+ check_forward (AF_INET);
+ check_forward (AF_INET6);
+ check_forward (AF_UNSPEC);
+
+ for (int i = 0; i < nscount; ++i)
+ {
+ if (i != disable_server && i != drop_server
+ && query_counts[i] == 0)
+ {
+ support_record_failure ();
+ printf ("error: nscount=%d, but no query to server %d\n",
+ nscount, i);
+ }
+ }
+
+ resolv_test_end (aux);
+ }
+ return 0;
+}
+
+#define TIMEOUT 300
+#include <support/test-driver.c>

View File

@ -0,0 +1,366 @@
commit 09fbb56ad69b9e02fb3710a9234566536a96facf
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 11:31:23 2017 +0200
resolv: Remove DEBUG from resolv/res_send.c
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 1dbe30088167636c..18308709542da6e6 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -103,7 +103,6 @@
#include <netdb.h>
#include <resolv/resolv-internal.h>
#include <signal.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -182,10 +181,6 @@ evNowTime(struct timespec *res) {
}
-/* Options. Leave them on. */
-/* #undef DEBUG */
-#include "res_debug.h"
-
#define EXT(res) ((res)->_u._ext)
/* Forward. */
@@ -200,11 +195,6 @@ static int send_dg(res_state, const u_char *, int,
u_char **, int *, int *, int,
int *, int *, u_char **,
u_char **, int *, int *, int *);
-#ifdef DEBUG
-static void Aerror(const res_state, FILE *, const char *, int,
- const struct sockaddr *);
-static void Perror(const res_state, FILE *, const char *, int);
-#endif
static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
/* Public. */
@@ -422,8 +412,6 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
return (-1);
}
- DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
- (stdout, ";; res_send()\n"), buf, buflen);
v_circuit = ((statp->options & RES_USEVC)
|| buflen > PACKETSZ
|| buflen2 > PACKETSZ);
@@ -493,20 +481,8 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
unsigned int ns = ns_shift + ns_offset;
if (ns >= statp->nscount)
ns -= statp->nscount;
-#ifdef DEBUG
- char tmpbuf[40];
- struct sockaddr *nsap = get_nsaddr (statp, ns);
-#endif
same_ns:
- Dprint(statp->options & RES_DEBUG,
- (stdout, ";; Querying server (# %d) address = %s\n",
- ns + 1, inet_ntop(nsap->sa_family,
- (nsap->sa_family == AF_INET6
- ? (void *) &((struct sockaddr_in6 *) nsap)->sin6_addr
- : (void *) &((struct sockaddr_in *) nsap)->sin_addr),
- tmpbuf, sizeof (tmpbuf))));
-
if (__glibc_unlikely (v_circuit)) {
/* Use VC; at most one attempt per server. */
try = statp->retry;
@@ -536,22 +512,6 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
resplen = n;
- Dprint((statp->options & RES_DEBUG) ||
- ((statp->pfcode & RES_PRF_REPLY) &&
- (statp->pfcode & RES_PRF_HEAD1)),
- (stdout, ";; got answer:\n"));
-
- DprintQ((statp->options & RES_DEBUG) ||
- (statp->pfcode & RES_PRF_REPLY),
- (stdout, "%s", ""),
- ans, (resplen > anssiz) ? anssiz : resplen);
- if (buf2 != NULL) {
- DprintQ((statp->options & RES_DEBUG) ||
- (statp->pfcode & RES_PRF_REPLY),
- (stdout, "%s", ""),
- *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
- }
-
/*
* If we have temporarily opened a virtual circuit,
* or if we haven't been asked to keep a socket open,
@@ -741,7 +701,6 @@ send_vc(res_state statp,
(nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (statp->_vcsock < 0) {
*terrno = errno;
- Perror(statp, stderr, "socket(vc)", errno);
if (resplen2 != NULL)
*resplen2 = 0;
return (-1);
@@ -752,7 +711,6 @@ send_vc(res_state statp,
? sizeof (struct sockaddr_in)
: sizeof (struct sockaddr_in6)) < 0) {
*terrno = errno;
- Aerror(statp, stderr, "connect/vc", errno, nsap);
return close_and_return_error (statp, resplen2);
}
statp->_flags |= RES_F_VC;
@@ -775,7 +733,6 @@ send_vc(res_state statp,
}
if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
*terrno = errno;
- Perror(statp, stderr, "write failed", errno);
return close_and_return_error (statp, resplen2);
}
/*
@@ -797,7 +754,6 @@ send_vc(res_state statp,
}
if (n <= 0) {
*terrno = errno;
- Perror(statp, stderr, "read failed", errno);
/*
* A long running process might get its TCP
* connection reset if the remote server was
@@ -860,9 +816,6 @@ send_vc(res_state statp,
read RLEN bytes instead. */
len = rlen;
} else {
- Dprint(statp->options & RES_DEBUG,
- (stdout, ";; response truncated\n")
- );
truncating = 1;
len = *thisanssizp;
}
@@ -873,8 +826,6 @@ send_vc(res_state statp,
/*
* Undersized message.
*/
- Dprint(statp->options & RES_DEBUG,
- (stdout, ";; undersized: %d\n", len));
*terrno = EMSGSIZE;
return close_and_return_error (statp, resplen2);
}
@@ -886,7 +837,6 @@ send_vc(res_state statp,
}
if (__glibc_unlikely (n <= 0)) {
*terrno = errno;
- Perror(statp, stderr, "read(vc)", errno);
return close_and_return_error (statp, resplen2);
}
if (__glibc_unlikely (truncating)) {
@@ -914,14 +864,8 @@ send_vc(res_state statp,
* wait for the correct one.
*/
if ((recvresp1 || hp->id != anhp->id)
- && (recvresp2 || hp2->id != anhp->id)) {
- DprintQ((statp->options & RES_DEBUG) ||
- (statp->pfcode & RES_PRF_REPLY),
- (stdout, ";; old answer (unexpected):\n"),
- *thisansp,
- (rlen > *thisanssizp) ? *thisanssizp: rlen);
+ && (recvresp2 || hp2->id != anhp->id))
goto read_len;
- }
/* Mark which reply we received. */
if (recvresp1 == 0 && hp->id == anhp->id)
@@ -962,7 +906,6 @@ reopen (res_state statp, int *terrno, int ns)
}
if (EXT(statp).nssocks[ns] < 0) {
*terrno = errno;
- Perror(statp, stderr, "socket(dg)", errno);
return (-1);
}
@@ -987,7 +930,6 @@ reopen (res_state statp, int *terrno, int ns)
DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) {
DIAG_POP_NEEDS_COMMENT;
- Aerror(statp, stderr, "connect(dg)", errno, nsap);
__res_iclose(statp, false);
return (0);
}
@@ -1112,7 +1054,6 @@ send_dg(res_state statp,
evNowTime(&now);
if (evCmpTime(finish, now) <= 0) {
poll_err_out:
- Perror(statp, stderr, "poll", errno);
return close_and_return_error (statp, resplen2);
}
evSubTime(&timeout, &finish, &now);
@@ -1129,7 +1070,6 @@ send_dg(res_state statp,
need_recompute = 1;
}
if (n == 0) {
- Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
{
/* There are quite a few broken name servers out
@@ -1229,7 +1169,6 @@ send_dg(res_state statp,
#endif
fail_sendmmsg:
- Perror(statp, stderr, "sendmmsg", errno);
return close_and_return_error (statp, resplen2);
}
}
@@ -1247,7 +1186,6 @@ send_dg(res_state statp,
if (sr != (nwritten != 0 ? buflen2 : buflen)) {
if (errno == EINTR || errno == EAGAIN)
goto recompute_resend;
- Perror(statp, stderr, "send", errno);
return close_and_return_error (statp, resplen2);
}
just_one:
@@ -1308,12 +1246,6 @@ send_dg(res_state statp,
MSG_TRUNC which is only available on Linux. We
can abstract out the Linux-specific feature in the
future to detect truncation. */
- if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
- Dprint(statp->options & RES_DEBUG,
- (stdout, ";; response may be truncated (UDP)\n")
- );
- }
-
HEADER *anhp = (HEADER *) *thisansp;
socklen_t fromlen = sizeof(struct sockaddr_in6);
assert (sizeof(from) <= fromlen);
@@ -1325,7 +1257,6 @@ send_dg(res_state statp,
need_recompute = 1;
goto wait;
}
- Perror(statp, stderr, "recvfrom", errno);
return close_and_return_error (statp, resplen2);
}
*gotsomewhere = 1;
@@ -1333,9 +1264,6 @@ send_dg(res_state statp,
/*
* Undersized message.
*/
- Dprint(statp->options & RES_DEBUG,
- (stdout, ";; undersized: %d\n",
- *thisresplenp));
*terrno = EMSGSIZE;
return close_and_return_error (statp, resplen2);
}
@@ -1346,12 +1274,6 @@ send_dg(res_state statp,
* XXX - potential security hazard could
* be detected here.
*/
- DprintQ((statp->options & RES_DEBUG) ||
- (statp->pfcode & RES_PRF_REPLY),
- (stdout, ";; old answer:\n"),
- *thisansp,
- (*thisresplenp > *thisanssizp)
- ? *thisanssizp : *thisresplenp);
goto wait;
}
if (!(statp->options & RES_INSECURE1) &&
@@ -1361,12 +1283,6 @@ send_dg(res_state statp,
* XXX - potential security hazard could
* be detected here.
*/
- DprintQ((statp->options & RES_DEBUG) ||
- (statp->pfcode & RES_PRF_REPLY),
- (stdout, ";; not our server:\n"),
- *thisansp,
- (*thisresplenp > *thisanssizp)
- ? *thisanssizp : *thisresplenp);
goto wait;
}
if (!(statp->options & RES_INSECURE2)
@@ -1383,23 +1299,11 @@ send_dg(res_state statp,
* XXX - potential security hazard could
* be detected here.
*/
- DprintQ((statp->options & RES_DEBUG) ||
- (statp->pfcode & RES_PRF_REPLY),
- (stdout, ";; wrong query name:\n"),
- *thisansp,
- (*thisresplenp > *thisanssizp)
- ? *thisanssizp : *thisresplenp);
goto wait;
}
if (anhp->rcode == SERVFAIL ||
anhp->rcode == NOTIMP ||
anhp->rcode == REFUSED) {
- DprintQ(statp->options & RES_DEBUG,
- (stdout, "server rejected query:\n"),
- *thisansp,
- (*thisresplenp > *thisanssizp)
- ? *thisanssizp : *thisresplenp);
-
next_ns:
if (recvresp1 || (buf2 != NULL && recvresp2)) {
*resplen2 = 0;
@@ -1425,11 +1329,6 @@ send_dg(res_state statp,
}
if (anhp->rcode == NOERROR && anhp->ancount == 0
&& anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
- DprintQ(statp->options & RES_DEBUG,
- (stdout, "referred query:\n"),
- *thisansp,
- (*thisresplenp > *thisanssizp)
- ? *thisanssizp : *thisresplenp);
goto next_ns;
}
if (!(statp->options & RES_IGNTC) && anhp->tc) {
@@ -1437,8 +1336,6 @@ send_dg(res_state statp,
* To get the rest of answer,
* use TCP with same server.
*/
- Dprint(statp->options & RES_DEBUG,
- (stdout, ";; truncated answer\n"));
*v_circuit = 1;
__res_iclose(statp, false);
// XXX if we have received one reply we could
@@ -1482,46 +1379,6 @@ send_dg(res_state statp,
}
}
-#ifdef DEBUG
-static void
-Aerror(const res_state statp, FILE *file, const char *string, int error,
- const struct sockaddr *address)
-{
- int save = errno;
-
- if ((statp->options & RES_DEBUG) != 0) {
- char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
-
- fprintf(file, "res_send: %s ([%s].%u): %s\n",
- string,
- (address->sa_family == AF_INET
- ? inet_ntop(address->sa_family,
- &((const struct sockaddr_in *) address)->sin_addr,
- tmp, sizeof tmp)
- : inet_ntop(address->sa_family,
- &((const struct sockaddr_in6 *) address)->sin6_addr,
- tmp, sizeof tmp)),
- (address->sa_family == AF_INET
- ? ntohs(((struct sockaddr_in *) address)->sin_port)
- : address->sa_family == AF_INET6
- ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
- : 0),
- strerror(error));
- }
- __set_errno (save);
-}
-
-static void
-Perror(const res_state statp, FILE *file, const char *string, int error) {
- int save = errno;
-
- if ((statp->options & RES_DEBUG) != 0)
- fprintf(file, "res_send: %s: %s\n",
- string, strerror(error));
- __set_errno (save);
-}
-#endif
-
static int
sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
if (a1->sin6_family == a2->sin6_family) {

View File

@ -0,0 +1,59 @@
commit e68111fbd63e84b66bd9e03b42721c79230b9b6d
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 13:18:45 2017 +0200
resolv: Remove DEBUG preprocessor conditionals from res_setoptions
diff --git a/resolv/res_init.c b/resolv/res_init.c
index eb380d3d56bc018c..eb24fca3a6ecef9a 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -83,9 +83,6 @@
#include <sys/types.h>
#include <inet/net-internal.h>
-/* Options. Should all be left alone. */
-/* #undef DEBUG */
-
static void res_setoptions (res_state, const char *, const char *)
internal_function;
@@ -383,11 +380,6 @@ res_setoptions(res_state statp, const char *options, const char *source) {
const char *cp = options;
int i;
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; res_setoptions(\"%s\", \"%s\")...\n",
- options, source);
-#endif
while (*cp) {
/* skip leading and inner runs of spaces */
while (*cp == ' ' || *cp == '\t')
@@ -399,10 +391,6 @@ res_setoptions(res_state statp, const char *options, const char *source) {
statp->ndots = i;
else
statp->ndots = RES_MAXNDOTS;
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";;\tndots=%d\n", statp->ndots);
-#endif
} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
i = atoi(cp + sizeof("timeout:") - 1);
if (i <= RES_MAXRETRANS)
@@ -415,15 +403,6 @@ res_setoptions(res_state statp, const char *options, const char *source) {
statp->retry = i;
else
statp->retry = RES_MAXRETRY;
- } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
-#ifdef DEBUG
- if (!(statp->options & RES_DEBUG)) {
- printf(";; res_setoptions(\"%s\", \"%s\")..\n",
- options, source);
- statp->options |= RES_DEBUG;
- }
- printf(";;\tdebug\n");
-#endif
} else {
static const struct
{

View File

@ -0,0 +1,211 @@
commit ea4924ce5bccfccc4e8a492faa96933131abd9ef
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 14:05:49 2017 +0200
resolv: Report allocation errors in __res_vinit
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index f121aa3de73704ea..206924de8603b4dd 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -164,7 +164,11 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
enum nss_status status;
if (__res_maybe_init (&_res, 0) == -1)
- return NSS_STATUS_UNAVAIL;
+ {
+ *errnop = errno;
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
switch (af) {
case AF_INET:
@@ -289,7 +293,11 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
int *herrnop, int32_t *ttlp)
{
if (__res_maybe_init (&_res, 0) == -1)
- return NSS_STATUS_UNAVAIL;
+ {
+ *errnop = errno;
+ *herrnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
/*
* if there aren't any dots, it could be a user-level alias.
@@ -416,7 +424,11 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
host_data = (struct host_data *) buffer;
if (__res_maybe_init (&_res, 0) == -1)
- return NSS_STATUS_UNAVAIL;
+ {
+ *errnop = errno;
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
if (af == AF_INET6 && len == IN6ADDRSZ
&& (memcmp (uaddr, mapped, sizeof mapped) == 0
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index 2be72d33a30f917e..dc1599b47122fea2 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -116,7 +116,11 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
enum nss_status status;
if (__res_maybe_init (&_res, 0) == -1)
- return NSS_STATUS_UNAVAIL;
+ {
+ *errnop = errno;
+ *herrnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
@@ -166,7 +170,11 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
return NSS_STATUS_UNAVAIL;
if (__res_maybe_init (&_res, 0) == -1)
- return NSS_STATUS_UNAVAIL;
+ {
+ *errnop = errno;
+ *herrnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
net2 = (u_int32_t) net;
for (cnt = 4; net2 != 0; net2 >>= 8)
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 49fc94595bfe147f..e604a0212fa13624 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -100,6 +100,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <inet/net-internal.h>
+#include <errno.h>
static void res_setoptions (res_state, const char *, const char *);
static uint32_t net_mask (struct in_addr);
@@ -121,14 +122,11 @@ is_sort_mask (char ch)
return ch == '/' || ch == '&';
}
-/* Set up default settings. If the /etc/resolv.conf configuration
- file exist, the values there will have precedence. Otherwise, the
- server address is set to INADDR_LOOPBACK and the default domain
- name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN
- environment variables can be used to override some settings.
- Return 0 if completes successfully, -1 on error. */
-int
-__res_vinit (res_state statp, int preinit)
+/* Internal helper function for __res_vinit, to aid with resource
+ deallocation and error handling. Return true on success, false on
+ failure. */
+static bool
+res_vinit_1 (res_state statp, bool preinit, FILE *fp)
{
char *cp, **pp;
char buf[BUFSIZ];
@@ -203,7 +201,6 @@ __res_vinit (res_state statp, int preinit)
&& (line[sizeof (name) - 1] == ' ' \
|| line[sizeof (name) - 1] == '\t'))
- FILE *fp = fopen (_PATH_RESCONF, "rce");
if (fp != NULL)
{
/* No threads use this stream. */
@@ -302,26 +299,26 @@ __res_vinit (res_state statp, int preinit)
struct sockaddr_in6 *sa6;
sa6 = malloc (sizeof (*sa6));
- if (sa6 != NULL)
- {
- sa6->sin6_family = AF_INET6;
- sa6->sin6_port = htons (NAMESERVER_PORT);
- sa6->sin6_flowinfo = 0;
- sa6->sin6_addr = a6;
-
- sa6->sin6_scope_id = 0;
- if (__glibc_likely (el != NULL))
- /* Ignore errors, for backwards
- compatibility. */
- __inet6_scopeid_pton
- (&a6, el + 1, &sa6->sin6_scope_id);
-
- statp->nsaddr_list[nserv].sin_family = 0;
- statp->_u._ext.nsaddrs[nserv] = sa6;
- statp->_u._ext.nssocks[nserv] = -1;
- have_serv6 = true;
- nserv++;
- }
+ if (sa6 == NULL)
+ return -1;
+
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_port = htons (NAMESERVER_PORT);
+ sa6->sin6_flowinfo = 0;
+ sa6->sin6_addr = a6;
+
+ sa6->sin6_scope_id = 0;
+ if (__glibc_likely (el != NULL))
+ /* Ignore errors, for backwards
+ compatibility. */
+ __inet6_scopeid_pton
+ (&a6, el + 1, &sa6->sin6_scope_id);
+
+ statp->nsaddr_list[nserv].sin_family = 0;
+ statp->_u._ext.nsaddrs[nserv] = sa6;
+ statp->_u._ext.nssocks[nserv] = -1;
+ have_serv6 = true;
+ nserv++;
}
}
continue;
@@ -410,6 +407,44 @@ __res_vinit (res_state statp, int preinit)
return 0;
}
+/* Set up default settings. If the /etc/resolv.conf configuration
+ file exist, the values there will have precedence. Otherwise, the
+ server address is set to INADDR_LOOPBACK and the default domain
+ name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN
+ environment variables can be used to override some settings.
+ Return 0 if completes successfully, -1 on error. */
+int
+__res_vinit (res_state statp, int preinit)
+{
+ FILE *fp = fopen (_PATH_RESCONF, "rce");
+ if (fp == NULL)
+ switch (errno)
+ {
+ case EACCES:
+ case EISDIR:
+ case ELOOP:
+ case ENOENT:
+ case ENOTDIR:
+ case EPERM:
+ /* Ignore these errors. They are persistent errors caused
+ by file system contents. */
+ break;
+ default:
+ /* Other errors refer to resource allocation problems and
+ need to be handled by the application. */
+ return -1;
+ }
+ if (!res_vinit_1 (statp, preinit, fp))
+ {
+ /* Deallocate the name server addresses which have been
+ allocated. */
+ for (int n = 0; n < MAXNS; n++)
+ free (statp->_u._ext.nsaddrs[n]);
+ return -1;
+ }
+ return 0;
+}
+
static void
res_setoptions (res_state statp, const char *options, const char *source)
{

View File

@ -0,0 +1,759 @@
commit 4c4480eecb2e00764dd3bf79d68ea4e1d747d78c
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 13:20:46 2017 +0200
resolv: Reformat res_vinit and related functions to GNU style
Also remove some obsolete comments.
diff --git a/resolv/res_init.c b/resolv/res_init.c
index eb8e308fdaa899ef..49fc94595bfe147f 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -1,3 +1,21 @@
+/* Resolver state initialization and resolv.conf parsing.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
/*
* Copyright (c) 1985, 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -83,26 +101,15 @@
#include <sys/types.h>
#include <inet/net-internal.h>
-static void res_setoptions (res_state, const char *, const char *)
- internal_function;
-static u_int32_t net_mask (struct in_addr) __THROW;
+static void res_setoptions (res_state, const char *, const char *);
+static uint32_t net_mask (struct in_addr);
unsigned long long int __res_initstamp attribute_hidden;
-/*
- * Resolver state default settings.
- */
-
-/*
- * Set up default settings. If the configuration file exist, the values
- * there will have precedence. Otherwise, the server address is set to
- * INADDR_LOOPBACK and the default domain name comes from gethostname.
- *
- * Return 0 if completes successfully, -1 on error
- */
int
-res_ninit(res_state statp) {
- return (__res_vinit(statp, 0));
+res_ninit (res_state statp)
+{
+ return __res_vinit (statp, 0);
}
libc_hidden_def (__res_ninit)
@@ -114,349 +121,374 @@ is_sort_mask (char ch)
return ch == '/' || ch == '&';
}
-/* This function has to be reachable by res_data.c but not publically. */
+/* Set up default settings. If the /etc/resolv.conf configuration
+ file exist, the values there will have precedence. Otherwise, the
+ server address is set to INADDR_LOOPBACK and the default domain
+ name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN
+ environment variables can be used to override some settings.
+ Return 0 if completes successfully, -1 on error. */
int
-__res_vinit(res_state statp, int preinit) {
- FILE *fp;
- char *cp, **pp;
- int n;
- char buf[BUFSIZ];
- int nserv = 0; /* number of nameservers read from file */
- int have_serv6 = 0;
- int haveenv = 0;
- int havesearch = 0;
- int nsort = 0;
- char *net;
- statp->_u._ext.initstamp = __res_initstamp;
+__res_vinit (res_state statp, int preinit)
+{
+ char *cp, **pp;
+ char buf[BUFSIZ];
+ int nserv = 0; /* Number of nameservers read from file. */
+ bool have_serv6 = false;
+ bool haveenv = false;
+ bool havesearch = false;
+ int nsort = 0;
+ char *net;
+ statp->_u._ext.initstamp = __res_initstamp;
- if (!preinit) {
- statp->retrans = RES_TIMEOUT;
- statp->retry = RES_DFLRETRY;
- statp->options = RES_DEFAULT;
- statp->id = res_randomid();
- }
+ if (!preinit)
+ {
+ statp->retrans = RES_TIMEOUT;
+ statp->retry = RES_DFLRETRY;
+ statp->options = RES_DEFAULT;
+ statp->id = res_randomid ();
+ }
- statp->nscount = 0;
- statp->defdname[0] = '\0';
- statp->ndots = 1;
- statp->pfcode = 0;
- statp->_vcsock = -1;
- statp->_flags = 0;
- statp->__glibc_unused_qhook = NULL;
- statp->__glibc_unused_rhook = NULL;
- statp->_u._ext.nscount = 0;
- for (n = 0; n < MAXNS; n++)
- statp->_u._ext.nsaddrs[n] = NULL;
+ statp->nscount = 0;
+ statp->defdname[0] = '\0';
+ statp->ndots = 1;
+ statp->pfcode = 0;
+ statp->_vcsock = -1;
+ statp->_flags = 0;
+ statp->__glibc_unused_qhook = NULL;
+ statp->__glibc_unused_rhook = NULL;
+ statp->_u._ext.nscount = 0;
+ for (int n = 0; n < MAXNS; n++)
+ statp->_u._ext.nsaddrs[n] = NULL;
- /* Allow user to override the local domain definition */
- if ((cp = getenv("LOCALDOMAIN")) != NULL) {
- (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
- statp->defdname[sizeof(statp->defdname) - 1] = '\0';
- haveenv++;
+ /* Allow user to override the local domain definition. */
+ if ((cp = getenv ("LOCALDOMAIN")) != NULL)
+ {
+ strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
+ statp->defdname[sizeof (statp->defdname) - 1] = '\0';
+ haveenv = true;
- /*
- * Set search list to be blank-separated strings
- * from rest of env value. Permits users of LOCALDOMAIN
- * to still have a search list, and anyone to set the
- * one that they want to use as an individual (even more
- * important now that the rfc1535 stuff restricts searches)
- */
- cp = statp->defdname;
- pp = statp->dnsrch;
- *pp++ = cp;
- for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
- if (*cp == '\n') /* silly backwards compat */
- break;
- else if (*cp == ' ' || *cp == '\t') {
- *cp = 0;
- n = 1;
- } else if (n) {
- *pp++ = cp;
- n = 0;
- havesearch = 1;
- }
- }
- /* null terminate last domain if there are excess */
- while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
- cp++;
- *cp = '\0';
- *pp++ = 0;
- }
+ /* Set search list to be blank-separated strings from rest of
+ env value. Permits users of LOCALDOMAIN to still have a
+ search list, and anyone to set the one that they want to use
+ as an individual (even more important now that the rfc1535
+ stuff restricts searches). */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (int n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+ {
+ if (*cp == '\n')
+ break;
+ else if (*cp == ' ' || *cp == '\t')
+ {
+ *cp = 0;
+ n = 1;
+ }
+ else if (n > 0)
+ {
+ *pp++ = cp;
+ n = 0;
+ havesearch = true;
+ }
+ }
+ /* Null terminate last domain if there are excess. */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ }
-#define MATCH(line, name) \
- (!strncmp(line, name, sizeof(name) - 1) && \
- (line[sizeof(name) - 1] == ' ' || \
- line[sizeof(name) - 1] == '\t'))
+#define MATCH(line, name) \
+ (!strncmp (line, name, sizeof (name) - 1) \
+ && (line[sizeof (name) - 1] == ' ' \
+ || line[sizeof (name) - 1] == '\t'))
- if ((fp = fopen(_PATH_RESCONF, "rce")) != NULL) {
- /* No threads use this stream. */
- __fsetlocking (fp, FSETLOCKING_BYCALLER);
- /* read the config file */
- while (__fgets_unlocked(buf, sizeof(buf), fp) != NULL) {
- /* skip comments */
- if (*buf == ';' || *buf == '#')
- continue;
- /* read default domain name */
- if (MATCH(buf, "domain")) {
- if (haveenv) /* skip if have from environ */
- continue;
- cp = buf + sizeof("domain") - 1;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
- statp->defdname[sizeof(statp->defdname) - 1] = '\0';
- if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
- *cp = '\0';
- havesearch = 0;
- continue;
- }
- /* set search list */
- if (MATCH(buf, "search")) {
- if (haveenv) /* skip if have from environ */
- continue;
- cp = buf + sizeof("search") - 1;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
- statp->defdname[sizeof(statp->defdname) - 1] = '\0';
- if ((cp = strchr(statp->defdname, '\n')) != NULL)
- *cp = '\0';
- /*
- * Set search list to be blank-separated strings
- * on rest of line.
- */
- cp = statp->defdname;
- pp = statp->dnsrch;
- *pp++ = cp;
- for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
- if (*cp == ' ' || *cp == '\t') {
- *cp = 0;
- n = 1;
- } else if (n) {
- *pp++ = cp;
- n = 0;
- }
- }
- /* null terminate last domain if there are excess */
- while (*cp != '\0' && *cp != ' ' && *cp != '\t')
- cp++;
- *cp = '\0';
- *pp++ = 0;
- havesearch = 1;
- continue;
- }
- /* read nameservers to query */
- if (MATCH(buf, "nameserver") && nserv < MAXNS) {
- struct in_addr a;
+ FILE *fp = fopen (_PATH_RESCONF, "rce");
+ if (fp != NULL)
+ {
+ /* No threads use this stream. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+ /* Read the config file. */
+ while (__fgets_unlocked (buf, sizeof (buf), fp) != NULL)
+ {
+ /* Skip comments. */
+ if (*buf == ';' || *buf == '#')
+ continue;
+ /* Read default domain name. */
+ if (MATCH (buf, "domain"))
+ {
+ if (haveenv)
+ /* LOCALDOMAIN overrides the configuration file. */
+ continue;
+ cp = buf + sizeof ("domain") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
+ statp->defdname[sizeof (statp->defdname) - 1] = '\0';
+ if ((cp = strpbrk (statp->defdname, " \t\n")) != NULL)
+ *cp = '\0';
+ havesearch = false;
+ continue;
+ }
+ /* Set search list. */
+ if (MATCH (buf, "search"))
+ {
+ if (haveenv)
+ /* LOCALDOMAIN overrides the configuration file. */
+ continue;
+ cp = buf + sizeof ("search") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
+ statp->defdname[sizeof (statp->defdname) - 1] = '\0';
+ if ((cp = strchr (statp->defdname, '\n')) != NULL)
+ *cp = '\0';
+ /* Set search list to be blank-separated strings on rest
+ of line. */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (int n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+ {
+ if (*cp == ' ' || *cp == '\t')
+ {
+ *cp = 0;
+ n = 1;
+ }
+ else if (n)
+ {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ /* Null terminate last domain if there are excess. */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ havesearch = true;
+ continue;
+ }
+ /* Read nameservers to query. */
+ if (MATCH (buf, "nameserver") && nserv < MAXNS)
+ {
+ struct in_addr a;
- cp = buf + sizeof("nameserver") - 1;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- if ((*cp != '\0') && (*cp != '\n')
- && __inet_aton(cp, &a)) {
- statp->nsaddr_list[nserv].sin_addr = a;
- statp->nsaddr_list[nserv].sin_family = AF_INET;
- statp->nsaddr_list[nserv].sin_port =
- htons(NAMESERVER_PORT);
- nserv++;
- } else {
- struct in6_addr a6;
- char *el;
+ cp = buf + sizeof ("nameserver") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
+ {
+ statp->nsaddr_list[nserv].sin_addr = a;
+ statp->nsaddr_list[nserv].sin_family = AF_INET;
+ statp->nsaddr_list[nserv].sin_port = htons (NAMESERVER_PORT);
+ nserv++;
+ }
+ else
+ {
+ struct in6_addr a6;
+ char *el;
- if ((el = strpbrk(cp, " \t\n")) != NULL)
- *el = '\0';
- if ((el = strchr(cp, SCOPE_DELIMITER)) != NULL)
- *el = '\0';
- if ((*cp != '\0') &&
- (__inet_pton(AF_INET6, cp, &a6) > 0)) {
- struct sockaddr_in6 *sa6;
+ if ((el = strpbrk (cp, " \t\n")) != NULL)
+ *el = '\0';
+ if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL)
+ *el = '\0';
+ if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0))
+ {
+ struct sockaddr_in6 *sa6;
- sa6 = malloc(sizeof(*sa6));
- if (sa6 != NULL) {
- sa6->sin6_family = AF_INET6;
- sa6->sin6_port = htons(NAMESERVER_PORT);
- sa6->sin6_flowinfo = 0;
- sa6->sin6_addr = a6;
+ sa6 = malloc (sizeof (*sa6));
+ if (sa6 != NULL)
+ {
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_port = htons (NAMESERVER_PORT);
+ sa6->sin6_flowinfo = 0;
+ sa6->sin6_addr = a6;
- sa6->sin6_scope_id = 0;
- if (__glibc_likely (el != NULL)) {
- /* Ignore errors, for backwards
- compatibility. */
- (void) __inet6_scopeid_pton
- (&a6, el + 1, &sa6->sin6_scope_id);
- }
+ sa6->sin6_scope_id = 0;
+ if (__glibc_likely (el != NULL))
+ /* Ignore errors, for backwards
+ compatibility. */
+ __inet6_scopeid_pton
+ (&a6, el + 1, &sa6->sin6_scope_id);
- statp->nsaddr_list[nserv].sin_family = 0;
- statp->_u._ext.nsaddrs[nserv] = sa6;
- statp->_u._ext.nssocks[nserv] = -1;
- have_serv6 = 1;
- nserv++;
- }
- }
- }
- continue;
- }
- if (MATCH(buf, "sortlist")) {
- struct in_addr a;
+ statp->nsaddr_list[nserv].sin_family = 0;
+ statp->_u._ext.nsaddrs[nserv] = sa6;
+ statp->_u._ext.nssocks[nserv] = -1;
+ have_serv6 = true;
+ nserv++;
+ }
+ }
+ }
+ continue;
+ }
+ if (MATCH (buf, "sortlist"))
+ {
+ struct in_addr a;
- cp = buf + sizeof("sortlist") - 1;
- while (nsort < MAXRESOLVSORT) {
- while (*cp == ' ' || *cp == '\t')
- cp++;
- if (*cp == '\0' || *cp == '\n' || *cp == ';')
- break;
- net = cp;
- while (*cp && !is_sort_mask (*cp) && *cp != ';' &&
- isascii(*cp) && !isspace(*cp))
- cp++;
- n = *cp;
- *cp = 0;
- if (__inet_aton(net, &a)) {
- statp->sort_list[nsort].addr = a;
- if (is_sort_mask (n)) {
- *cp++ = n;
- net = cp;
- while (*cp && *cp != ';' &&
- isascii(*cp) && !isspace(*cp))
- cp++;
- n = *cp;
- *cp = 0;
- if (__inet_aton(net, &a)) {
- statp->sort_list[nsort].mask = a.s_addr;
- } else {
- statp->sort_list[nsort].mask =
- net_mask(statp->sort_list[nsort].addr);
- }
- } else {
- statp->sort_list[nsort].mask =
- net_mask(statp->sort_list[nsort].addr);
- }
- nsort++;
- }
- *cp = n;
- }
- continue;
- }
- if (MATCH(buf, "options")) {
- res_setoptions(statp, buf + sizeof("options") - 1, "conf");
- continue;
- }
- }
- statp->nscount = nserv;
- if (have_serv6) {
- /* We try IPv6 servers again. */
- statp->ipv6_unavail = false;
- }
- statp->nsort = nsort;
- (void) fclose(fp);
- }
- if (__glibc_unlikely (statp->nscount == 0)) {
- statp->nsaddr.sin_addr = __inet_makeaddr(IN_LOOPBACKNET, 1);
- statp->nsaddr.sin_family = AF_INET;
- statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
- statp->nscount = 1;
- }
- if (statp->defdname[0] == 0 &&
- __gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
- (cp = strchr(buf, '.')) != NULL)
- strcpy(statp->defdname, cp + 1);
+ cp = buf + sizeof ("sortlist") - 1;
+ while (nsort < MAXRESOLVSORT)
+ {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0' || *cp == '\n' || *cp == ';')
+ break;
+ net = cp;
+ while (*cp && !is_sort_mask (*cp) && *cp != ';'
+ && isascii (*cp) && !isspace (*cp))
+ cp++;
+ char separator = *cp;
+ *cp = 0;
+ if (__inet_aton (net, &a))
+ {
+ statp->sort_list[nsort].addr = a;
+ if (is_sort_mask (separator))
+ {
+ *cp++ = separator;
+ net = cp;
+ while (*cp && *cp != ';'
+ && isascii (*cp) && !isspace (*cp))
+ cp++;
+ separator = *cp;
+ *cp = 0;
+ if (__inet_aton (net, &a))
+ statp->sort_list[nsort].mask = a.s_addr;
+ else
+ statp->sort_list[nsort].mask
+ = net_mask (statp->sort_list[nsort].addr);
+ }
+ else
+ statp->sort_list[nsort].mask
+ = net_mask (statp->sort_list[nsort].addr);
+ nsort++;
+ }
+ *cp = separator;
+ }
+ continue;
+ }
+ if (MATCH (buf, "options"))
+ {
+ res_setoptions (statp, buf + sizeof ("options") - 1, "conf");
+ continue;
+ }
+ }
+ statp->nscount = nserv;
+ if (have_serv6)
+ /* We try IPv6 servers again. */
+ statp->ipv6_unavail = false;
+ statp->nsort = nsort;
+ fclose (fp);
+ }
+ if (__glibc_unlikely (statp->nscount == 0))
+ {
+ statp->nsaddr.sin_addr = __inet_makeaddr (IN_LOOPBACKNET, 1);
+ statp->nsaddr.sin_family = AF_INET;
+ statp->nsaddr.sin_port = htons (NAMESERVER_PORT);
+ statp->nscount = 1;
+ }
+ if (statp->defdname[0] == 0
+ && __gethostname (buf, sizeof (statp->defdname) - 1) == 0
+ && (cp = strchr (buf, '.')) != NULL)
+ strcpy (statp->defdname, cp + 1);
- /* find components of local domain that might be searched */
- if (havesearch == 0) {
- pp = statp->dnsrch;
- *pp++ = statp->defdname;
- *pp = NULL;
+ /* Find components of local domain that might be searched. */
+ if (!havesearch)
+ {
+ pp = statp->dnsrch;
+ *pp++ = statp->defdname;
+ *pp = NULL;
- }
+ }
- if ((cp = getenv("RES_OPTIONS")) != NULL)
- res_setoptions(statp, cp, "env");
- statp->options |= RES_INIT;
- return (0);
+ if ((cp = getenv ("RES_OPTIONS")) != NULL)
+ res_setoptions (statp, cp, "env");
+ statp->options |= RES_INIT;
+ return 0;
}
static void
-internal_function
-res_setoptions(res_state statp, const char *options, const char *source) {
- const char *cp = options;
- int i;
+res_setoptions (res_state statp, const char *options, const char *source)
+{
+ const char *cp = options;
- while (*cp) {
- /* skip leading and inner runs of spaces */
- while (*cp == ' ' || *cp == '\t')
- cp++;
- /* search for and process individual options */
- if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
- i = atoi(cp + sizeof("ndots:") - 1);
- if (i <= RES_MAXNDOTS)
- statp->ndots = i;
- else
- statp->ndots = RES_MAXNDOTS;
- } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
- i = atoi(cp + sizeof("timeout:") - 1);
- if (i <= RES_MAXRETRANS)
- statp->retrans = i;
- else
- statp->retrans = RES_MAXRETRANS;
- } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
- i = atoi(cp + sizeof("attempts:") - 1);
- if (i <= RES_MAXRETRY)
- statp->retry = i;
- else
- statp->retry = RES_MAXRETRY;
- } else {
- static const struct
- {
- char str[22];
- uint8_t len;
- uint8_t clear;
- unsigned long int flag;
- } options[] = {
+ while (*cp)
+ {
+ /* Skip leading and inner runs of spaces. */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ /* Search for and process individual options. */
+ if (!strncmp (cp, "ndots:", sizeof ("ndots:") - 1))
+ {
+ int i = atoi (cp + sizeof ("ndots:") - 1);
+ if (i <= RES_MAXNDOTS)
+ statp->ndots = i;
+ else
+ statp->ndots = RES_MAXNDOTS;
+ }
+ else if (!strncmp (cp, "timeout:", sizeof ("timeout:") - 1))
+ {
+ int i = atoi (cp + sizeof ("timeout:") - 1);
+ if (i <= RES_MAXRETRANS)
+ statp->retrans = i;
+ else
+ statp->retrans = RES_MAXRETRANS;
+ }
+ else if (!strncmp (cp, "attempts:", sizeof ("attempts:") - 1))
+ {
+ int i = atoi (cp + sizeof ("attempts:") - 1);
+ if (i <= RES_MAXRETRY)
+ statp->retry = i;
+ else
+ statp->retry = RES_MAXRETRY;
+ }
+ else
+ {
+ static const struct
+ {
+ char str[22];
+ uint8_t len;
+ uint8_t clear;
+ unsigned long int flag;
+ } options[] = {
#define STRnLEN(str) str, sizeof (str) - 1
- { STRnLEN ("inet6"), 0, DEPRECATED_RES_USE_INET6 },
- { STRnLEN ("rotate"), 0, RES_ROTATE },
- { STRnLEN ("edns0"), 0, RES_USE_EDNS0 },
- { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP },
- { STRnLEN ("single-request"), 0, RES_SNGLKUP },
- { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
- { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
- { STRnLEN ("use-vc"), 0, RES_USEVC }
- };
+ { STRnLEN ("inet6"), 0, DEPRECATED_RES_USE_INET6 },
+ { STRnLEN ("rotate"), 0, RES_ROTATE },
+ { STRnLEN ("edns0"), 0, RES_USE_EDNS0 },
+ { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP },
+ { STRnLEN ("single-request"), 0, RES_SNGLKUP },
+ { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
+ { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
+ { STRnLEN ("use-vc"), 0, RES_USEVC }
+ };
#define noptions (sizeof (options) / sizeof (options[0]))
- int i;
- for (i = 0; i < noptions; ++i)
- if (strncmp (cp, options[i].str, options[i].len) == 0)
- {
- if (options[i].clear)
- statp->options &= options[i].flag;
- else
- statp->options |= options[i].flag;
- break;
- }
- if (i == noptions) {
- /* XXX - print a warning here? */
- }
- }
- /* skip to next run of spaces */
- while (*cp && *cp != ' ' && *cp != '\t')
- cp++;
- }
+ for (int i = 0; i < noptions; ++i)
+ if (strncmp (cp, options[i].str, options[i].len) == 0)
+ {
+ if (options[i].clear)
+ statp->options &= options[i].flag;
+ else
+ statp->options |= options[i].flag;
+ break;
+ }
+ }
+ /* Skip to next run of spaces. */
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ }
}
-/* XXX - should really support CIDR which means explicit masks always. */
-/* XXX - should really use system's version of this */
-static u_int32_t
+static uint32_t
net_mask (struct in_addr in)
{
- u_int32_t i = ntohl(in.s_addr);
+ uint32_t i = ntohl (in.s_addr);
- if (IN_CLASSA(i))
- return (htonl(IN_CLASSA_NET));
- else if (IN_CLASSB(i))
- return (htonl(IN_CLASSB_NET));
- return (htonl(IN_CLASSC_NET));
+ if (IN_CLASSA (i))
+ return htonl (IN_CLASSA_NET);
+ else if (IN_CLASSB (i))
+ return htonl (IN_CLASSB_NET);
+ return htonl (IN_CLASSC_NET);
}

View File

@ -0,0 +1,47 @@
commit ca3d65ff69d5187cb4d6b7f81d414427c7007e22
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 19 13:15:11 2017 +0200
resolv: Make __res_vinit hidden
And remove unnecessary separate declarations.
diff --git a/include/resolv.h b/include/resolv.h
index e8f477cd86b7be11..37e4047ac40c6ae1 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -23,7 +23,7 @@ extern __thread struct __res_state *__resp attribute_tls_model_ie;
# define _res (*__resp)
/* Now define the internal interfaces. */
-extern int __res_vinit (res_state, int);
+extern int __res_vinit (res_state, int) attribute_hidden;
extern int __res_maybe_init (res_state, int);
extern void _sethtent (int);
extern struct hostent *_gethtent (void);
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 23676e994dd58be7..57223b470af9ba4d 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -110,8 +110,6 @@ unsigned long long int __res_initstamp attribute_hidden;
*/
int
res_ninit(res_state statp) {
- extern int __res_vinit(res_state, int);
-
return (__res_vinit(statp, 0));
}
libc_hidden_def (__res_ninit)
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index c52574f895d4f19d..3ef885762e890a40 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -41,8 +41,6 @@ __libc_lock_define_initialized (static, lock);
int
res_init(void) {
- extern int __res_vinit(res_state, int);
-
/*
* These three fields used to be statically initialized. This made
* it hard to use this code in a shared library. It is necessary,

View File

@ -0,0 +1,174 @@
commit 89f187a40fc0ad4e22838526bfe34d73f758b776
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 16 20:54:43 2017 +0200
resolv: Use getline for configuration file reading in res_vinit_1
diff --git a/resolv/res_init.c b/resolv/res_init.c
index e604a0212fa13624..ed5a4d4804a792de 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -126,10 +126,10 @@ is_sort_mask (char ch)
deallocation and error handling. Return true on success, false on
failure. */
static bool
-res_vinit_1 (res_state statp, bool preinit, FILE *fp)
+res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
{
char *cp, **pp;
- char buf[BUFSIZ];
+ size_t buffer_size = 0;
int nserv = 0; /* Number of nameservers read from file. */
bool have_serv6 = false;
bool haveenv = false;
@@ -197,27 +197,38 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
}
#define MATCH(line, name) \
- (!strncmp (line, name, sizeof (name) - 1) \
- && (line[sizeof (name) - 1] == ' ' \
- || line[sizeof (name) - 1] == '\t'))
+ (!strncmp ((line), name, sizeof (name) - 1) \
+ && ((line)[sizeof (name) - 1] == ' ' \
+ || (line)[sizeof (name) - 1] == '\t'))
if (fp != NULL)
{
/* No threads use this stream. */
__fsetlocking (fp, FSETLOCKING_BYCALLER);
/* Read the config file. */
- while (__fgets_unlocked (buf, sizeof (buf), fp) != NULL)
+ while (true)
{
+ {
+ ssize_t ret = __getline (buffer, &buffer_size, fp);
+ if (ret <= 0)
+ {
+ if (_IO_ferror_unlocked (fp))
+ return false;
+ else
+ break;
+ }
+ }
+
/* Skip comments. */
- if (*buf == ';' || *buf == '#')
+ if (**buffer == ';' || **buffer == '#')
continue;
/* Read default domain name. */
- if (MATCH (buf, "domain"))
+ if (MATCH (*buffer, "domain"))
{
if (haveenv)
/* LOCALDOMAIN overrides the configuration file. */
continue;
- cp = buf + sizeof ("domain") - 1;
+ cp = *buffer + sizeof ("domain") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
@@ -230,12 +241,12 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
continue;
}
/* Set search list. */
- if (MATCH (buf, "search"))
+ if (MATCH (*buffer, "search"))
{
if (haveenv)
/* LOCALDOMAIN overrides the configuration file. */
continue;
- cp = buf + sizeof ("search") - 1;
+ cp = *buffer + sizeof ("search") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
@@ -271,11 +282,11 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
continue;
}
/* Read nameservers to query. */
- if (MATCH (buf, "nameserver") && nserv < MAXNS)
+ if (MATCH (*buffer, "nameserver") && nserv < MAXNS)
{
struct in_addr a;
- cp = buf + sizeof ("nameserver") - 1;
+ cp = *buffer + sizeof ("nameserver") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
@@ -300,7 +311,7 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
sa6 = malloc (sizeof (*sa6));
if (sa6 == NULL)
- return -1;
+ return false;
sa6->sin6_family = AF_INET6;
sa6->sin6_port = htons (NAMESERVER_PORT);
@@ -323,11 +334,11 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
}
continue;
}
- if (MATCH (buf, "sortlist"))
+ if (MATCH (*buffer, "sortlist"))
{
struct in_addr a;
- cp = buf + sizeof ("sortlist") - 1;
+ cp = *buffer + sizeof ("sortlist") - 1;
while (nsort < MAXRESOLVSORT)
{
while (*cp == ' ' || *cp == '\t')
@@ -367,9 +378,9 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
}
continue;
}
- if (MATCH (buf, "options"))
+ if (MATCH (*buffer, "options"))
{
- res_setoptions (statp, buf + sizeof ("options") - 1, "conf");
+ res_setoptions (statp, *buffer + sizeof ("options") - 1, "conf");
continue;
}
}
@@ -387,10 +398,13 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
statp->nsaddr.sin_port = htons (NAMESERVER_PORT);
statp->nscount = 1;
}
- if (statp->defdname[0] == 0
- && __gethostname (buf, sizeof (statp->defdname) - 1) == 0
- && (cp = strchr (buf, '.')) != NULL)
- strcpy (statp->defdname, cp + 1);
+ if (statp->defdname[0] == 0)
+ {
+ char buf[sizeof (statp->defdname)];
+ if (__gethostname (buf, sizeof (statp->defdname) - 1) == 0
+ && (cp = strchr (buf, '.')) != NULL)
+ strcpy (statp->defdname, cp + 1);
+ }
/* Find components of local domain that might be searched. */
if (!havesearch)
@@ -404,7 +418,7 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp)
if ((cp = getenv ("RES_OPTIONS")) != NULL)
res_setoptions (statp, cp, "env");
statp->options |= RES_INIT;
- return 0;
+ return true;
}
/* Set up default settings. If the /etc/resolv.conf configuration
@@ -434,7 +448,12 @@ __res_vinit (res_state statp, int preinit)
need to be handled by the application. */
return -1;
}
- if (!res_vinit_1 (statp, preinit, fp))
+
+ char *buffer = NULL;
+ bool ok = res_vinit_1 (statp, preinit, fp, &buffer);
+ free (buffer);
+
+ if (!ok)
{
/* Deallocate the name server addresses which have been
allocated. */

View File

@ -0,0 +1,602 @@
commit aef16cc8a4c670036d45590877d411a97f01e0cd
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jul 3 21:06:23 2017 +0200
resolv: Automatically reload a changed /etc/resolv.conf file [BZ #984]
This commit enhances the stub resolver to reload the configuration
in the per-thread _res object if the /etc/resolv.conf file has
changed. The resolver checks whether the application has modified
_res and will not overwrite the _res object in that case.
The struct resolv_context mechanism is used to check the
configuration file only once per name lookup.
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index b26c38bae0a1674b..1914324dcc3cabc3 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -607,6 +607,7 @@ p_option(u_long option) {
case RES_SNGLKUPREOP: return "single-request-reopen";
case RES_USE_DNSSEC: return "dnssec";
case RES_NOTLDQUERY: return "no-tld-query";
+ case RES_NORELOAD: return "no-reload";
/* XXX nonreentrant */
default: sprintf(nbuf, "?0x%lx?", (u_long)option);
return (nbuf);
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 80a21fb90d991e95..fa46ce7813c1f8af 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -106,8 +106,6 @@
static uint32_t net_mask (struct in_addr);
-unsigned long long int __res_initstamp;
-
int
res_ninit (res_state statp)
{
@@ -164,6 +162,16 @@ struct resolv_conf_parser
struct resolv_conf template;
};
+/* Return true if *PREINIT contains actual preinitialization. */
+static bool
+has_preinit_values (const struct __res_state *preinit)
+{
+ return (preinit->retrans != 0 && preinit->retrans != RES_TIMEOUT)
+ || (preinit->retry != 0 && preinit->retry != RES_DFLRETRY)
+ || (preinit->options != 0
+ && (preinit->options & ~RES_INIT) != RES_DEFAULT);
+}
+
static void
resolv_conf_parser_init (struct resolv_conf_parser *parser,
const struct __res_state *preinit)
@@ -531,14 +539,8 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
return true;
}
-/* Set up default settings. If the /etc/resolv.conf configuration
- file exist, the values there will have precedence. Otherwise, the
- server address is set to INADDR_LOOPBACK and the default domain
- name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN
- environment variables can be used to override some settings.
- Return 0 if completes successfully, -1 on error. */
-int
-__res_vinit (res_state statp, int preinit)
+struct resolv_conf *
+__resolv_conf_load (struct __res_state *preinit)
{
/* Ensure that /etc/hosts.conf has been loaded (once). */
_res_hconf_init ();
@@ -559,20 +561,14 @@ __res_vinit (res_state statp, int preinit)
default:
/* Other errors refer to resource allocation problems and
need to be handled by the application. */
- return -1;
+ return NULL;
}
struct resolv_conf_parser parser;
- if (preinit)
- {
- resolv_conf_parser_init (&parser, statp);
- statp->id = res_randomid ();
- }
- else
- resolv_conf_parser_init (&parser, NULL);
+ resolv_conf_parser_init (&parser, preinit);
- bool ok = res_vinit_1 (fp, &parser);
- if (ok)
+ struct resolv_conf *conf = NULL;
+ if (res_vinit_1 (fp, &parser))
{
parser.template.nameserver_list
= nameserver_list_begin (&parser.nameserver_list);
@@ -583,21 +579,42 @@ __res_vinit (res_state statp, int preinit)
= search_list_size (&parser.search_list);
parser.template.sort_list = sort_list_begin (&parser.sort_list);
parser.template.sort_list_size = sort_list_size (&parser.sort_list);
- struct resolv_conf *conf = __resolv_conf_allocate (&parser.template);
- if (conf == NULL)
- ok = false;
- else
- {
- ok = __resolv_conf_attach (statp, conf);
- __resolv_conf_put (conf);
- }
+ conf = __resolv_conf_allocate (&parser.template);
}
resolv_conf_parser_free (&parser);
- if (!ok)
+ return conf;
+}
+
+/* Set up default settings. If the /etc/resolv.conf configuration
+ file exist, the values there will have precedence. Otherwise, the
+ server address is set to INADDR_LOOPBACK and the default domain
+ name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN
+ environment variables can be used to override some settings.
+ Return 0 if completes successfully, -1 on error. */
+int
+__res_vinit (res_state statp, int preinit)
+{
+ struct resolv_conf *conf;
+ if (preinit && has_preinit_values (statp))
+ /* For the preinit case, we cannot use the cached configuration
+ because some settings could be different. */
+ conf = __resolv_conf_load (statp);
+ else
+ conf = __resolv_conf_get_current ();
+ if (conf == NULL)
return -1;
+
+ bool ok = __resolv_conf_attach (statp, conf);
+ __resolv_conf_put (conf);
+ if (ok)
+ {
+ if (preinit)
+ statp->id = res_randomid ();
+ return 0;
+ }
else
- return 0;
+ return -1;
}
static void
@@ -652,6 +669,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options)
{ STRnLEN ("single-request"), 0, RES_SNGLKUP },
{ STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
{ STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
+ { STRnLEN ("no-reload"), 0, RES_NORELOAD },
{ STRnLEN ("use-vc"), 0, RES_USEVC }
};
#define noptions (sizeof (options) / sizeof (options[0]))
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index b90816472ab09dc2..8dd06f9f1310248a 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -42,18 +42,6 @@
#include <libc-lock.h>
#include <resolv-internal.h>
-/* We have atomic increment operations on 64-bit platforms. */
-#if __WORDSIZE == 64
-# define atomicinclock(lock) (void) 0
-# define atomicincunlock(lock) (void) 0
-# define atomicinc(var) catomic_increment (&(var))
-#else
-__libc_lock_define_initialized (static, lock);
-# define atomicinclock(lock) __libc_lock_lock (lock)
-# define atomicincunlock(lock) __libc_lock_unlock (lock)
-# define atomicinc(var) ++var
-#endif
-
int
res_init (void)
{
@@ -90,12 +78,6 @@ res_init (void)
if (!_res.id)
_res.id = res_randomid ();
- atomicinclock (lock);
- /* Request all threads to re-initialize their resolver states,
- resolv.conf might have changed. */
- atomicinc (__res_initstamp);
- atomicincunlock (lock);
-
return __res_vinit (&_res, 1);
}
diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
index 9246497196adab7d..32dc44777e311849 100644
--- a/resolv/resolv-internal.h
+++ b/resolv/resolv-internal.h
@@ -97,7 +97,4 @@ int __res_nopt (struct resolv_context *, int n0,
int __inet_pton_length (int af, const char *src, size_t srclen, void *);
libc_hidden_proto (__inet_pton_length)
-/* Used to propagate the effect of res_init calls across threads. */
-extern unsigned long long int __res_initstamp attribute_hidden;
-
#endif /* _RESOLV_INTERNAL_H */
diff --git a/resolv/resolv.h b/resolv/resolv.h
index b83232cca8e8f0c3..6d4271987a0d705a 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -196,6 +196,7 @@ struct res_sym {
#define RES_USE_DNSSEC 0x00800000 /* use DNSSEC using OK bit in OPT */
#define RES_NOTLDQUERY 0x01000000 /* Do not look up unqualified name
as a TLD. */
+#define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */
#define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH)
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index dd665239926cbac7..9ef59240ebc57a70 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <libc-lock.h>
#include <resolv-internal.h>
+#include <sys/stat.h>
/* _res._u._ext.__glibc_extension_index is used as an index into a
struct resolv_conf_array object. The intent of this construction
@@ -54,6 +55,15 @@ struct resolv_conf_global
the array element is overwritten with NULL. */
struct resolv_conf_array array;
+ /* Cached current configuration object for /etc/resolv.conf. */
+ struct resolv_conf *conf_current;
+
+ /* These properties of /etc/resolv.conf are used to check if the
+ configuration needs reloading. */
+ struct timespec conf_mtime;
+ struct timespec conf_ctime;
+ off64_t conf_size;
+ ino64_t conf_ino;
};
/* Lazily allocated storage for struct resolv_conf_global. */
@@ -100,6 +110,75 @@ conf_decrement (struct resolv_conf *conf)
free (conf);
}
+struct resolv_conf *
+__resolv_conf_get_current (void)
+{
+ struct stat64 st;
+ if (stat64 (_PATH_RESCONF, &st) != 0)
+ {
+ switch (errno)
+ {
+ case EACCES:
+ case EISDIR:
+ case ELOOP:
+ case ENOENT:
+ case ENOTDIR:
+ case EPERM:
+ /* Ignore errors due to file system contents. */
+ memset (&st, 0, sizeof (st));
+ break;
+ default:
+ /* Other errors are fatal. */
+ return NULL;
+ }
+ }
+
+ struct resolv_conf_global *global_copy = get_locked_global ();
+ if (global_copy == NULL)
+ return NULL;
+ struct resolv_conf *conf;
+ if (global_copy->conf_current != NULL
+ && (global_copy->conf_mtime.tv_sec == st.st_mtim.tv_sec
+ && global_copy->conf_mtime.tv_nsec == st.st_mtim.tv_nsec
+ && global_copy->conf_ctime.tv_sec == st.st_ctim.tv_sec
+ && global_copy->conf_ctime.tv_nsec == st.st_ctim.tv_nsec
+ && global_copy->conf_ino == st.st_ino
+ && global_copy->conf_size == st.st_size))
+ /* We can reuse the cached configuration object. */
+ conf = global_copy->conf_current;
+ else
+ {
+ /* Parse configuration while holding the lock. This avoids
+ duplicate work. */
+ conf = __resolv_conf_load (NULL);
+ if (conf != NULL)
+ {
+ if (global_copy->conf_current != NULL)
+ conf_decrement (global_copy->conf_current);
+ global_copy->conf_current = conf; /* Takes ownership. */
+
+ /* Update file modification stamps. The configuration we
+ read could be a newer version of the file, but this does
+ not matter because this will lead to an extraneous reload
+ later. */
+ global_copy->conf_mtime = st.st_mtim;
+ global_copy->conf_ctime = st.st_ctim;
+ global_copy->conf_ino = st.st_ino;
+ global_copy->conf_size = st.st_size;
+ }
+ }
+
+ if (conf != NULL)
+ {
+ /* Return an additional reference. */
+ assert (conf->__refcount > 0);
+ ++conf->__refcount;
+ assert (conf->__refcount > 0);
+ }
+ put_locked_global (global_copy);
+ return conf;
+}
+
/* Internal implementation of __resolv_conf_get, without validation
against *RESP. */
static struct resolv_conf *
@@ -320,7 +399,6 @@ __resolv_conf_allocate (const struct resolv_conf *init)
conf->retry = init->retry;
conf->options = init->options;
conf->ndots = init->ndots;
- conf->initstamp = __res_initstamp;
/* Allocate the arrays with pointers. These must come first because
they have the highets alignment. */
@@ -580,6 +658,12 @@ freeres (void)
if (global == NULL)
return;
+ if (global->conf_current != NULL)
+ {
+ conf_decrement (global->conf_current);
+ global->conf_current = NULL;
+ }
+
/* Note that this frees only the array itself. The pointed-to
configuration objects should have been deallocated by res_nclose
and per-thread cleanup functions. */
diff --git a/resolv/resolv_conf.h b/resolv/resolv_conf.h
index 7ca80cdeba115c12..0ff8bd7e928708fc 100644
--- a/resolv/resolv_conf.h
+++ b/resolv/resolv_conf.h
@@ -35,11 +35,6 @@ struct resolv_sortlist_entry
object. */
struct resolv_conf
{
- /* Used to propagate the effect of res_init across threads. This
- member is mutable and prevents sharing of the same struct
- resolv_conf object among multiple struct __res_state objects. */
- unsigned long long int initstamp;
-
/* Reference counter. The object is deallocated once it reaches
zero. For internal use within resolv_conf only. */
size_t __refcount;
@@ -69,6 +64,18 @@ struct resolv_conf
struct __res_state;
+/* Read /etc/resolv.conf and return a configuration object, or NULL if
+ /etc/resolv.conf cannot be read due to memory allocation errors.
+ If PREINIT is not NULL, some configuration values are taken from the
+ struct __res_state object. */
+struct resolv_conf *__resolv_conf_load (struct __res_state *preinit)
+ attribute_hidden __attribute__ ((warn_unused_result));
+
+/* Return a configuration object for the current /etc/resolv.conf
+ settings, or NULL on failure. The object is cached. */
+struct resolv_conf *__resolv_conf_get_current (void)
+ attribute_hidden __attribute__ ((warn_unused_result));
+
/* Return the extended resolver state for *RESP, or NULL if it cannot
be determined. A call to this function must be paired with a call
to __resolv_conf_put. */
diff --git a/resolv/resolv_context.c b/resolv/resolv_context.c
index 0ee2184055911d02..35d4b3d41d59fc98 100644
--- a/resolv/resolv_context.c
+++ b/resolv/resolv_context.c
@@ -51,6 +51,20 @@
resolver state. */
static __thread struct resolv_context *current attribute_tls_model_ie;
+/* The resolv_conf handling will gives us a ctx->conf pointer even if
+ these fields do not match because a mis-match does not cause a loss
+ of state (_res objects can store the full information). This
+ function checks to ensure that there is a full patch, to prevent
+ overwriting a patched configuration. */
+static bool
+replicated_configuration_matches (const struct resolv_context *ctx)
+{
+ return ctx->resp->options == ctx->conf->options
+ && ctx->resp->retrans == ctx->conf->retrans
+ && ctx->resp->retry == ctx->conf->retry
+ && ctx->resp->ndots == ctx->conf->ndots;
+}
+
/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
res_init in some other thread requested re-initializing. */
static __attribute__ ((warn_unused_result)) bool
@@ -59,27 +73,36 @@ maybe_init (struct resolv_context *ctx, bool preinit)
struct __res_state *resp = ctx->resp;
if (resp->options & RES_INIT)
{
+ if (resp->options & RES_NORELOAD)
+ /* Configuration reloading was explicitly disabled. */
+ return true;
+
/* If there is no associated resolv_conf object despite the
initialization, something modified *ctx->resp. Do not
override those changes. */
- if (ctx->conf != NULL && ctx->conf->initstamp != __res_initstamp)
+ if (ctx->conf != NULL && replicated_configuration_matches (ctx))
{
- if (resp->nscount > 0)
- /* This call will detach the extended resolver state. */
- __res_iclose (resp, true);
- /* And this call will attach it again. */
- if (__res_vinit (resp, 1) < 0)
+ struct resolv_conf *current = __resolv_conf_get_current ();
+ if (current == NULL)
+ return false;
+
+ /* Check if the configuration changed. */
+ if (current != ctx->conf)
{
- /* The configuration no longer matches after failed
- initialization. */
- __resolv_conf_put (ctx->conf);
- ctx->conf = NULL;
- return false;
+ /* This call will detach the extended resolver state. */
+ if (resp->nscount > 0)
+ __res_iclose (resp, true);
+ /* Reattach the current configuration. */
+ if (__resolv_conf_attach (ctx->resp, current))
+ {
+ __resolv_conf_put (ctx->conf);
+ /* ctx takes ownership, so we do not release current. */
+ ctx->conf = current;
+ }
}
- /* Delay the release of the old configuration until this
- point, so that __res_vinit can reuse it if possible. */
- __resolv_conf_put (ctx->conf);
- ctx->conf = __resolv_conf_get (ctx->resp);
+ else
+ /* No change. Drop the reference count for current. */
+ __resolv_conf_put (current);
}
return true;
}
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index f98e9f40305d4897..9e496a3212b0f2ab 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -151,6 +151,7 @@ print_resp (FILE *fp, res_state resp)
print_option_flag (fp, &options, RES_SNGLKUPREOP,
"single-request-reopen");
print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query");
+ print_option_flag (fp, &options, RES_NORELOAD, "no-reload");
fputc ('\n', fp);
if (options != 0)
fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
@@ -470,6 +471,28 @@ struct test_case test_cases[] =
"nameserver 192.0.2.1\n"
"; nameserver[0]: [192.0.2.1]:53\n"
},
+ {.name = "basic no-reload",
+ .conf = "options no-reload\n"
+ "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options no-reload\n"
+ "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"
+ },
+ {.name = "basic no-reload via RES_OPTIONS",
+ .conf = "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options no-reload\n"
+ "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",
+ .res_options = "no-reload"
+ },
{.name = "whitespace",
.conf = "# This test covers comment and whitespace processing "
" (trailing whitespace,\n"
@@ -722,18 +745,7 @@ test_file_contents (const struct test_case *t)
}
/* Special tests which do not follow the general pattern. */
-enum { special_tests_count = 7 };
-
-#if TEST_THREAD
-/* Called from test number 3-6 to trigger reloading of the
- configuration. */
-static void *
-special_test_call_res_init (void *closure)
-{
- TEST_VERIFY (res_init () == 0);
- return NULL;
-}
-#endif
+enum { special_tests_count = 11 };
/* Implementation of special tests. */
static void
@@ -800,20 +812,29 @@ special_test_callback (void *closure)
case 4:
case 5:
case 6:
- /* Test res_init change broadcast. This requires a second
- thread to trigger the reload. */
-#if TEST_THREAD
support_write_file_string (_PATH_RESCONF,
"options edns0\n"
"nameserver 192.0.2.1\n");
+ goto reload_tests;
+ case 7: /* 7 and the following tests are with no-reload. */
+ case 8:
+ case 9:
+ case 10:
+ support_write_file_string (_PATH_RESCONF,
+ "options edns0 no-reload\n"
+ "nameserver 192.0.2.1\n");
+ /* Fall through. */
+ reload_tests:
for (int iteration = 0; iteration < 2; ++iteration)
{
switch (test_index)
{
case 3:
+ case 7:
TEST_VERIFY (res_init () == 0);
break;
case 4:
+ case 8:
{
unsigned char buf[512];
TEST_VERIFY
@@ -822,37 +843,44 @@ special_test_callback (void *closure)
}
break;
case 5:
+ case 9:
gethostbyname (test_hostname);
break;
case 6:
+ case 10:
{
struct addrinfo *ai;
(void) getaddrinfo (test_hostname, NULL, NULL, &ai);
}
break;
}
- if (iteration == 0)
+ /* test_index == 7 is res_init and performs a reload even
+ with no-reload. */
+ if (iteration == 0 || test_index > 7)
{
TEST_VERIFY (_res.options & RES_USE_EDNS0);
TEST_VERIFY (!(_res.options & RES_ROTATE));
+ if (test_index < 7)
+ TEST_VERIFY (!(_res.options & RES_NORELOAD));
+ else
+ TEST_VERIFY (_res.options & RES_NORELOAD);
TEST_VERIFY (_res.nscount == 1);
+ /* File change triggers automatic reloading. */
support_write_file_string (_PATH_RESCONF,
"options rotate\n"
"nameserver 192.0.2.1\n"
"nameserver 192.0.2.2\n");
- xpthread_join (xpthread_create
- (NULL, special_test_call_res_init, NULL));
}
else
{
- /* edns0 was dropped, but the flag is not cleared. See
- bug 21701. */
- /* TEST_VERIFY (!(_res.options & RES_USE_EDNS0)); */
+ if (test_index != 3 && test_index != 7)
+ /* test_index 3, 7 are res_init; this function does
+ not reset flags. See bug 21701. */
+ TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
TEST_VERIFY (_res.options & RES_ROTATE);
TEST_VERIFY (_res.nscount == 2);
}
}
-#endif
break;
}
}

View File

@ -0,0 +1,132 @@
commit a7ff1da8239a5f0e1927db9d5310f53cfea97fc2
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 13 10:52:27 2017 +0200
resolv: Remove internal and unused definitions from <resolv.h>
The RES_F_* constants are only used with the private _res._flags
member. RES_EXHAUSTIVE is unused. The removed function
declarations refer to functions not actually exported by glibc,
so they are unusable by applications.
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index 14557dd323f5f4b2..e23559bad3d92e71 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -115,6 +115,8 @@
extern const char *_res_sectioncodes[] attribute_hidden;
+static const char *p_section(int section, int opcode);
+
/*
* Print the current options.
*/
@@ -512,7 +514,7 @@ libresolv_hidden_def (p_type)
/*
* Return a string for the type.
*/
-const char *
+static const char *
p_section(int section, int opcode) {
const struct res_sym *symbols;
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 57156d01ec3c9fc2..c3ebcbf6b50fcf4b 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -74,6 +74,7 @@
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
+#include <resolv/resolv-internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 93db5b9a615ffde7..77d59dcc4e3b8d23 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -101,7 +101,7 @@
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
-#include <resolv.h>
+#include <resolv/resolv-internal.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
index 76fbe2f1a61b79bb..0d69ce10d33afcc5 100644
--- a/resolv/resolv-internal.h
+++ b/resolv/resolv-internal.h
@@ -22,6 +22,12 @@
#include <resolv.h>
#include <stdbool.h>
+/* Resolver flags. Used for _flags in struct __res_state. */
+#define RES_F_VC 0x00000001 /* Socket is TCP. */
+#define RES_F_CONN 0x00000002 /* Socket is connected. */
+#define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors. */
+
+
/* Internal version of RES_USE_INET6 which does not trigger a
deprecation warning. */
#define DEPRECATED_RES_USE_INET6 0x00002000
diff --git a/resolv/resolv.h b/resolv/resolv.h
index 7809e2eb194f48ef..9fef8e9f248c84e6 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -163,16 +163,6 @@ struct res_sym {
};
/*
- * Resolver flags (used to be discrete per-module statics ints).
- */
-#define RES_F_VC 0x00000001 /* socket is TCP */
-#define RES_F_CONN 0x00000002 /* socket is connected */
-#define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors */
-
-/* res_findzonecut() options */
-#define RES_EXHAUSTIVE 0x00000001 /* always do all queries */
-
-/*
* Resolver options (keep these in synch with res_debug.c, please)
*/
#define RES_INIT 0x00000001 /* address initialized */
@@ -285,7 +275,6 @@ __END_DECLS
#define p_fqnname __p_fqnname
#define p_option __p_option
#define p_secstodate __p_secstodate
-#define p_section __p_section
#define p_time __p_time
#define p_type __p_type
#define p_rcode __p_rcode
@@ -299,12 +288,10 @@ __END_DECLS
#define res_nclose __res_nclose
#define res_ninit __res_ninit
#define res_nmkquery __res_nmkquery
-#define res_npquery __res_npquery
#define res_nquery __res_nquery
#define res_nquerydomain __res_nquerydomain
#define res_nsearch __res_nsearch
#define res_nsend __res_nsend
-#define res_nisourserver __res_nisourserver
#define res_ownok __res_ownok
#define res_queriesmatch __res_queriesmatch
#define res_randomid __res_randomid
@@ -356,14 +343,9 @@ int res_queriesmatch (const unsigned char *,
const unsigned char *,
const unsigned char *,
const unsigned char *) __THROW;
-const char * p_section (int __section, int __opcode) __THROW;
/* Things involving a resolver context. */
int res_ninit (res_state) __THROW;
-int res_nisourserver (const res_state,
- const struct sockaddr_in *) __THROW;
void fp_resstat (const res_state, FILE *) __THROW;
-void res_npquery (const res_state, const unsigned char *, int,
- FILE *) __THROW;
const char * res_hostalias (const res_state, const char *, char *, size_t)
__THROW;
int res_nquery (res_state, const char *, int, int,

View File

@ -0,0 +1,24 @@
commit 905a6129147e7ee80e8918e23efe212433b8cce7
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Sep 6 15:46:54 2017 +0200
resolv: Fix memory leak with OOM during resolv.conf parsing [BZ #22095]
(cherry picked from commit 5670c4ab256114e869b1df4b05653aa5f909182c)
diff --git a/resolv/res_init.c b/resolv/res_init.c
index fa46ce7813c1f8af..4e1f9fe8dea93e8a 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -446,6 +446,11 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
(&parser->nameserver_list);
if (p != NULL)
*p = sa;
+ else
+ {
+ free (sa);
+ return false;
+ }
}
continue;
}

View File

@ -0,0 +1,520 @@
commit cb3c27e87b914bde5ec00a02363536c76e08b850
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jul 5 17:39:33 2017 +0200
support: Add resolver testing mode which does not patch _res
diff --git a/resolv/Makefile b/resolv/Makefile
index e80583c72b96efb4..83f99791e3a097cc 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -65,7 +65,9 @@ tests += \
tst-resolv-res_init-thread \
# Needs resolv_context.
-tests += tst-resolv-res_ninit
+tests += \
+ tst-resolv-res_ninit \
+ tst-resolv-threads \
endif
@@ -168,6 +170,8 @@ $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-threads: \
+ $(libdl) $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-canonname: \
$(libdl) $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/tst-resolv-threads.c b/resolv/tst-resolv-threads.c
new file mode 100644
index 0000000000000000..7be417b056f720d8
--- /dev/null
+++ b/resolv/tst-resolv-threads.c
@@ -0,0 +1,484 @@
+/* Test basic nss_dns functionality with multiple threads.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Unlike tst-resolv-basic, this test does not overwrite the _res
+ structure and relies on namespaces to achieve the redirection to
+ the test servers with a custom /etc/resolv.conf file. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <gnu/lib-names.h>
+#include <netdb.h>
+#include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+
+/* Each client thread sends this many queries. */
+enum { queries_per_thread = 500 };
+
+/* Return a small positive number identifying this thread. */
+static int
+get_thread_number (void)
+{
+ static int __thread local;
+ if (local != 0)
+ return local;
+ static int global = 1;
+ local = __atomic_fetch_add (&global, 1, __ATOMIC_RELAXED);
+ return local;
+}
+
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ TEST_VERIFY_EXIT (qname != NULL);
+
+ int counter = 0;
+ int thread = 0;
+ int dummy = 0;
+ TEST_VERIFY (sscanf (qname, "counter%d.thread%d.example.com%n",
+ &counter, &thread, &dummy) == 2);
+ TEST_VERIFY (dummy > 0);
+
+ struct resolv_response_flags flags = { 0 };
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, qtype, 0);
+ switch (qtype)
+ {
+ case T_A:
+ {
+ char ipv4[4] = {10, 0, counter, thread};
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+ }
+ break;
+ case T_AAAA:
+ {
+ char ipv6[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0,
+ counter, 0, thread, 0, 0};
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+ }
+ break;
+ default:
+ support_record_failure ();
+ printf ("error: unexpected QTYPE: %s/%u/%u\n",
+ qname, qclass, qtype);
+ }
+ resolv_response_close_record (b);
+}
+
+/* Check that the resolver configuration for this thread has an
+ extended resolver configuration. */
+static void
+check_have_conf (void)
+{
+ struct resolv_context *ctx = __resolv_context_get ();
+ TEST_VERIFY_EXIT (ctx != NULL);
+ TEST_VERIFY (ctx->conf != NULL);
+ __resolv_context_put (ctx);
+}
+
+/* Verify that E matches the expected response for FAMILY and
+ COUNTER. */
+static void
+check_hostent (const char *caller, const char *function, const char *qname,
+ int ret, struct hostent *e, int family, int counter)
+{
+ if (ret != 0)
+ {
+ errno = ret;
+ support_record_failure ();
+ printf ("error: %s: %s for %s failed: %m\n", caller, function, qname);
+ return;
+ }
+
+ TEST_VERIFY_EXIT (e != NULL);
+ TEST_VERIFY (strcmp (qname, e->h_name) == 0);
+ TEST_VERIFY (e->h_addrtype == family);
+ TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL);
+ TEST_VERIFY (e->h_addr_list[1] == NULL);
+ switch (family)
+ {
+ case AF_INET:
+ {
+ char addr[4] = {10, 0, counter, get_thread_number ()};
+ TEST_VERIFY (e->h_length == sizeof (addr));
+ TEST_VERIFY (memcmp (e->h_addr_list[0], addr, sizeof (addr)) == 0);
+ }
+ break;
+ case AF_INET6:
+ {
+ char addr[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
+ 0, counter, 0, get_thread_number (), 0, 0};
+ TEST_VERIFY (e->h_length == sizeof (addr));
+ TEST_VERIFY (memcmp (e->h_addr_list[0], addr, sizeof (addr)) == 0);
+ }
+ break;
+ default:
+ FAIL_EXIT1 ("%s: invalid address family %d", caller, family);
+ }
+ check_have_conf ();
+}
+
+/* Check a getaddrinfo result. */
+static void
+check_addrinfo (const char *caller, const char *qname,
+ int ret, struct addrinfo *ai, int family, int counter)
+{
+ if (ret != 0)
+ {
+ support_record_failure ();
+ printf ("error: %s: getaddrinfo for %s failed: %s\n",
+ caller, qname, gai_strerror (ret));
+ return;
+ }
+
+ TEST_VERIFY_EXIT (ai != NULL);
+
+ /* Check that available data matches the requirements. */
+ bool have_ipv4 = false;
+ bool have_ipv6 = false;
+ for (struct addrinfo *p = ai; p != NULL; p = p->ai_next)
+ {
+ TEST_VERIFY (p->ai_socktype == SOCK_STREAM);
+ TEST_VERIFY (p->ai_protocol == IPPROTO_TCP);
+ TEST_VERIFY_EXIT (p->ai_addr != NULL);
+ TEST_VERIFY (p->ai_addr->sa_family == p->ai_family);
+
+ switch (p->ai_family)
+ {
+ case AF_INET:
+ {
+ TEST_VERIFY (!have_ipv4);
+ have_ipv4 = true;
+ struct sockaddr_in *sa = (struct sockaddr_in *) p->ai_addr;
+ TEST_VERIFY (p->ai_addrlen == sizeof (*sa));
+ char addr[4] = {10, 0, counter, get_thread_number ()};
+ TEST_VERIFY (memcmp (&sa->sin_addr, addr, sizeof (addr)) == 0);
+ TEST_VERIFY (ntohs (sa->sin_port) == 80);
+ }
+ break;
+ case AF_INET6:
+ {
+ TEST_VERIFY (!have_ipv6);
+ have_ipv6 = true;
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *) p->ai_addr;
+ TEST_VERIFY (p->ai_addrlen == sizeof (*sa));
+ char addr[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
+ 0, counter, 0, get_thread_number (), 0, 0};
+ TEST_VERIFY (memcmp (&sa->sin6_addr, addr, sizeof (addr)) == 0);
+ TEST_VERIFY (ntohs (sa->sin6_port) == 80);
+ }
+ break;
+ default:
+ FAIL_EXIT1 ("%s: invalid address family %d", caller, family);
+ }
+ }
+
+ switch (family)
+ {
+ case AF_INET:
+ TEST_VERIFY (have_ipv4);
+ TEST_VERIFY (!have_ipv6);
+ break;
+ case AF_INET6:
+ TEST_VERIFY (!have_ipv4);
+ TEST_VERIFY (have_ipv6);
+ break;
+ case AF_UNSPEC:
+ TEST_VERIFY (have_ipv4);
+ TEST_VERIFY (have_ipv6);
+ break;
+ default:
+ FAIL_EXIT1 ("%s: invalid address family %d", caller, family);
+ }
+
+ check_have_conf ();
+}
+
+/* This barrier ensures that all test threads begin their work
+ simultaneously. */
+static pthread_barrier_t barrier;
+
+/* Test gethostbyname2_r (if do_2 is false) or gethostbyname2_r with
+ AF_INET (if do_2 is true). */
+static void *
+byname (bool do_2)
+{
+ int this_thread = get_thread_number ();
+ xpthread_barrier_wait (&barrier);
+ for (int i = 0; i < queries_per_thread; ++i)
+ {
+ char qname[100];
+ snprintf (qname, sizeof (qname), "counter%d.thread%d.example.com",
+ i, this_thread);
+ struct hostent storage;
+ char buf[1000];
+ struct hostent *e = NULL;
+ int herrno;
+ int ret;
+ if (do_2)
+ ret = gethostbyname_r (qname, &storage, buf, sizeof (buf),
+ &e, &herrno);
+ else
+ ret = gethostbyname2_r (qname, AF_INET, &storage, buf, sizeof (buf),
+ &e, &herrno);
+ check_hostent (__func__, do_2 ? "gethostbyname2_r" : "gethostbyname_r",
+ qname, ret, e, AF_INET, i);
+ }
+ check_have_conf ();
+ return NULL;
+}
+
+/* Test gethostbyname_r. */
+static void *
+thread_byname (void *closure)
+{
+ return byname (false);
+}
+
+/* Test gethostbyname2_r with AF_INET. */
+static void *
+thread_byname2 (void *closure)
+{
+ return byname (true);
+}
+
+/* Call gethostbyname_r with RES_USE_INET6 (if do_2 is false), or
+ gethostbyname_r with AF_INET6 (if do_2 is true). */
+static void *
+byname_inet6 (bool do_2)
+{
+ int this_thread = get_thread_number ();
+ xpthread_barrier_wait (&barrier);
+ if (!do_2)
+ {
+ res_init ();
+ _res.options |= DEPRECATED_RES_USE_INET6;
+ TEST_VERIFY (strcmp (_res.defdname, "example.com") == 0);
+ }
+ for (int i = 0; i < queries_per_thread; ++i)
+ {
+ char qname[100];
+ snprintf (qname, sizeof (qname), "counter%d.thread%d.example.com",
+ i, this_thread);
+ struct hostent storage;
+ char buf[1000];
+ struct hostent *e = NULL;
+ int herrno;
+ int ret;
+ if (do_2)
+ ret = gethostbyname2_r (qname, AF_INET6, &storage, buf, sizeof (buf),
+ &e, &herrno);
+ else
+ ret = gethostbyname_r (qname, &storage, buf, sizeof (buf),
+ &e, &herrno);
+ check_hostent (__func__,
+ do_2 ? "gethostbyname2_r" : "gethostbyname_r",
+ qname, ret, e, AF_INET6, i);
+ }
+ return NULL;
+}
+
+/* Test gethostbyname_r with AF_INET6. */
+static void *
+thread_byname_inet6 (void *closure)
+{
+ return byname_inet6 (false);
+}
+
+/* Test gethostbyname2_r with AF_INET6. */
+static void *
+thread_byname2_af_inet6 (void *closure)
+{
+ return byname_inet6 (true);
+}
+
+/* Run getaddrinfo tests for FAMILY. */
+static void *
+gai (int family, bool do_inet6)
+{
+ int this_thread = get_thread_number ();
+ xpthread_barrier_wait (&barrier);
+ if (do_inet6)
+ {
+ res_init ();
+ _res.options |= DEPRECATED_RES_USE_INET6;
+ check_have_conf ();
+ }
+ for (int i = 0; i < queries_per_thread; ++i)
+ {
+ char qname[100];
+ snprintf (qname, sizeof (qname), "counter%d.thread%d.example.com",
+ i, this_thread);
+ struct addrinfo hints =
+ {
+ .ai_family = family,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ };
+ struct addrinfo *ai;
+ int ret = getaddrinfo (qname, "80", &hints, &ai);
+ check_addrinfo (__func__, qname, ret, ai, family, i);
+ if (ret == 0)
+ freeaddrinfo (ai);
+ }
+ return NULL;
+}
+
+/* Test getaddrinfo with AF_INET. */
+static void *
+thread_gai_inet (void *closure)
+{
+ return gai (AF_INET, false);
+}
+
+/* Test getaddrinfo with AF_INET6. */
+static void *
+thread_gai_inet6 (void *closure)
+{
+ return gai (AF_INET6, false);
+}
+
+/* Test getaddrinfo with AF_UNSPEC. */
+static void *
+thread_gai_unspec (void *closure)
+{
+ return gai (AF_UNSPEC, false);
+}
+
+/* Test getaddrinfo with AF_INET. */
+static void *
+thread_gai_inet_inet6 (void *closure)
+{
+ return gai (AF_INET, true);
+}
+
+/* Test getaddrinfo with AF_INET6. */
+static void *
+thread_gai_inet6_inet6 (void *closure)
+{
+ return gai (AF_INET6, true);
+}
+
+/* Test getaddrinfo with AF_UNSPEC. */
+static void *
+thread_gai_unspec_inet6 (void *closure)
+{
+ return gai (AF_UNSPEC, true);
+}
+
+/* Description of the chroot environment used to run the tests. */
+static struct support_chroot *chroot_env;
+
+/* Set up the chroot environment. */
+static void
+prepare (int argc, char **argv)
+{
+ chroot_env = support_chroot_create
+ ((struct support_chroot_configuration)
+ {
+ .resolv_conf =
+ "search example.com\n"
+ "nameserver 127.0.0.1\n"
+ "nameserver 127.0.0.2\n"
+ "nameserver 127.0.0.3\n",
+ });
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ if (!support_enter_network_namespace ())
+ return EXIT_UNSUPPORTED;
+ if (!support_can_chroot ())
+ return EXIT_UNSUPPORTED;
+
+ /* Load the shared object outside of the chroot. */
+ TEST_VERIFY (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) != NULL);
+
+ xchroot (chroot_env->path_chroot);
+ TEST_VERIFY_EXIT (chdir ("/") == 0);
+
+ struct sockaddr_in server_address =
+ {
+ .sin_family = AF_INET,
+ .sin_addr = { .s_addr = htonl (INADDR_LOOPBACK) },
+ .sin_port = htons (53)
+ };
+ const struct sockaddr *server_addresses[1] =
+ { (const struct sockaddr *) &server_address };
+
+ struct resolv_test *aux = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response,
+ .nscount = 1,
+ .disable_redirect = true,
+ .server_address_overrides = server_addresses,
+ });
+
+ enum { thread_count = 10 };
+ xpthread_barrier_init (&barrier, NULL, thread_count + 1);
+ pthread_t threads[thread_count];
+ typedef void *(*thread_func) (void *);
+ thread_func thread_funcs[thread_count] =
+ {
+ thread_byname,
+ thread_byname2,
+ thread_byname_inet6,
+ thread_byname2_af_inet6,
+ thread_gai_inet,
+ thread_gai_inet6,
+ thread_gai_unspec,
+ thread_gai_inet_inet6,
+ thread_gai_inet6_inet6,
+ thread_gai_unspec_inet6,
+ };
+ for (int i = 0; i < thread_count; ++i)
+ threads[i] = xpthread_create (NULL, thread_funcs[i], NULL);
+ xpthread_barrier_wait (&barrier); /* Start the test threads. */
+ for (int i = 0; i < thread_count; ++i)
+ xpthread_join (threads[i]);
+
+ resolv_test_end (aux);
+ support_chroot_free (chroot_env);
+
+ return 0;
+}
+
+#define PREPARE prepare
+#include <support/test-driver.c>

View File

@ -0,0 +1,33 @@
commit 9f5a1271315b0e7c7828f2d8077ab33dca3ee8bd
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Jul 6 14:03:39 2017 +0200
resolv: Deal with non-deterministic address order in tst-resolv-basic
diff --git a/resolv/tst-resolv-basic.c b/resolv/tst-resolv-basic.c
index 95aea1bcfb266017..66a0e8a1659219b4 100644
--- a/resolv/tst-resolv-basic.c
+++ b/resolv/tst-resolv-basic.c
@@ -495,22 +495,6 @@ do_test (void)
test_bug_21295 ();
test_nodata_nxdomain ();
- /* Test for bug 21295. */
- check_ai_hints ("www.example", "80",
- (struct addrinfo) { .ai_family = AF_INET6,
- .ai_socktype = SOCK_STREAM,
- .ai_flags = AI_V4MAPPED | AI_ALL, },
- "flags: AI_V4MAPPED AI_ALL\n"
- "address: STREAM/TCP 2001:db8::1 80\n"
- "address: STREAM/TCP ::ffff:192.0.2.17 80\n");
- check_ai_hints ("t.www.example", "80",
- (struct addrinfo) { .ai_family = AF_INET6,
- .ai_socktype = SOCK_STREAM,
- .ai_flags = AI_V4MAPPED | AI_ALL, },
- "flags: AI_V4MAPPED AI_ALL\n"
- "address: STREAM/TCP 2001:db8::3 80\n"
- "address: STREAM/TCP ::ffff:192.0.2.19 80\n");
-
resolv_test_end (aux);
return 0;

View File

@ -0,0 +1,224 @@
commit 4e45d83c92dbb5b8dc20654f32395108d18cf739
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jul 3 17:41:19 2017 +0200
resolv: Add preinit tests to resolv/tst-resolv-res_init-skeleton.c
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index b5fe2cfb002679f2..ce206f52c4c27c32 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -260,7 +260,7 @@ enum test_init
static const char *const test_init_names[] =
{
[test_init] = "res_init",
- [test_ninit] = "res_init",
+ [test_ninit] = "res_ninit",
[test_mkquery] = "res_mkquery",
[test_gethostbyname] = "gethostbyname",
[test_getaddrinfo] = "getaddrinfo",
@@ -540,6 +540,192 @@ test_file_contents (const struct test_case *t)
}
}
+/* Special tests which do not follow the general pattern. */
+enum { special_tests_count = 7 };
+
+#if TEST_THREAD
+/* Called from test number 3-6 to trigger reloading of the
+ configuration. */
+static void *
+special_test_call_res_init (void *closure)
+{
+ TEST_VERIFY (res_init () == 0);
+ return NULL;
+}
+#endif
+
+/* Implementation of special tests. */
+static void
+special_test_callback (void *closure)
+{
+ unsigned int *test_indexp = closure;
+ unsigned test_index = *test_indexp;
+ TEST_VERIFY (test_index < special_tests_count);
+ if (test_verbose > 0)
+ printf ("info: special test %u\n", test_index);
+ xchroot (path_chroot);
+
+ switch (test_index)
+ {
+ case 0:
+ case 1:
+ /* Second res_init with missing or empty file preserves
+ flags. */
+ if (test_index == 1)
+ TEST_VERIFY (unlink (_PATH_RESCONF) == 0);
+ _res.options = RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* First res_init clears flag. */
+ TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
+ _res.options |= RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* Second res_init preserves flag. */
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ if (test_index == 1)
+ /* Restore empty file. */
+ support_write_file_string (_PATH_RESCONF, "");
+ break;
+
+ case 2:
+ /* Second res_init is cumulative. */
+ support_write_file_string (_PATH_RESCONF,
+ "options rotate\n"
+ "nameserver 192.0.2.1\n");
+ _res.options = RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* First res_init clears flag. */
+ TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
+ /* And sets RES_ROTATE. */
+ TEST_VERIFY (_res.options & RES_ROTATE);
+ _res.options |= RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* Second res_init preserves flag. */
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ TEST_VERIFY (_res.options & RES_ROTATE);
+ /* Reloading the configuration does not clear the explicitly set
+ flag. */
+ support_write_file_string (_PATH_RESCONF,
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n");
+ TEST_VERIFY (res_init () == 0);
+ TEST_VERIFY (_res.nscount == 2);
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ /* Whether RES_ROTATE (originally in resolv.conf, now removed)
+ should be preserved is subject to debate. See bug 21701. */
+ /* TEST_VERIFY (!(_res.options & RES_ROTATE)); */
+ break;
+
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ /* Test res_init change broadcast. This requires a second
+ thread to trigger the reload. */
+#if TEST_THREAD
+ support_write_file_string (_PATH_RESCONF,
+ "options edns0\n"
+ "nameserver 192.0.2.1\n");
+ for (int iteration = 0; iteration < 2; ++iteration)
+ {
+ switch (test_index)
+ {
+ case 3:
+ TEST_VERIFY (res_init () == 0);
+ break;
+ case 4:
+ {
+ unsigned char buf[512];
+ TEST_VERIFY
+ (res_mkquery (QUERY, test_hostname, C_IN, T_A,
+ NULL, 0, NULL, buf, sizeof (buf)) > 0);
+ }
+ break;
+ case 5:
+ gethostbyname (test_hostname);
+ break;
+ case 6:
+ {
+ struct addrinfo *ai;
+ (void) getaddrinfo (test_hostname, NULL, NULL, &ai);
+ }
+ break;
+ }
+ if (iteration == 0)
+ {
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ TEST_VERIFY (!(_res.options & RES_ROTATE));
+ TEST_VERIFY (_res.nscount == 1);
+ support_write_file_string (_PATH_RESCONF,
+ "options rotate\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n");
+ xpthread_join (xpthread_create
+ (NULL, special_test_call_res_init, NULL));
+ }
+ else
+ {
+ /* edns0 was dropped, but the flag is not cleared. See
+ bug 21701. */
+ /* TEST_VERIFY (!(_res.options & RES_USE_EDNS0)); */
+ TEST_VERIFY (_res.options & RES_ROTATE);
+ TEST_VERIFY (_res.nscount == 2);
+ }
+ }
+#endif
+ break;
+ }
+}
+
+#if TEST_THREAD
+/* Helper function which calls special_test_callback from a
+ thread. */
+static void *
+special_test_thread_func (void *closure)
+{
+ special_test_callback (closure);
+ return NULL;
+}
+
+/* Variant of special_test_callback which runs the function on a
+ non-main thread. */
+static void
+run_special_test_on_thread (void *closure)
+{
+ xpthread_join (xpthread_create (NULL, special_test_thread_func, closure));
+}
+#endif /* TEST_THREAD */
+
+/* Perform the requested special test in a subprocess using
+ special_test_callback. */
+static void
+special_test (unsigned int test_index)
+{
+#if TEST_THREAD
+ for (int do_thread = 0; do_thread < 2; ++do_thread)
+#endif
+ {
+ void (*func) (void *) = special_test_callback;
+#if TEST_THREAD
+ if (do_thread)
+ func = run_special_test_on_thread;
+#endif
+ struct support_capture_subprocess proc
+ = support_capture_subprocess (func, &test_index);
+ char *test_name = xasprintf ("special test %u", test_index);
+ if (strcmp (proc.out.buffer, "") != 0)
+ {
+ support_record_failure ();
+ printf ("error: output mismatch for %s\n", test_name);
+ support_run_diff ("expected", "",
+ "actual", proc.out.buffer);
+ }
+ support_capture_subprocess_check (&proc, test_name, 0, sc_allow_stdout);
+ free (test_name);
+ support_capture_subprocess_free (&proc);
+ }
+}
+
+
/* Dummy DNS server. It ensures that the probe queries sent by
gethostbyname and getaddrinfo receive a reply even if the system
applies a very strict rate limit to localhost. */
@@ -672,6 +858,11 @@ do_test (void)
}
}
+ /* The tests which do not follow a regular pattern. */
+ for (unsigned int test_index = 0;
+ test_index < special_tests_count; ++test_index)
+ special_test (test_index);
+
if (server > 0)
{
if (kill (server, SIGTERM) < 0)

View File

@ -0,0 +1,128 @@
commit 39bd76df3d61c6d83c5aa8bab06c7c1dbe7159ac
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jun 27 10:21:34 2017 +0200
resolv: Avoid timeouts in test-resolv-res-init, test-resolv-res_init-thread
Some Linux kernels have very aggressive ICMP rate limiting on the
loopback interface. This commit introduces a minimal echoing DNS server
inside the network namespace, so that there is no need for ICMP error
messages anymore.
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index 1d2c475c4b233131..2b68c5ff9a69a291 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -21,6 +21,7 @@
in. */
#include <arpa/inet.h>
+#include <errno.h>
#include <gnu/lib-names.h>
#include <netdb.h>
#include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6. */
@@ -33,6 +34,7 @@
#include <support/support.h>
#include <support/temp_file.h>
#include <support/test-driver.h>
+#include <support/xsocket.h>
#include <support/xstdio.h>
#include <support/xunistd.h>
@@ -527,6 +529,73 @@ test_file_contents (const struct test_case *t)
}
}
+/* Dummy DNS server. It ensures that the probe queries sent by
+ gethostbyname and getaddrinfo receive a reply even if the system
+ applies a very strict rate limit to localhost. */
+static pid_t
+start_dummy_server (void)
+{
+ int server_socket = xsocket (AF_INET, SOCK_DGRAM, 0);
+ {
+ struct sockaddr_in sin =
+ {
+ .sin_family = AF_INET,
+ .sin_addr = { .s_addr = htonl (INADDR_LOOPBACK) },
+ .sin_port = htons (53),
+ };
+ int ret = bind (server_socket, (struct sockaddr *) &sin, sizeof (sin));
+ if (ret < 0)
+ {
+ if (errno == EACCES)
+ /* The port is reserved, which means we cannot start the
+ server. */
+ return -1;
+ FAIL_EXIT1 ("cannot bind socket to port 53: %m");
+ }
+ }
+
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ /* Child process. Echo back queries as SERVFAIL responses. */
+ while (true)
+ {
+ union
+ {
+ HEADER header;
+ unsigned char bytes[512];
+ } packet;
+ struct sockaddr_in sin;
+ socklen_t sinlen = sizeof (sin);
+
+ ssize_t ret = recvfrom
+ (server_socket, &packet, sizeof (packet),
+ MSG_NOSIGNAL, (struct sockaddr *) &sin, &sinlen);
+ if (ret < 0)
+ FAIL_EXIT1 ("recvfrom on fake server socket: %m");
+ if (ret > sizeof (HEADER))
+ {
+ /* Turn the query into a SERVFAIL response. */
+ packet.header.qr = 1;
+ packet.header.rcode = ns_r_servfail;
+
+ /* Send the response. */
+ ret = sendto (server_socket, &packet, ret,
+ MSG_NOSIGNAL, (struct sockaddr *) &sin, sinlen);
+ if (ret < 0)
+ /* The peer may have closed socket prematurely, so
+ this is not an error. */
+ printf ("warning: sending DNS server reply: %m\n");
+ }
+ }
+ }
+
+ /* In the parent, close the socket. */
+ xclose (server_socket);
+
+ return pid;
+}
+
static int
do_test (void)
{
@@ -552,6 +621,8 @@ do_test (void)
support_capture_subprocess_free (&proc);
}
+ pid_t server = start_dummy_server ();
+
for (size_t i = 0; test_cases[i].name != NULL; ++i)
{
if (test_verbose > 0)
@@ -590,6 +661,13 @@ do_test (void)
}
}
+ if (server > 0)
+ {
+ if (kill (server, SIGTERM) < 0)
+ FAIL_EXIT1 ("could not terminate server process: %m");
+ xwaitpid (server, NULL, 0);
+ }
+
free (path_chroot);
path_chroot = NULL;
free (path_resolv_conf);

View File

@ -0,0 +1,132 @@
commit 4446a885f3aeb3a33b95c72bae1f115bed77f0cb
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jul 4 14:47:29 2017 +0200
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.
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index 0ed36cde02608f2d..f391d30c277bb348 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 9e496a3212b0f2ab..8f395d8ce92773a9 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"

View File

@ -0,0 +1,251 @@
commit e237357a5a0559dee92261f1914d1fa2cd43a1a8
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jul 3 15:01:34 2017 +0200
resolv: Introduce free list for resolv_conf index slosts
diff --git a/resolv/Makefile b/resolv/Makefile
index ef5ed2966e4d6c51..c1fcf341746cf1a8 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -63,6 +63,9 @@ tests += \
tst-resolv-res_init \
tst-resolv-res_init-thread \
+# Needs resolv_context.
+tests += tst-resolv-res_ninit
+
endif
# This test accesses __inet_ntop_range, an internal libc function.
@@ -103,6 +106,7 @@ ifeq ($(run-built-tests),yes)
ifneq (no,$(PERL))
tests-special += $(objpfx)mtrace-tst-leaks.out
xtests-special += $(objpfx)mtrace-tst-leaks2.out
+tests-special += $(objpfx)mtrace-tst-resolv-res_ninit.out
endif
endif
@@ -114,7 +118,8 @@ headers += rpc/netdb.h
endif
generated += mtrace-tst-leaks.out tst-leaks.mtrace \
- mtrace-tst-leaks2.out tst-leaks2.mtrace
+ mtrace-tst-leaks2.out tst-leaks2.mtrace \
+ mtrace-tst-resolv-res_ninit.out tst-resolv-res_ninit.mtrace \
include ../Rules
@@ -142,6 +147,12 @@ $(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \
$(evaluate-test)
+tst-resolv-res_ninit-ENV = MALLOC_TRACE=$(objpfx)tst-resolv-res_ninit.mtrace
+$(objpfx)mtrace-tst-resolv-res_ninit.out: $(objpfx)tst-resolv-res_ninit.out
+ $(common-objpfx)malloc/mtrace \
+ $(objpfx)tst-resolv-res_ninit.mtrace > $@; \
+ $(evaluate-test)
+
$(objpfx)tst-bug18665-tcp: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index 9ef59240ebc57a70..b98cf92890a121f9 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -28,9 +28,12 @@
struct resolv_conf_array object. The intent of this construction
is to make reasonably sure that even if struct __res_state objects
are copied around and patched by applications, we can still detect
- accesses to stale extended resolver state. */
+ accesses to stale extended resolver state. The array elements are
+ either struct resolv_conf * pointers (if the LSB is cleared) or
+ free list entries (if the LSB is set). The free list is used to
+ speed up finding available entries in the array. */
#define DYNARRAY_STRUCT resolv_conf_array
-#define DYNARRAY_ELEMENT struct resolv_conf *
+#define DYNARRAY_ELEMENT uintptr_t
#define DYNARRAY_PREFIX resolv_conf_array_
#define DYNARRAY_INITIAL_SIZE 0
#include <malloc/dynarray-skeleton.c>
@@ -55,6 +58,10 @@ struct resolv_conf_global
the array element is overwritten with NULL. */
struct resolv_conf_array array;
+ /* Start of the free list in the array. The MSB is set if this
+ field has been initialized. */
+ uintptr_t free_list_start;
+
/* Cached current configuration object for /etc/resolv.conf. */
struct resolv_conf *conf_current;
@@ -194,15 +201,17 @@ resolv_conf_get_1 (const struct __res_state *resp)
contexts exists, so returning NULL is correct. */
return NULL;
size_t index = resp->_u._ext.__glibc_extension_index ^ INDEX_MAGIC;
- struct resolv_conf *conf;
+ struct resolv_conf *conf = NULL;
if (index < resolv_conf_array_size (&global_copy->array))
{
- conf = *resolv_conf_array_at (&global_copy->array, index);
- assert (conf->__refcount > 0);
- ++conf->__refcount;
+ uintptr_t *slot = resolv_conf_array_at (&global_copy->array, index);
+ if (!(*slot & 1))
+ {
+ conf = (struct resolv_conf *) *slot;
+ assert (conf->__refcount > 0);
+ ++conf->__refcount;
+ }
}
- else
- conf = NULL;
put_locked_global (global_copy);
return conf;
}
@@ -550,17 +559,20 @@ decrement_at_index (struct resolv_conf_global *global_copy, size_t index)
{
if (index < resolv_conf_array_size (&global_copy->array))
{
- /* Index found. Deallocate the struct resolv_conf object once
- the reference counter reaches. Free the array slot. */
- struct resolv_conf **slot
- = resolv_conf_array_at (&global_copy->array, index);
- struct resolv_conf *conf = *slot;
- if (conf != NULL)
+ /* Index found. */
+ uintptr_t *slot = resolv_conf_array_at (&global_copy->array, index);
+ /* Check that the slot is not already part of the free list. */
+ if (!(*slot & 1))
{
+ struct resolv_conf *conf = (struct resolv_conf *) *slot;
conf_decrement (conf);
- /* Clear the slot even if the reference count is positive.
- Slots are not shared. */
- *slot = NULL;
+ /* Put the slot onto the free list. */
+ if (global_copy->free_list_start == 0)
+ /* Not yet initialized. */
+ *slot = 1;
+ else
+ *slot = global_copy->free_list_start;
+ global_copy->free_list_start = (index << 1) | 1;
}
}
}
@@ -580,24 +592,21 @@ __resolv_conf_attach (struct __res_state *resp, struct resolv_conf *conf)
/* Try to find an unused index in the array. */
size_t index;
{
- size_t size = resolv_conf_array_size (&global_copy->array);
- bool found = false;
- for (index = 0; index < size; ++index)
+ if (global_copy->free_list_start & 1)
{
- struct resolv_conf **p
- = resolv_conf_array_at (&global_copy->array, index);
- if (*p == NULL)
- {
- *p = conf;
- found = true;
- break;
- }
+ /* Unlink from the free list. */
+ index = global_copy->free_list_start >> 1;
+ uintptr_t *slot = resolv_conf_array_at (&global_copy->array, index);
+ global_copy->free_list_start = *slot;
+ assert (global_copy->free_list_start & 1);
+ /* Install the configuration pointer. */
+ *slot = (uintptr_t) conf;
}
-
- if (!found)
+ else
{
+ size_t size = resolv_conf_array_size (&global_copy->array);
/* No usable index found. Increase the array size. */
- resolv_conf_array_add (&global_copy->array, conf);
+ resolv_conf_array_add (&global_copy->array, (uintptr_t) conf);
if (resolv_conf_array_has_failed (&global_copy->array))
{
put_locked_global (global_copy);
diff --git a/resolv/tst-resolv-res_ninit.c b/resolv/tst-resolv-res_ninit.c
new file mode 100644
index 0000000000000000..d08153fed78b5f03
--- /dev/null
+++ b/resolv/tst-resolv-res_ninit.c
@@ -0,0 +1,74 @@
+/* Test the creation of many struct __res_state objects.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <mcheck.h>
+#include <resolv.h>
+#include <resolv/resolv_context.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+/* Order the resolver states by their extended resolver state
+ index. */
+static int
+sort_res_state (const void *a, const void *b)
+{
+ res_state left = (res_state) a;
+ res_state right = (res_state) b;
+ return memcmp (&left->_u._ext.__glibc_extension_index,
+ &right->_u._ext.__glibc_extension_index,
+ sizeof (left->_u._ext.__glibc_extension_index));
+}
+
+static int
+do_test (void)
+{
+ mtrace ();
+
+ enum { count = 100 * 1000 };
+ res_state array = calloc (count, sizeof (*array));
+ const struct resolv_conf *conf = NULL;
+ for (size_t i = 0; i < count; ++i)
+ {
+ TEST_VERIFY (res_ninit (array + i) == 0);
+ TEST_VERIFY (array[i].nscount > 0);
+ struct resolv_context *ctx = __resolv_context_get_override (array + i);
+ TEST_VERIFY_EXIT (ctx != NULL);
+ TEST_VERIFY (ctx->resp == array + i);
+ if (i == 0)
+ {
+ conf = ctx->conf;
+ TEST_VERIFY (conf != NULL);
+ }
+ else
+ /* The underyling configuration should be identical across all
+ res_state opjects because resolv.conf did not change. */
+ TEST_VERIFY (ctx->conf == conf);
+ }
+ qsort (array, count, sizeof (*array), sort_res_state);
+ for (size_t i = 1; i < count; ++i)
+ /* All extension indices should be different. */
+ TEST_VERIFY (sort_res_state (array + i - 1, array + i) < 0);
+ for (size_t i = 0; i < count; ++i)
+ res_nclose (array + i);
+ free (array);
+
+ TEST_VERIFY (res_init () == 0);
+ return 0;
+}
+
+#include <support/test-driver.c>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,788 @@
commit 3f853f22c87f0b671c0366eb290919719fa56c0e
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Jul 1 00:53:05 2017 +0200
resolv: Lift domain search list limits [BZ #19569] [BZ #21475]
This change uses the extended resolver state in struct resolv_conf to
store the search list. If applications have not patched the _res
object directly, this extended search list will be used by the stub
resolver during name resolution.
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 659d3ea81f973257..5941d37f3241b1e7 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -124,18 +124,75 @@ is_sort_mask (char ch)
return ch == '/' || ch == '&';
}
+/* Array of strings for the search array. The backing store is
+ managed separately. */
+#define DYNARRAY_STRUCT search_list
+#define DYNARRAY_ELEMENT const char *
+#define DYNARRAY_INITIAL_SIZE 4
+#define DYNARRAY_PREFIX search_list_
+#include <malloc/dynarray-skeleton.c>
+
+/* resolv.conf parser state and results. */
+struct resolv_conf_parser
+{
+ char *buffer; /* Temporary buffer for reading lines. */
+ char *search_list_store; /* Backing storage for search list entries. */
+ struct search_list search_list; /* Points into search_list_store. */
+};
+
+static void
+resolv_conf_parser_init (struct resolv_conf_parser *parser)
+{
+ parser->buffer = NULL;
+ parser->search_list_store = NULL;
+ search_list_init (&parser->search_list);
+}
+
+static void
+resolv_conf_parser_free (struct resolv_conf_parser *parser)
+{
+ free (parser->buffer);
+ free (parser->search_list_store);
+ search_list_free (&parser->search_list);
+}
+
+/* Try to obtain the domain name from the host name and store it in
+ *RESULT. Return false on memory allocation failure. If the domain
+ name cannot be determined for any other reason, write NULL to
+ *RESULT and return true. */
+static bool
+domain_from_hostname (char **result)
+{
+ char buf[256];
+ /* gethostbyname may not terminate the buffer. */
+ buf[sizeof (buf) - 1] = '\0';
+ if (__gethostname (buf, sizeof (buf) - 1) == 0)
+ {
+ char *dot = strchr (buf, '.');
+ if (dot != NULL)
+ {
+ *result = __strdup (dot + 1);
+ if (*result == NULL)
+ return false;
+ return true;
+ }
+ }
+ *result = NULL;
+ return true;
+}
+
/* Internal helper function for __res_vinit, to aid with resource
deallocation and error handling. Return true on success, false on
failure. */
static bool
-res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
+res_vinit_1 (res_state statp, bool preinit, FILE *fp,
+ struct resolv_conf_parser *parser)
{
- char *cp, **pp;
+ char *cp;
size_t buffer_size = 0;
int nserv = 0; /* Number of nameservers read from file. */
bool have_serv6 = false;
bool haveenv = false;
- bool havesearch = false;
int nsort = 0;
char *net;
@@ -162,39 +219,40 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
/* Allow user to override the local domain definition. */
if ((cp = getenv ("LOCALDOMAIN")) != NULL)
{
- strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
- statp->defdname[sizeof (statp->defdname) - 1] = '\0';
+ /* The code below splits the string in place. */
+ cp = __strdup (cp);
+ if (cp == NULL)
+ return false;
+ free (parser->search_list_store);
+ parser->search_list_store = cp;
haveenv = true;
+ /* The string will be truncated as needed below. */
+ search_list_add (&parser->search_list, cp);
+
/* Set search list to be blank-separated strings from rest of
env value. Permits users of LOCALDOMAIN to still have a
search list, and anyone to set the one that they want to use
as an individual (even more important now that the rfc1535
stuff restricts searches). */
- cp = statp->defdname;
- pp = statp->dnsrch;
- *pp++ = cp;
- for (int n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+ for (bool in_name = true; *cp != '\0'; cp++)
{
if (*cp == '\n')
- break;
+ {
+ *cp = '\0';
+ break;
+ }
else if (*cp == ' ' || *cp == '\t')
{
- *cp = 0;
- n = 1;
+ *cp = '\0';
+ in_name = false;
}
- else if (n > 0)
+ else if (!in_name)
{
- *pp++ = cp;
- n = 0;
- havesearch = true;
+ search_list_add (&parser->search_list, cp);
+ in_name = true;
}
}
- /* Null terminate last domain if there are excess. */
- while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
- cp++;
- *cp = '\0';
- *pp++ = 0;
}
#define MATCH(line, name) \
@@ -210,7 +268,7 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
while (true)
{
{
- ssize_t ret = __getline (buffer, &buffer_size, fp);
+ ssize_t ret = __getline (&parser->buffer, &buffer_size, fp);
if (ret <= 0)
{
if (_IO_ferror_unlocked (fp))
@@ -221,73 +279,82 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
}
/* Skip comments. */
- if (**buffer == ';' || **buffer == '#')
+ if (*parser->buffer == ';' || *parser->buffer == '#')
continue;
/* Read default domain name. */
- if (MATCH (*buffer, "domain"))
+ if (MATCH (parser->buffer, "domain"))
{
if (haveenv)
/* LOCALDOMAIN overrides the configuration file. */
continue;
- cp = *buffer + sizeof ("domain") - 1;
+ cp = parser->buffer + sizeof ("domain") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
- strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
- statp->defdname[sizeof (statp->defdname) - 1] = '\0';
- if ((cp = strpbrk (statp->defdname, " \t\n")) != NULL)
+
+ cp = __strdup (cp);
+ if (cp == NULL)
+ return false;
+ free (parser->search_list_store);
+ parser->search_list_store = cp;
+ search_list_clear (&parser->search_list);
+ search_list_add (&parser->search_list, cp);
+ /* Replace trailing whitespace. */
+ if ((cp = strpbrk (cp, " \t\n")) != NULL)
*cp = '\0';
- havesearch = false;
continue;
}
/* Set search list. */
- if (MATCH (*buffer, "search"))
+ if (MATCH (parser->buffer, "search"))
{
if (haveenv)
/* LOCALDOMAIN overrides the configuration file. */
continue;
- cp = *buffer + sizeof ("search") - 1;
+ cp = parser->buffer + sizeof ("search") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
- strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
- statp->defdname[sizeof (statp->defdname) - 1] = '\0';
- if ((cp = strchr (statp->defdname, '\n')) != NULL)
- *cp = '\0';
+
+ {
+ char *p = strchr (cp, '\n');
+ if (p != NULL)
+ *p = '\0';
+ }
+ cp = __strdup (cp);
+ if (cp == NULL)
+ return false;
+ free (parser->search_list_store);
+ parser->search_list_store = cp;
+
+ /* The string is truncated below. */
+ search_list_clear (&parser->search_list);
+ search_list_add (&parser->search_list, cp);
+
/* Set search list to be blank-separated strings on rest
of line. */
- cp = statp->defdname;
- pp = statp->dnsrch;
- *pp++ = cp;
- for (int n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+ for (bool in_name = true; *cp != '\0'; cp++)
{
if (*cp == ' ' || *cp == '\t')
{
- *cp = 0;
- n = 1;
+ *cp = '\0';
+ in_name = false;
}
- else if (n)
+ else if (!in_name)
{
- *pp++ = cp;
- n = 0;
+ search_list_add (&parser->search_list, cp);
+ in_name = true;
}
}
- /* Null terminate last domain if there are excess. */
- while (*cp != '\0' && *cp != ' ' && *cp != '\t')
- cp++;
- *cp = '\0';
- *pp++ = 0;
- havesearch = true;
continue;
}
/* Read nameservers to query. */
- if (MATCH (*buffer, "nameserver") && nserv < MAXNS)
+ if (MATCH (parser->buffer, "nameserver") && nserv < MAXNS)
{
struct in_addr a;
- cp = *buffer + sizeof ("nameserver") - 1;
+ cp = parser->buffer + sizeof ("nameserver") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
@@ -335,11 +402,11 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
}
continue;
}
- if (MATCH (*buffer, "sortlist"))
+ if (MATCH (parser->buffer, "sortlist"))
{
struct in_addr a;
- cp = *buffer + sizeof ("sortlist") - 1;
+ cp = parser->buffer + sizeof ("sortlist") - 1;
while (nsort < MAXRESOLVSORT)
{
while (*cp == ' ' || *cp == '\t')
@@ -379,9 +446,9 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
}
continue;
}
- if (MATCH (*buffer, "options"))
+ if (MATCH (parser->buffer, "options"))
{
- res_setoptions (statp, *buffer + sizeof ("options") - 1);
+ res_setoptions (statp, parser->buffer + sizeof ("options") - 1);
continue;
}
}
@@ -399,25 +466,29 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
statp->nsaddr.sin_port = htons (NAMESERVER_PORT);
statp->nscount = 1;
}
- if (statp->defdname[0] == 0)
- {
- char buf[sizeof (statp->defdname)];
- if (__gethostname (buf, sizeof (statp->defdname) - 1) == 0
- && (cp = strchr (buf, '.')) != NULL)
- strcpy (statp->defdname, cp + 1);
- }
- /* Find components of local domain that might be searched. */
- if (!havesearch)
+ if (search_list_size (&parser->search_list) == 0)
{
- pp = statp->dnsrch;
- *pp++ = statp->defdname;
- *pp = NULL;
-
+ char *domain;
+ if (!domain_from_hostname (&domain))
+ return false;
+ if (domain != NULL)
+ {
+ free (parser->search_list_store);
+ parser->search_list_store = domain;
+ search_list_add (&parser->search_list, domain);
+ }
}
if ((cp = getenv ("RES_OPTIONS")) != NULL)
res_setoptions (statp, cp);
+
+ if (search_list_has_failed (&parser->search_list))
+ {
+ __set_errno (ENOMEM);
+ return false;
+ }
+
statp->options |= RES_INIT;
return true;
}
@@ -453,13 +524,17 @@ __res_vinit (res_state statp, int preinit)
return -1;
}
- char *buffer = NULL;
- bool ok = res_vinit_1 (statp, preinit, fp, &buffer);
- free (buffer);
+ struct resolv_conf_parser parser;
+ resolv_conf_parser_init (&parser);
+ bool ok = res_vinit_1 (statp, preinit, fp, &parser);
if (ok)
{
- struct resolv_conf init = { 0 }; /* No data yet. */
+ struct resolv_conf init =
+ {
+ .search_list = search_list_begin (&parser.search_list),
+ .search_list_size = search_list_size (&parser.search_list),
+ };
struct resolv_conf *conf = __resolv_conf_allocate (&init);
if (conf == NULL)
ok = false;
@@ -469,6 +544,7 @@ __res_vinit (res_state statp, int preinit)
__resolv_conf_put (conf);
}
}
+ resolv_conf_parser_free (&parser);
if (!ok)
{
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 33249e36f51bcf9a..ebbe5a6a4ed86abe 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -326,7 +326,7 @@ __res_context_search (struct resolv_context *ctx,
int *nanswerp2, int *resplen2, int *answerp2_malloced)
{
struct __res_state *statp = ctx->resp;
- const char *cp, * const *domain;
+ const char *cp;
HEADER *hp = (HEADER *) answer;
char tmp[NS_MAXDNAME];
u_int dots;
@@ -392,10 +392,11 @@ __res_context_search (struct resolv_context *ctx,
(dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
int done = 0;
- for (domain = (const char * const *)statp->dnsrch;
- *domain && !done;
- domain++) {
- const char *dname = domain[0];
+ for (size_t domain_index = 0; !done; ++domain_index) {
+ const char *dname = __resolv_context_search_list
+ (ctx, domain_index);
+ if (dname == NULL)
+ break;
searched = 1;
/* __res_context_querydoman concatenates name
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index cabe69cf1ba3f4d5..76d55fc32c8f0662 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -133,6 +133,34 @@ static bool
resolv_conf_matches (const struct __res_state *resp,
const struct resolv_conf *conf)
{
+ /* Check that the search list in *RESP has not been modified by the
+ application. */
+ {
+ if (!(resp->dnsrch[0] == resp->defdname
+ && resp->dnsrch[MAXDNSRCH] == NULL))
+ return false;
+ size_t search_list_size = 0;
+ for (size_t i = 0; i < conf->search_list_size; ++i)
+ {
+ if (resp->dnsrch[i] != NULL)
+ {
+ search_list_size += strlen (resp->dnsrch[i]) + 1;
+ if (strcmp (resp->dnsrch[i], conf->search_list[i]) != 0)
+ return false;
+ }
+ else
+ {
+ /* resp->dnsrch is truncated if the number of elements
+ exceeds MAXDNSRCH, or if the combined storage space for
+ the search list exceeds what can be stored in
+ resp->defdname. */
+ if (i == MAXDNSRCH || search_list_size > sizeof (resp->dnsrch))
+ break;
+ /* Otherwise, a mismatch indicates a match failure. */
+ return false;
+ }
+ }
+ }
return true;
}
@@ -162,10 +190,17 @@ __resolv_conf_put (struct resolv_conf *conf)
struct resolv_conf *
__resolv_conf_allocate (const struct resolv_conf *init)
{
+ /* Space needed by the strings. */
+ size_t string_space = 0;
+ for (size_t i = 0; i < init->search_list_size; ++i)
+ string_space += strlen (init->search_list[i]) + 1;
+
/* Allocate the buffer. */
void *ptr;
struct alloc_buffer buffer = alloc_buffer_allocate
- (sizeof (struct resolv_conf),
+ (sizeof (struct resolv_conf)
+ + init->search_list_size * sizeof (init->search_list[0])
+ + string_space,
&ptr);
struct resolv_conf *conf
= alloc_buffer_alloc (&buffer, struct resolv_conf);
@@ -178,6 +213,16 @@ __resolv_conf_allocate (const struct resolv_conf *init)
conf->__refcount = 1;
conf->initstamp = __res_initstamp;
+ /* Allocate and fill the search list array. */
+ {
+ conf->search_list_size = init->search_list_size;
+ const char **array = alloc_buffer_alloc_array
+ (&buffer, const char *, init->search_list_size);
+ conf->search_list = array;
+ for (size_t i = 0; i < init->search_list_size; ++i)
+ array[i] = alloc_buffer_copy_string (&buffer, init->search_list[i]);
+ }
+
assert (!alloc_buffer_has_failed (&buffer));
return conf;
}
@@ -186,6 +231,24 @@ __resolv_conf_allocate (const struct resolv_conf *init)
static __attribute__ ((nonnull (1, 2), warn_unused_result)) bool
update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
{
+ /* Fill in the prefix of the search list. It is truncated either at
+ MAXDNSRCH, or if reps->defdname has insufficient space. */
+ {
+ struct alloc_buffer buffer
+ = alloc_buffer_create (resp->defdname, sizeof (resp->defdname));
+ size_t size = conf->search_list_size;
+ size_t i;
+ for (i = 0; i < size && i < MAXDNSRCH; ++i)
+ {
+ resp->dnsrch[i] = alloc_buffer_copy_string
+ (&buffer, conf->search_list[i]);
+ if (resp->dnsrch[i] == NULL)
+ /* No more space in resp->defdname. Truncate. */
+ break;
+ }
+ resp->dnsrch[i] = NULL;
+ }
+
/* The overlapping parts of both configurations should agree after
initialization. */
assert (resolv_conf_matches (resp, conf));
diff --git a/resolv/resolv_conf.h b/resolv/resolv_conf.h
index 48f92d6d5753aef1..80a0b93f94588e89 100644
--- a/resolv/resolv_conf.h
+++ b/resolv/resolv_conf.h
@@ -35,6 +35,10 @@ struct resolv_conf
/* Reference counter. The object is deallocated once it reaches
zero. For internal use within resolv_conf only. */
size_t __refcount;
+
+ /* The domain names forming the search list. */
+ const char *const *search_list;
+ size_t search_list_size;
};
/* The functions below are for use by the res_init resolv.conf parser
diff --git a/resolv/resolv_context.h b/resolv/resolv_context.h
index ff9ef2c7fe6101f3..0f4d47d26dd513f4 100644
--- a/resolv/resolv_context.h
+++ b/resolv/resolv_context.h
@@ -93,6 +93,25 @@ struct resolv_context *__resolv_context_get_override (struct __res_state *)
__attribute__ ((nonnull (1), warn_unused_result));
libc_hidden_proto (__resolv_context_get_override)
+/* Return the search path entry at INDEX, or NULL if there are fewer
+ than INDEX entries. */
+static __attribute__ ((nonnull (1), unused)) const char *
+__resolv_context_search_list (const struct resolv_context *ctx, size_t index)
+{
+ if (ctx->conf != NULL)
+ {
+ if (index < ctx->conf->search_list_size)
+ return ctx->conf->search_list[index];
+ else
+ return NULL;
+ }
+ /* Fallback. ctx->resp->dnsrch is a NULL-terminated array. */
+ for (size_t i = 0; ctx->resp->dnsrch[i] != NULL && i < MAXDNSRCH; ++i)
+ if (i == index)
+ return ctx->resp->dnsrch[i];
+ return NULL;
+}
+
/* Called during thread shutdown to free the associated resolver
context (mostly in response to cancellation, otherwise the
__resolv_context_get/__resolv_context_put pairing will already have
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index ce206f52c4c27c32..cea14569b89cb51f 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -25,6 +25,7 @@
#include <gnu/lib-names.h>
#include <netdb.h>
#include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6. */
+#include <resolv/resolv_context.h>
#include <stdio.h>
#include <stdlib.h>
#include <support/capture_subprocess.h>
@@ -116,6 +117,11 @@ print_option_flag (FILE *fp, int *options, int flag, const char *name)
static void
print_resp (FILE *fp, res_state resp)
{
+ struct resolv_context *ctx = __resolv_context_get_override (resp);
+ TEST_VERIFY_EXIT (ctx != NULL);
+ if (ctx->conf == NULL)
+ fprintf (fp, "; extended resolver state missing\n");
+
/* The options directive. */
{
/* RES_INIT is used internally for tracking initialization. */
@@ -165,6 +171,19 @@ print_resp (FILE *fp, res_state resp)
else if (resp->defdname[0] != '\0')
fprintf (fp, "domain %s\n", resp->defdname);
+ /* The extended search path. */
+ {
+ size_t i = 0;
+ while (true)
+ {
+ const char *name = __resolv_context_search_list (ctx, i);
+ if (name == NULL)
+ break;
+ fprintf (fp, "; search[%zu]: %s\n", i, name);
+ ++i;
+ }
+ }
+
/* The sortlist directive. */
if (resp->nsort > 0)
{
@@ -224,6 +243,8 @@ print_resp (FILE *fp, res_state resp)
}
TEST_VERIFY (!ferror (fp));
+
+ __resolv_context_put (ctx);
}
/* Parameters of one test case. */
@@ -368,11 +389,13 @@ struct test_case test_cases[] =
{.name = "empty file",
.conf = "",
.expected = "search example.com\n"
+ "; search[0]: example.com\n"
"nameserver 127.0.0.1\n"
},
{.name = "empty file with LOCALDOMAIN",
.conf = "",
.expected = "search example.net\n"
+ "; search[0]: example.net\n"
"nameserver 127.0.0.1\n",
.localdomain = "example.net",
},
@@ -380,6 +403,7 @@ struct test_case test_cases[] =
.conf = "",
.expected = "options attempts:5 edns0\n"
"search example.com\n"
+ "; search[0]: example.com\n"
"nameserver 127.0.0.1\n",
.res_options = "edns0 attempts:5",
},
@@ -387,6 +411,7 @@ struct test_case test_cases[] =
.conf = "",
.expected = "options attempts:5 edns0\n"
"search example.org\n"
+ "; search[0]: example.org\n"
"nameserver 127.0.0.1\n",
.localdomain = "example.org",
.res_options = "edns0 attempts:5",
@@ -396,6 +421,8 @@ struct test_case test_cases[] =
"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"
},
{.name = "whitespace",
@@ -403,16 +430,46 @@ struct test_case test_cases[] =
" (trailing whitespace,\n"
"# missing newline at end of file).\n"
"\n"
- "domain example.net\n"
";search commented out\n"
- "search corp.example.com\texample.com\n"
+ "search corp.example.com\texample.com \n"
"#nameserver 192.0.2.3\n"
"nameserver 192.0.2.1 \n"
"nameserver 192.0.2.2", /* No \n at end of file. */
.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 192.0.2.2\n"
},
+ {.name = "domain",
+ .conf = "domain example.net\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ },
+ {.name = "domain space",
+ .conf = "domain example.net \n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ },
+ {.name = "domain tab",
+ .conf = "domain example.net\t\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ },
+ {.name = "domain override",
+ .conf = "search example.com example.org\n"
+ "nameserver 192.0.2.1\n"
+ "domain example.net", /* No \n at end of file. */
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ },
{.name = "option values, multiple servers",
.conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
"domain example.net\n"
@@ -423,6 +480,8 @@ struct test_case test_cases[] =
"nameserver 192.0.2.2\n",
.expected = "options ndots:3 timeout:19 attempts:5 inet6 edns0\n"
"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 ::1\n"
"nameserver 192.0.2.2\n"
@@ -432,6 +491,7 @@ struct test_case test_cases[] =
"search example.com\n",
.expected = "options ndots:15 timeout:30 attempts:5 use-vc\n"
"search example.com\n"
+ "; search[0]: example.com\n"
"nameserver 127.0.0.1\n"
},
{.name = "repeated directives",
@@ -443,6 +503,7 @@ struct test_case test_cases[] =
"search\n",
.expected = "options ndots:2 use-vc edns0\n"
"search example.org\n"
+ "; search[0]: example.org\n"
"nameserver 127.0.0.1\n"
},
{.name = "many name servers, sortlist",
@@ -459,6 +520,10 @@ struct test_case test_cases[] =
"nameserver 192.0.2.8\n",
.expected = "options single-request\n"
"search example.org example.com example.net corp.example.com\n"
+ "; search[0]: example.org\n"
+ "; search[1]: example.com\n"
+ "; search[2]: example.net\n"
+ "; search[3]: corp.example.com\n"
"sortlist 192.0.2.0/255.255.255.0\n"
"nameserver 192.0.2.1\n"
"nameserver 192.0.2.2\n"
@@ -480,6 +545,11 @@ struct test_case test_cases[] =
.expected = "options single-request\n"
"search example.org example.com example.net corp.example.com"
" legacy.example.com\n"
+ "; search[0]: example.org\n"
+ "; search[1]: example.com\n"
+ "; search[2]: example.net\n"
+ "; search[3]: corp.example.com\n"
+ "; search[4]: legacy.example.com\n"
"sortlist 192.0.2.0/255.255.255.0\n"
"nameserver 192.0.2.1\n"
"nameserver 2001:db8::2\n"
@@ -490,6 +560,7 @@ struct test_case test_cases[] =
"nameserver 192.0.2.2:5353\n"
"nameserver 192.0.2.3 5353\n",
.expected = "search example.com\n"
+ "; search[0]: example.com\n"
"nameserver 192.0.2.1\n"
"nameserver 192.0.2.3\n"
},
@@ -498,9 +569,42 @@ struct test_case test_cases[] =
"nameserver 192.0.2.1\n",
.expected = "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
"search example.com\n"
+ "; search[0]: example.com\n"
"nameserver 192.0.2.1\n",
.res_options = "attempts:5 ndots:3 edns0 ",
},
+ {.name = "many search list entries (bug 19569)",
+ .conf = "nameserver 192.0.2.1\n"
+ "search corp.example.com support.example.com"
+ " community.example.org wan.example.net vpn.example.net"
+ " example.com example.org example.net\n",
+ .expected = "search corp.example.com support.example.com"
+ " community.example.org wan.example.net vpn.example.net example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: support.example.com\n"
+ "; search[2]: community.example.org\n"
+ "; search[3]: wan.example.net\n"
+ "; search[4]: vpn.example.net\n"
+ "; search[5]: example.com\n"
+ "; search[6]: example.org\n"
+ "; search[7]: example.net\n"
+ "nameserver 192.0.2.1\n",
+ },
+ {.name = "very long search list entries (bug 21475)",
+ .conf = "nameserver 192.0.2.1\n"
+ "search example.com "
+#define H63 "this-host-name-is-longer-than-yours-yes-I-really-really-mean-it"
+#define D63 "this-domain-name-is-as-long-as-the-previous-name--63-characters"
+ " " H63 "." D63 ".example.org"
+ " " H63 "." D63 ".example.net\n",
+ .expected = "search example.com " H63 "." D63 ".example.org\n"
+ "; search[0]: example.com\n"
+ "; search[1]: " H63 "." D63 ".example.org\n"
+ "; search[2]: " H63 "." D63 ".example.net\n"
+#undef H63
+#undef D63
+ "nameserver 192.0.2.1\n",
+ },
{ NULL }
};

View File

@ -0,0 +1,130 @@
commit 2f83a7294d0d0904d72839843a80531769525d59
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Apr 19 07:45:04 2017 +0200
Create more sockets with SOCK_CLOEXEC [BZ #15722]
diff --git a/inet/rcmd.c b/inet/rcmd.c
index 8613d96764b08cc8..f6c9ec54acfc800f 100644
--- a/inet/rcmd.c
+++ b/inet/rcmd.c
@@ -383,6 +383,7 @@ rresvport_af (int *alport, sa_family_t family)
__set_errno (EAFNOSUPPORT);
return -1;
}
+ /* NB: No SOCK_CLOXEC for backwards compatibility. */
s = __socket(family, SOCK_STREAM, 0);
if (s < 0)
return -1;
diff --git a/inet/rexec.c b/inet/rexec.c
index 24ac4b11b6d745aa..96ebf3d59a5d97ac 100644
--- a/inet/rexec.c
+++ b/inet/rexec.c
@@ -86,6 +86,7 @@ rexec_af (char **ahost, int rport, const char *name, const char *pass,
}
ruserpass(res0->ai_canonname, &name, &pass);
retry:
+ /* NB: No SOCK_CLOXEC for backwards compatibility. */
s = __socket(res0->ai_family, res0->ai_socktype, 0);
if (s < 0) {
perror("rexec: socket");
diff --git a/nis/nis_findserv.c b/nis/nis_findserv.c
index 77f3c7c3cea14fbc..8e01164e3db9252e 100644
--- a/nis/nis_findserv.c
+++ b/nis/nis_findserv.c
@@ -142,7 +142,7 @@ __nis_findfastest_with_timeout (dir_binding *bind,
}
/* Create RPC handle */
- sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ sock = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
clnt = clntudp_create (&saved_sin, NIS_PROG, NIS_VERSION, *timeout, &sock);
if (clnt == NULL)
{
diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c
index d0d116d308b31b40..8fc06e9abdc084f6 100644
--- a/resolv/res_hconf.c
+++ b/resolv/res_hconf.c
@@ -388,7 +388,7 @@ _res_hconf_reorder_addrs (struct hostent *hp)
/* Initialize interface table. */
/* The SIOCGIFNETMASK ioctl will only work on an AF_INET socket. */
- sd = __socket (AF_INET, SOCK_DGRAM, 0);
+ sd = __socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sd < 0)
return;
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 98968d6239d0c8f7..440da90a0b381b84 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -692,7 +692,8 @@ send_vc(res_state statp,
if (statp->_vcsock >= 0)
__res_iclose(statp, false);
- statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+ statp->_vcsock = socket
+ (nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (statp->_vcsock < 0) {
*terrno = errno;
Perror(statp, stderr, "socket(vc)", errno);
@@ -902,14 +903,16 @@ reopen (res_state statp, int *terrno, int ns)
/* only try IPv6 if IPv6 NS and if not failed before */
if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) {
- EXT(statp).nssocks[ns]
- = socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK, 0);
+ EXT(statp).nssocks[ns] = socket
+ (PF_INET6,
+ SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (EXT(statp).nssocks[ns] < 0)
statp->ipv6_unavail = errno == EAFNOSUPPORT;
slen = sizeof (struct sockaddr_in6);
} else if (nsap->sa_family == AF_INET) {
- EXT(statp).nssocks[ns]
- = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, 0);
+ EXT(statp).nssocks[ns] = socket
+ (PF_INET,
+ SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
slen = sizeof (struct sockaddr_in);
}
if (EXT(statp).nssocks[ns] < 0) {
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 43eb31365ed10059..1ea2b2218d263b28 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -2472,7 +2472,7 @@ getaddrinfo (const char *name, const char *service,
close_retry:
close_not_cancel_no_status (fd);
af = q->ai_family;
- fd = __socket (af, SOCK_DGRAM, IPPROTO_IP);
+ fd = __socket (af, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP);
}
else
{
diff --git a/sysdeps/unix/sysv/linux/check_native.c b/sysdeps/unix/sysv/linux/check_native.c
index 4a1646089ffb7f1e..7e5a7c9be30c05e7 100644
--- a/sysdeps/unix/sysv/linux/check_native.c
+++ b/sysdeps/unix/sysv/linux/check_native.c
@@ -41,7 +41,7 @@ void
__check_native (uint32_t a1_index, int *a1_native,
uint32_t a2_index, int *a2_native)
{
- int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ int fd = __socket (PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
struct sockaddr_nl nladdr;
memset (&nladdr, '\0', sizeof (nladdr));
diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c
index cff12c2ac4517741..3bc99028639c7149 100644
--- a/sysdeps/unix/sysv/linux/ifaddrs.c
+++ b/sysdeps/unix/sysv/linux/ifaddrs.c
@@ -255,7 +255,7 @@ __netlink_open (struct netlink_handle *h)
{
struct sockaddr_nl nladdr;
- h->fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ h->fd = __socket (PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (h->fd < 0)
goto out;

View File

@ -0,0 +1,637 @@
commit f30a54b21b83f254533c59ca72ad17af5249c6be
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jul 3 20:31:23 2017 +0200
resolv: Introduce struct resolv_conf with extended resolver state
This change provides additional resolver configuration state which
is not exposed through the _res ABI. It reuses the existing
initstamp field in the supposedly-private part of _res. Some effort
is undertaken to avoid memory safety issues introduced by applications
which directly patch the _res object.
With this commit, only the initstamp field is moved into struct
resolv_conf. Additional members will be added later, eventually
migrating the entire resolver configuration.
diff --git a/resolv/Makefile b/resolv/Makefile
index 7f5e07d618297f60..ef5ed2966e4d6c51 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -29,7 +29,7 @@ headers := resolv.h \
routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
res_hconf res_libc res-state res_randomid res-close \
- resolv_context
+ resolv_context resolv_conf
tests = tst-aton tst-leaks tst-inet_ntop
xtests = tst-leaks2
diff --git a/resolv/res-close.c b/resolv/res-close.c
index 97da73c99cfd0e12..21f038c2c77f7375 100644
--- a/resolv/res-close.c
+++ b/resolv/res-close.c
@@ -84,6 +84,7 @@
#include <resolv-internal.h>
#include <resolv_context.h>
+#include <resolv_conf.h>
#include <not-cancel.h>
/* Close all open sockets. If FREE_ADDR is true, deallocate any
@@ -111,6 +112,8 @@ __res_iclose (res_state statp, bool free_addr)
statp->_u._ext.nsaddrs[ns] = NULL;
}
}
+ if (free_addr)
+ __resolv_conf_detach (statp);
}
libc_hidden_def (__res_iclose)
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 5d8b2c994d8e6f04..659d3ea81f973257 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -102,6 +102,7 @@
#include <sys/types.h>
#include <inet/net-internal.h>
#include <errno.h>
+#include <resolv_conf.h>
static void res_setoptions (res_state, const char *);
static uint32_t net_mask (struct in_addr);
@@ -137,7 +138,6 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
bool havesearch = false;
int nsort = 0;
char *net;
- statp->_u._ext.initstamp = __res_initstamp;
if (!preinit)
{
@@ -457,6 +457,19 @@ __res_vinit (res_state statp, int preinit)
bool ok = res_vinit_1 (statp, preinit, fp, &buffer);
free (buffer);
+ if (ok)
+ {
+ struct resolv_conf init = { 0 }; /* No data yet. */
+ struct resolv_conf *conf = __resolv_conf_allocate (&init);
+ if (conf == NULL)
+ ok = false;
+ else
+ {
+ ok = __resolv_conf_attach (statp, conf);
+ __resolv_conf_put (conf);
+ }
+ }
+
if (!ok)
{
/* Deallocate the name server addresses which have been
diff --git a/resolv/resolv.h b/resolv/resolv.h
index 9fef8e9f248c84e6..b83232cca8e8f0c3 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -122,10 +122,10 @@ struct __res_state {
uint16_t nsinit;
struct sockaddr_in6 *nsaddrs[MAXNS];
#ifdef _LIBC
- unsigned long long int initstamp
+ unsigned long long int __glibc_extension_index
__attribute__((packed));
#else
- unsigned int _initstamp[2];
+ unsigned int __glibc_reserved[2];
#endif
} _ext;
} _u;
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
new file mode 100644
index 0000000000000000..cabe69cf1ba3f4d5
--- /dev/null
+++ b/resolv/resolv_conf.c
@@ -0,0 +1,322 @@
+/* Extended resolver state separate from struct __res_state.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <resolv_conf.h>
+
+#include <alloc_buffer.h>
+#include <assert.h>
+#include <libc-lock.h>
+#include <resolv-internal.h>
+
+/* _res._u._ext.__glibc_extension_index is used as an index into a
+ struct resolv_conf_array object. The intent of this construction
+ is to make reasonably sure that even if struct __res_state objects
+ are copied around and patched by applications, we can still detect
+ accesses to stale extended resolver state. */
+#define DYNARRAY_STRUCT resolv_conf_array
+#define DYNARRAY_ELEMENT struct resolv_conf *
+#define DYNARRAY_PREFIX resolv_conf_array_
+#define DYNARRAY_INITIAL_SIZE 0
+#include <malloc/dynarray-skeleton.c>
+
+/* A magic constant for XORing the extension index
+ (_res._u._ext.__glibc_extension_index). This makes it less likely
+ that a valid index is created by accident. In particular, a zero
+ value leads to an invalid index. */
+#define INDEX_MAGIC 0x26a8fa5e48af8061ULL
+
+/* Global resolv.conf-related state. */
+struct resolv_conf_global
+{
+ /* struct __res_state objects contain the extension index
+ (_res._u._ext.__glibc_extension_index ^ INDEX_MAGIC), which
+ refers to an element of this array. When a struct resolv_conf
+ object (extended resolver state) is associated with a struct
+ __res_state object (legacy resolver state), its reference count
+ is increased and added to this array. Conversely, if the
+ extended state is detached from the basic state (during
+ reinitialization or deallocation), the index is decremented, and
+ the array element is overwritten with NULL. */
+ struct resolv_conf_array array;
+
+};
+
+/* Lazily allocated storage for struct resolv_conf_global. */
+static struct resolv_conf_global *global;
+
+/* The lock synchronizes access to global and *global. It also
+ protects the __refcount member of struct resolv_conf. */
+__libc_lock_define_initialized (static, lock);
+
+/* Ensure that GLOBAL is allocated and lock it. Return NULL if
+ memory allocation failes. */
+static struct resolv_conf_global *
+get_locked_global (void)
+{
+ __libc_lock_lock (lock);
+ /* Use relaxed MO through because of load outside the lock in
+ __resolv_conf_detach. */
+ struct resolv_conf_global *global_copy = atomic_load_relaxed (&global);
+ if (global_copy == NULL)
+ {
+ global_copy = calloc (1, sizeof (*global));
+ if (global_copy == NULL)
+ return NULL;
+ atomic_store_relaxed (&global, global_copy);
+ resolv_conf_array_init (&global_copy->array);
+ }
+ return global_copy;
+}
+
+/* Relinquish the lock acquired by get_locked_global. */
+static void
+put_locked_global (struct resolv_conf_global *global_copy)
+{
+ __libc_lock_unlock (lock);
+}
+
+/* Decrement the reference counter. The caller must acquire the lock
+ around the function call. */
+static void
+conf_decrement (struct resolv_conf *conf)
+{
+ assert (conf->__refcount > 0);
+ if (--conf->__refcount == 0)
+ free (conf);
+}
+
+/* Internal implementation of __resolv_conf_get, without validation
+ against *RESP. */
+static struct resolv_conf *
+resolv_conf_get_1 (const struct __res_state *resp)
+{
+ /* Not initialized, and therefore no assoicated context. */
+ if (!(resp->options & RES_INIT))
+ return NULL;
+
+ struct resolv_conf_global *global_copy = get_locked_global ();
+ if (global_copy == NULL)
+ /* A memory allocation failure here means that no associated
+ contexts exists, so returning NULL is correct. */
+ return NULL;
+ size_t index = resp->_u._ext.__glibc_extension_index ^ INDEX_MAGIC;
+ struct resolv_conf *conf;
+ if (index < resolv_conf_array_size (&global_copy->array))
+ {
+ conf = *resolv_conf_array_at (&global_copy->array, index);
+ assert (conf->__refcount > 0);
+ ++conf->__refcount;
+ }
+ else
+ conf = NULL;
+ put_locked_global (global_copy);
+ return conf;
+}
+
+/* Check that *RESP and CONF match. Used by __resolv_conf_get. */
+static bool
+resolv_conf_matches (const struct __res_state *resp,
+ const struct resolv_conf *conf)
+{
+ return true;
+}
+
+struct resolv_conf *
+__resolv_conf_get (struct __res_state *resp)
+{
+ struct resolv_conf *conf = resolv_conf_get_1 (resp);
+ if (conf == NULL)
+ return NULL;
+ if (resolv_conf_matches (resp, conf))
+ return conf;
+ __resolv_conf_put (conf);
+ return NULL;
+}
+
+void
+__resolv_conf_put (struct resolv_conf *conf)
+{
+ if (conf == NULL)
+ return;
+
+ __libc_lock_lock (lock);
+ conf_decrement (conf);
+ __libc_lock_unlock (lock);
+}
+
+struct resolv_conf *
+__resolv_conf_allocate (const struct resolv_conf *init)
+{
+ /* Allocate the buffer. */
+ void *ptr;
+ struct alloc_buffer buffer = alloc_buffer_allocate
+ (sizeof (struct resolv_conf),
+ &ptr);
+ struct resolv_conf *conf
+ = alloc_buffer_alloc (&buffer, struct resolv_conf);
+ if (conf == NULL)
+ /* Memory allocation failure. */
+ return NULL;
+ assert (conf == ptr);
+
+ /* Initialize the contents. */
+ conf->__refcount = 1;
+ conf->initstamp = __res_initstamp;
+
+ assert (!alloc_buffer_has_failed (&buffer));
+ return conf;
+}
+
+/* Update *RESP from the extended state. */
+static __attribute__ ((nonnull (1, 2), warn_unused_result)) bool
+update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
+{
+ /* The overlapping parts of both configurations should agree after
+ initialization. */
+ assert (resolv_conf_matches (resp, conf));
+ return true;
+}
+
+/* Decrement the configuration object at INDEX and free it if the
+ reference counter reaches 0. *GLOBAL_COPY must be locked and
+ remains so. */
+static void
+decrement_at_index (struct resolv_conf_global *global_copy, size_t index)
+{
+ if (index < resolv_conf_array_size (&global_copy->array))
+ {
+ /* Index found. Deallocate the struct resolv_conf object once
+ the reference counter reaches. Free the array slot. */
+ struct resolv_conf **slot
+ = resolv_conf_array_at (&global_copy->array, index);
+ struct resolv_conf *conf = *slot;
+ if (conf != NULL)
+ {
+ conf_decrement (conf);
+ /* Clear the slot even if the reference count is positive.
+ Slots are not shared. */
+ *slot = NULL;
+ }
+ }
+}
+
+bool
+__resolv_conf_attach (struct __res_state *resp, struct resolv_conf *conf)
+{
+ assert (conf->__refcount > 0);
+
+ struct resolv_conf_global *global_copy = get_locked_global ();
+ if (global_copy == NULL)
+ {
+ free (conf);
+ return false;
+ }
+
+ /* Try to find an unused index in the array. */
+ size_t index;
+ {
+ size_t size = resolv_conf_array_size (&global_copy->array);
+ bool found = false;
+ for (index = 0; index < size; ++index)
+ {
+ struct resolv_conf **p
+ = resolv_conf_array_at (&global_copy->array, index);
+ if (*p == NULL)
+ {
+ *p = conf;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ /* No usable index found. Increase the array size. */
+ resolv_conf_array_add (&global_copy->array, conf);
+ if (resolv_conf_array_has_failed (&global_copy->array))
+ {
+ put_locked_global (global_copy);
+ __set_errno (ENOMEM);
+ return false;
+ }
+ /* The new array element was added at the end. */
+ index = size;
+ }
+ }
+
+ /* We have added a new reference to the object. */
+ ++conf->__refcount;
+ assert (conf->__refcount > 0);
+ put_locked_global (global_copy);
+
+ if (!update_from_conf (resp, conf))
+ {
+ /* Drop the reference we acquired. Reacquire the lock. The
+ object has already been allocated, so it cannot be NULL this
+ time. */
+ global_copy = get_locked_global ();
+ decrement_at_index (global_copy, index);
+ put_locked_global (global_copy);
+ return false;
+ }
+ resp->_u._ext.__glibc_extension_index = index ^ INDEX_MAGIC;
+
+ return true;
+}
+
+void
+__resolv_conf_detach (struct __res_state *resp)
+{
+ if (atomic_load_relaxed (&global) == NULL)
+ /* Detach operation after a shutdown, or without any prior
+ attachment. We cannot free the data (and there might not be
+ anything to free anyway). */
+ return;
+
+ struct resolv_conf_global *global_copy = get_locked_global ();
+ size_t index = resp->_u._ext.__glibc_extension_index ^ INDEX_MAGIC;
+ decrement_at_index (global_copy, index);
+
+ /* Clear the index field, so that accidental reuse is less
+ likely. */
+ resp->_u._ext.__glibc_extension_index = 0;
+
+ put_locked_global (global_copy);
+}
+
+/* Deallocate the global data. */
+static void __attribute__ ((section ("__libc_thread_freeres_fn")))
+freeres (void)
+{
+ /* No locking because this function is supposed to be called when
+ the process has turned single-threaded. */
+ if (global == NULL)
+ return;
+
+ /* Note that this frees only the array itself. The pointed-to
+ configuration objects should have been deallocated by res_nclose
+ and per-thread cleanup functions. */
+ resolv_conf_array_free (&global->array);
+
+ free (global);
+
+ /* Stop potential future __resolv_conf_detach calls from accessing
+ deallocated memory. */
+ global = NULL;
+}
+text_set_element (__libc_subfreeres, freeres);
diff --git a/resolv/resolv_conf.h b/resolv/resolv_conf.h
new file mode 100644
index 0000000000000000..48f92d6d5753aef1
--- /dev/null
+++ b/resolv/resolv_conf.h
@@ -0,0 +1,69 @@
+/* Extended resolver state separate from struct __res_state.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef RESOLV_STATE_H
+#define RESOLV_STATE_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/* Extended resolver state associated with res_state objects. Client
+ code can reach this state through a struct resolv_context
+ object. */
+struct resolv_conf
+{
+ /* Used to propagate the effect of res_init across threads. This
+ member is mutable and prevents sharing of the same struct
+ resolv_conf object among multiple struct __res_state objects. */
+ unsigned long long int initstamp;
+
+ /* Reference counter. The object is deallocated once it reaches
+ zero. For internal use within resolv_conf only. */
+ size_t __refcount;
+};
+
+/* The functions below are for use by the res_init resolv.conf parser
+ and the struct resolv_context facility. */
+
+struct __res_state;
+
+/* Return the extended resolver state for *RESP, or NULL if it cannot
+ be determined. A call to this function must be paired with a call
+ to __resolv_conf_put. */
+struct resolv_conf *__resolv_conf_get (struct __res_state *) attribute_hidden;
+
+/* Converse of __resolv_conf_get. */
+void __resolv_conf_put (struct resolv_conf *) attribute_hidden;
+
+/* Allocate a new struct resolv_conf object and copy the
+ pre-configured values from *INIT. Return NULL on allocation
+ failure. The object must be deallocated using
+ __resolv_conf_put. */
+struct resolv_conf *__resolv_conf_allocate (const struct resolv_conf *init)
+ attribute_hidden __attribute__ ((nonnull (1), warn_unused_result));
+
+/* Associate an existing extended resolver state with *RESP. Return
+ false on allocation failure. In addition, update *RESP with the
+ overlapping non-extended resolver state. */
+bool __resolv_conf_attach (struct __res_state *, struct resolv_conf *)
+ attribute_hidden;
+
+/* Detach the extended resolver state from *RESP. */
+void __resolv_conf_detach (struct __res_state *resp) attribute_hidden;
+
+#endif /* RESOLV_STATE_H */
diff --git a/resolv/resolv_context.c b/resolv/resolv_context.c
index 5083a40419bc463c..0ee2184055911d02 100644
--- a/resolv/resolv_context.c
+++ b/resolv/resolv_context.c
@@ -17,9 +17,11 @@
<http://www.gnu.org/licenses/>. */
#include <resolv_context.h>
+#include <resolv_conf.h>
#include <resolv-internal.h>
#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
@@ -52,19 +54,37 @@ static __thread struct resolv_context *current attribute_tls_model_ie;
/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
res_init in some other thread requested re-initializing. */
static __attribute__ ((warn_unused_result)) bool
-maybe_init (struct __res_state *resp, bool preinit)
+maybe_init (struct resolv_context *ctx, bool preinit)
{
+ struct __res_state *resp = ctx->resp;
if (resp->options & RES_INIT)
{
- if (__res_initstamp != resp->_u._ext.initstamp)
+ /* If there is no associated resolv_conf object despite the
+ initialization, something modified *ctx->resp. Do not
+ override those changes. */
+ if (ctx->conf != NULL && ctx->conf->initstamp != __res_initstamp)
{
if (resp->nscount > 0)
+ /* This call will detach the extended resolver state. */
__res_iclose (resp, true);
- return __res_vinit (resp, 1) == 0;
+ /* And this call will attach it again. */
+ if (__res_vinit (resp, 1) < 0)
+ {
+ /* The configuration no longer matches after failed
+ initialization. */
+ __resolv_conf_put (ctx->conf);
+ ctx->conf = NULL;
+ return false;
+ }
+ /* Delay the release of the old configuration until this
+ point, so that __res_vinit can reuse it if possible. */
+ __resolv_conf_put (ctx->conf);
+ ctx->conf = __resolv_conf_get (ctx->resp);
}
return true;
}
+ assert (ctx->conf == NULL);
if (preinit)
{
if (!resp->retrans)
@@ -75,7 +95,11 @@ maybe_init (struct __res_state *resp, bool preinit)
if (!resp->id)
resp->id = res_randomid ();
}
- return __res_vinit (resp, preinit) == 0;
+
+ if (__res_vinit (resp, preinit) < 0)
+ return false;
+ ctx->conf = __resolv_conf_get (ctx->resp);
+ return true;
}
/* Allocate a new context object and initialize it. The object is put
@@ -87,6 +111,7 @@ context_alloc (struct __res_state *resp)
if (ctx == NULL)
return NULL;
ctx->resp = resp;
+ ctx->conf = __resolv_conf_get (resp);
ctx->__refcount = 1;
ctx->__from_res = true;
ctx->__next = current;
@@ -98,8 +123,11 @@ context_alloc (struct __res_state *resp)
static void
context_free (struct resolv_context *ctx)
{
+ int error_code = errno;
current = ctx->__next;
+ __resolv_conf_put (ctx->conf);
free (ctx);
+ __set_errno (error_code);
}
/* Reuse the current context object. */
@@ -130,7 +158,7 @@ context_get (bool preinit)
struct resolv_context *ctx = context_alloc (&_res);
if (ctx == NULL)
return NULL;
- if (!maybe_init (ctx->resp, preinit))
+ if (!maybe_init (ctx, preinit))
{
context_free (ctx);
return NULL;
diff --git a/resolv/resolv_context.h b/resolv/resolv_context.h
index 27c8d56b36104521..ff9ef2c7fe6101f3 100644
--- a/resolv/resolv_context.h
+++ b/resolv/resolv_context.h
@@ -40,15 +40,22 @@
#ifndef _RESOLV_CONTEXT_H
#define _RESOLV_CONTEXT_H
+#include <bits/types/res_state.h>
+#include <resolv/resolv_conf.h>
#include <stdbool.h>
#include <stddef.h>
-#include <bits/types/res_state.h>
/* Temporary resolver state. */
struct resolv_context
{
struct __res_state *resp; /* Backing resolver state. */
+ /* Extended resolver state. This is set to NULL if the
+ __resolv_context_get functions are unable to locate an associated
+ extended state. In this case, the configuration data in *resp
+ has to be used; otherwise, the data from *conf should be
+ preferred (because it is a superset). */
+ struct resolv_conf *conf;
/* The following fields are for internal use within the
resolv_context module. */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,161 @@
commit d4165eedf5b85bfda3ea6b251f69838857e44925
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jul 5 15:38:42 2017 +0200
support: Add support_chroot_create and support_chroot_free
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index 8f395d8ce92773a9..3b7b4129e31eaa22 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -47,46 +47,23 @@
res_init. */
static const char *const test_hostname = "www.example.com";
-/* Path to the test root directory. */
-static char *path_chroot;
-
-/* Path to resolv.conf under path_chroot (outside the chroot). */
-static char *path_resolv_conf;
+struct support_chroot *chroot_env;
static void
prepare (int argc, char **argv)
{
- path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
- if (mkdtemp (path_chroot) == NULL)
- FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", path_chroot);
- add_temp_file (path_chroot);
-
- /* Create the /etc directory in the chroot environment. */
- char *path_etc = xasprintf ("%s/etc", path_chroot);
- xmkdir (path_etc, 0777);
- add_temp_file (path_etc);
-
- /* Create an empty resolv.conf file. */
- path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc);
- add_temp_file (path_resolv_conf);
- support_write_file_string (path_resolv_conf, "");
-
- free (path_etc);
-
- /* valgrind needs a temporary directory in the chroot. */
- {
- char *path_tmp = xasprintf ("%s/tmp", path_chroot);
- xmkdir (path_tmp, 0777);
- add_temp_file (path_tmp);
- free (path_tmp);
- }
+ chroot_env = support_chroot_create
+ ((struct support_chroot_configuration)
+ {
+ .resolv_conf = "",
+ });
}
/* Verify that the chroot environment has been set up. */
static void
check_chroot_working (void *closure)
{
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
FILE *fp = xfopen (_PATH_RESCONF, "r");
xfclose (fp);
@@ -345,7 +322,7 @@ setup_nss_dns_and_chroot (void)
/* Load nss_dns outside of the chroot. */
if (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) == NULL)
FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
/* Force the use of nss_dns. */
__nss_configure_lookup ("hosts", "dns");
}
@@ -374,13 +351,13 @@ run_res_init (void *closure)
switch (ctx->init)
{
case test_init:
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
TEST_VERIFY (res_init () == 0);
print_resp (stdout, &_res);
return;
case test_ninit:
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
res_state resp = xmalloc (sizeof (*resp));
memset (resp, 0, sizeof (*resp));
TEST_VERIFY (res_ninit (resp) == 0);
@@ -390,7 +367,7 @@ run_res_init (void *closure)
return;
case test_mkquery:
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
unsigned char buf[512];
TEST_VERIFY (res_mkquery (QUERY, "www.example",
C_IN, ns_t_a, NULL, 0,
@@ -783,7 +760,7 @@ special_test_callback (void *closure)
TEST_VERIFY (test_index < special_tests_count);
if (test_verbose > 0)
printf ("info: special test %u\n", test_index);
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
switch (test_index)
{
@@ -1063,7 +1040,8 @@ do_test (void)
TEST_VERIFY (test_cases[i].conf != NULL);
TEST_VERIFY (test_cases[i].expected != NULL);
- support_write_file_string (path_resolv_conf, test_cases[i].conf);
+ support_write_file_string (chroot_env->path_resolv_conf,
+ test_cases[i].conf);
test_file_contents (&test_cases[i]);
@@ -1073,24 +1051,24 @@ do_test (void)
{
if (test_verbose > 0)
printf ("info: special test: missing file\n");
- TEST_VERIFY (unlink (path_resolv_conf) == 0);
+ TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
test_file_contents (&test_cases[i]);
if (test_verbose > 0)
printf ("info: special test: dangling symbolic link\n");
- TEST_VERIFY (symlink ("does-not-exist", path_resolv_conf) == 0);
+ TEST_VERIFY (symlink ("does-not-exist", chroot_env->path_resolv_conf) == 0);
test_file_contents (&test_cases[i]);
- TEST_VERIFY (unlink (path_resolv_conf) == 0);
+ TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
if (test_verbose > 0)
printf ("info: special test: unreadable file\n");
- support_write_file_string (path_resolv_conf, "");
- TEST_VERIFY (chmod (path_resolv_conf, 0) == 0);
+ support_write_file_string (chroot_env->path_resolv_conf, "");
+ TEST_VERIFY (chmod (chroot_env->path_resolv_conf, 0) == 0);
test_file_contents (&test_cases[i]);
/* Restore the empty file. */
- TEST_VERIFY (unlink (path_resolv_conf) == 0);
- support_write_file_string (path_resolv_conf, "");
+ TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
+ support_write_file_string (chroot_env->path_resolv_conf, "");
}
}
@@ -1106,10 +1084,7 @@ do_test (void)
xwaitpid (server, NULL, 0);
}
- free (path_chroot);
- path_chroot = NULL;
- free (path_resolv_conf);
- path_resolv_conf = NULL;
+ support_chroot_free (chroot_env);
return 0;
}

View File

@ -0,0 +1,192 @@
commit 965d5c391c86eb3a812ce308411c32754f12a9d2
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jun 21 12:51:54 2017 +0200
inet: Add IPv6 getaddrinfo coverage to tst-inet6_scopeid_pton.c
diff --git a/inet/tst-inet6_scopeid_pton.c b/inet/tst-inet6_scopeid_pton.c
index 2178c5b4d2b19544..a1bafa9021c5cf3b 100644
--- a/inet/tst-inet6_scopeid_pton.c
+++ b/inet/tst-inet6_scopeid_pton.c
@@ -1,4 +1,4 @@
-/* Tests for __inet6_scopeid_pton.
+/* Tests for __inet6_scopeid_pton and IPv6 scopes in getaddrinfo.
Copyright (C) 2016-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -20,8 +20,13 @@
#include <inttypes.h>
#include <net-internal.h>
#include <net/if.h>
+#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
/* An interface which is known to the system. */
static const char *interface_name;
@@ -45,30 +50,103 @@ from_string (const char *address)
{
struct in6_addr addr;
if (inet_pton (AF_INET6, address, &addr) != 1)
+ FAIL_EXIT1 ("inet_pton (\"%s\")", address);
+ return addr;
+}
+
+/* Invoke getaddrinfo to parse ADDRESS%SCOPE. Return true if
+ getaddrinfo was successful. */
+static bool
+call_gai (int family, const char *address, const char *scope,
+ struct sockaddr_in6 *result)
+{
+ struct addrinfo hints =
{
- printf ("error: inet_pton (\"%s\") failed\n", address);
- exit (1);
+ .ai_family = family,
+ .ai_flags = AI_NUMERICHOST,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_protocol = IPPROTO_UDP,
+ };
+ char *fulladdr = xasprintf ("%s%%%s", address, scope);
+ struct addrinfo *ai = NULL;
+ int ret = getaddrinfo (fulladdr, NULL, &hints, &ai);
+ if (ret == EAI_ADDRFAMILY || ret == EAI_NONAME)
+ {
+ if (test_verbose > 0)
+ printf ("info: getaddrinfo (\"%s\"): %s (%d)\n",
+ fulladdr, gai_strerror (ret), ret);
+ free (fulladdr);
+ return false;
+ }
+ if (ret != 0)
+ FAIL_EXIT1 ("getaddrinfo (\"%s\"): %s (%d)\n",
+ fulladdr, gai_strerror (ret), ret);
+ TEST_VERIFY_EXIT (ai != NULL);
+ TEST_VERIFY_EXIT (ai->ai_addrlen == sizeof (*result));
+ TEST_VERIFY (ai->ai_family == AF_INET6);
+ TEST_VERIFY (ai->ai_next == NULL);
+ memcpy (result, ai->ai_addr, sizeof (*result));
+ free (fulladdr);
+ freeaddrinfo (ai);
+ return true;
+}
+
+/* Verify that a successful call to getaddrinfo returned the expected
+ scope data. */
+static void
+check_ai (const char *what, const char *addr_string, const char *scope_string,
+ const struct sockaddr_in6 *sa,
+ const struct in6_addr *addr, uint32_t scope)
+{
+ if (memcmp (addr, &sa->sin6_addr, sizeof (*addr)) != 0)
+ {
+ support_record_failure ();
+ printf ("error: getaddrinfo %s address mismatch for %s%%%s\n",
+ what, addr_string, scope_string);
+ }
+ if (sa->sin6_scope_id != scope)
+ {
+ support_record_failure ();
+ printf ("error: getaddrinfo %s scope mismatch for %s%%%s\n"
+ " expected: %" PRIu32 "\n"
+ " actual: %" PRIu32 "\n",
+ what, addr_string, scope_string, scope, sa->sin6_scope_id);
}
- return addr;
}
/* Check a single address were we expected a failure. */
static void
expect_failure (const char *address, const char *scope)
{
+ if (test_verbose > 0)
+ printf ("info: expecting failure for %s%%%s\n", address, scope);
struct in6_addr addr = from_string (address);
uint32_t result = 1234;
if (__inet6_scopeid_pton (&addr, scope, &result) == 0)
{
+ support_record_failure ();
printf ("error: unexpected success for %s%%%s\n",
address, scope);
- exit (1);
}
if (result != 1234)
{
+ support_record_failure ();
printf ("error: unexpected result update for %s%%%s\n",
address, scope);
- exit (1);
+ }
+
+ struct sockaddr_in6 sa;
+ if (call_gai (AF_UNSPEC, address, scope, &sa))
+ {
+ support_record_failure ();
+ printf ("error: unexpected getaddrinfo success for %s%%%s (AF_UNSPEC)\n",
+ address, scope);
+ }
+ if (call_gai (AF_INET6, address, scope, &sa))
+ {
+ support_record_failure ();
+ printf ("error: unexpected getaddrinfo success for %s%%%s (AF_INET6)\n",
+ address, scope);
}
}
@@ -76,21 +154,43 @@ expect_failure (const char *address, const char *scope)
static void
expect_success (const char *address, const char *scope, uint32_t expected)
{
+ if (test_verbose > 0)
+ printf ("info: expecting success for %s%%%s\n", address, scope);
struct in6_addr addr = from_string (address);
uint32_t actual = expected + 1;
if (__inet6_scopeid_pton (&addr, scope, &actual) != 0)
{
+ support_record_failure ();
printf ("error: unexpected failure for %s%%%s\n",
address, scope);
- exit (1);
}
if (actual != expected)
{
+ support_record_failure ();
printf ("error: unexpected result for for %s%%%s\n",
address, scope);
printf (" expected: %" PRIu32 "\n", expected);
printf (" actual: %" PRIu32 "\n", actual);
- exit (1);
+ }
+
+ struct sockaddr_in6 sa;
+ memset (&sa, 0xc0, sizeof (sa));
+ if (call_gai (AF_UNSPEC, address, scope, &sa))
+ check_ai ("AF_UNSPEC", address, scope, &sa, &addr, expected);
+ else
+ {
+ support_record_failure ();
+ printf ("error: unexpected getaddrinfo failure for %s%%%s (AF_UNSPEC)\n",
+ address, scope);
+ }
+ memset (&sa, 0xc0, sizeof (sa));
+ if (call_gai (AF_INET6, address, scope, &sa))
+ check_ai ("AF_INET6", address, scope, &sa, &addr, expected);
+ else
+ {
+ support_record_failure ();
+ printf ("error: unexpected getaddrinfo failure for %s%%%s (AF_INET6)\n",
+ address, scope);
}
}
@@ -127,5 +227,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>

View File

@ -0,0 +1,321 @@
commit 85cfe508568530eed2d9cfd34110c21721d1f99e
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Sep 6 13:43:01 2017 +0200
tst-res_use_inet6: Enhance test to cover IPv4-to-IPv6 address mapping
This requires more control over the response data, so it is now
determined by flags embedded in the query name.
(cherry picked from commit 5e9c4d17feb9910f489ad2915d0b6e00597a0f11)
diff --git a/resolv/tst-res_use_inet6.c b/resolv/tst-res_use_inet6.c
index 6f3db088929027b7..1522d5c5f5e4d860 100644
--- a/resolv/tst-res_use_inet6.c
+++ b/resolv/tst-res_use_inet6.c
@@ -19,18 +19,44 @@
#include <netdb.h>
#include <resolv.h>
#include <string.h>
+#include <support/check.h>
#include <support/check_nss.h>
#include <support/resolv_test.h>
#include <support/xthread.h>
+/* Produce a response based on QNAME: Certain characters in the first
+ label of QNAME trigger the inclusion of resource records:
+
+ 'a' A record (IPv4 address)
+ 'q' AAAA record (quad A record, IPv6 address)
+ 'm' record type must match QTYPE (no additional records)
+
+ QTYPE is ignored for record type selection if 'm' is not
+ specified. */
static void
response (const struct resolv_response_context *ctx,
struct resolv_response_builder *b,
const char *qname, uint16_t qclass, uint16_t qtype)
{
- bool include_both = strcmp (qname, "both.example") == 0;
- bool include_a = qtype == T_A || include_both;
- bool include_aaaa = qtype == T_AAAA || include_both;
+ bool include_a = false;
+ bool include_aaaa = false;
+ bool include_match = false;
+ for (const char *p = qname; *p != '.' && *p != '\0'; ++p)
+ {
+ if (*p == 'a')
+ include_a = true;
+ else if (*p == 'q')
+ include_aaaa = true;
+ else if (*p == 'm')
+ include_match = true;
+ }
+ if (include_match)
+ {
+ if (qtype == T_A)
+ include_aaaa = false;
+ else if (qtype == T_AAAA)
+ include_a = false;
+ }
resolv_response_init (b, (struct resolv_response_flags) {});
resolv_response_add_question (b, qname, qclass, qtype);
@@ -64,16 +90,21 @@ test_gai (void)
.ai_protocol = IPPROTO_TCP,
};
struct addrinfo *ai;
- int ret = getaddrinfo ("www1.example", "80", &hints, &ai);
- check_addrinfo ("getaddrinfo AF_UNSPEC www1.example", ai, ret,
+ int ret = getaddrinfo ("qam.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_UNSPEC qam.example", ai, ret,
"address: STREAM/TCP 192.0.2.17 80\n"
"address: STREAM/TCP 2001:db8::1 80\n");
if (ret == 0)
freeaddrinfo (ai);
- ret = getaddrinfo ("both.example", "80", &hints, &ai);
+ ret = getaddrinfo ("am.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_UNSPEC am.example", ai, ret,
+ "address: STREAM/TCP 192.0.2.17 80\n");
+ if (ret == 0)
+ freeaddrinfo (ai);
+ ret = getaddrinfo ("qa.example", "80", &hints, &ai);
/* Combined A/AAAA responses currently result in address
duplication. */
- check_addrinfo ("getaddrinfo AF_UNSPEC both.example", ai, ret,
+ check_addrinfo ("getaddrinfo AF_UNSPEC qa.example", ai, ret,
"address: STREAM/TCP 192.0.2.17 80\n"
"address: STREAM/TCP 192.0.2.17 80\n"
"address: STREAM/TCP 2001:db8::1 80\n"
@@ -89,13 +120,18 @@ test_gai (void)
.ai_protocol = IPPROTO_TCP,
};
struct addrinfo *ai;
- int ret = getaddrinfo ("www1.example", "80", &hints, &ai);
- check_addrinfo ("getaddrinfo AF_INET www1.example", ai, ret,
+ int ret = getaddrinfo ("qam.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_INET qam.example", ai, ret,
+ "address: STREAM/TCP 192.0.2.17 80\n");
+ if (ret == 0)
+ freeaddrinfo (ai);
+ ret = getaddrinfo ("am.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_INET am.example", ai, ret,
"address: STREAM/TCP 192.0.2.17 80\n");
if (ret == 0)
freeaddrinfo (ai);
- ret = getaddrinfo ("both.example", "80", &hints, &ai);
- check_addrinfo ("getaddrinfo AF_INET both.example", ai, ret,
+ ret = getaddrinfo ("qa.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_INET qa.example", ai, ret,
"address: STREAM/TCP 192.0.2.17 80\n");
if (ret == 0)
freeaddrinfo (ai);
@@ -108,40 +144,131 @@ test_gai (void)
.ai_protocol = IPPROTO_TCP,
};
struct addrinfo *ai;
- int ret = getaddrinfo ("www1.example", "80", &hints, &ai);
+ int ret = getaddrinfo ("qa.example", "80", &hints, &ai);
check_addrinfo ("getaddrinfo (AF_INET6)", ai, ret,
"address: STREAM/TCP 2001:db8::1 80\n");
if (ret == 0)
freeaddrinfo (ai);
- ret = getaddrinfo ("both.example", "80", &hints, &ai);
- check_addrinfo ("getaddrinfo AF_INET6 both.example", ai, ret,
+ ret = getaddrinfo ("am.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_INET6 am.example", ai, ret,
+ "error: No address associated with hostname\n");
+ if (ret == 0)
+ freeaddrinfo (ai);
+ ret = getaddrinfo ("qam.example", "80", &hints, &ai);
+ check_addrinfo ("getaddrinfo AF_INET6 qam.example", ai, ret,
"address: STREAM/TCP 2001:db8::1 80\n");
if (ret == 0)
freeaddrinfo (ai);
}
}
-/* Test that gethostbyname2 is not influenced by RES_USE_INET6. */
+/* Test that gethostbyname2 is mostly not influenced by
+ RES_USE_INET6. */
static void
-test_get2 (void)
+test_get2_any (void)
{
- check_hostent ("gethostbyname2 AF_INET www1.example",
- gethostbyname2 ("www1.example", AF_INET),
- "name: www1.example\n"
+ check_hostent ("gethostbyname2 AF_INET am.example",
+ gethostbyname2 ("am.example", AF_INET),
+ "name: am.example\n"
"address: 192.0.2.17\n");
- check_hostent ("gethostbyname2 AF_INET both.example",
- gethostbyname2 ("both.example", AF_INET),
- "name: both.example\n"
+ check_hostent ("gethostbyname2 AF_INET a.example",
+ gethostbyname2 ("a.example", AF_INET),
+ "name: a.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("gethostbyname2 AF_INET qm.example",
+ gethostbyname2 ("qm.example", AF_INET),
+ "error: NO_ADDRESS\n");
+ check_hostent ("gethostbyname2 AF_INET q.example",
+ gethostbyname2 ("q.example", AF_INET),
+ "error: NO_RECOVERY\n");
+ check_hostent ("gethostbyname2 AF_INET qam.example",
+ gethostbyname2 ("qam.example", AF_INET),
+ "name: qam.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("gethostbyname2 AF_INET qa.example",
+ gethostbyname2 ("qa.example", AF_INET),
+ "name: qa.example\n"
"address: 192.0.2.17\n");
- check_hostent ("gethostbyname2 AF_INET6 www1.example",
- gethostbyname2 ("www1.example", AF_INET6),
- "name: www1.example\n"
+ check_hostent ("gethostbyname2 AF_INET6 qm.example",
+ gethostbyname2 ("qm.example", AF_INET6),
+ "name: qm.example\n"
+ "address: 2001:db8::1\n");
+ check_hostent ("gethostbyname2 AF_INET6 q.example",
+ gethostbyname2 ("q.example", AF_INET6),
+ "name: q.example\n"
"address: 2001:db8::1\n");
- check_hostent ("gethostbyname2 AF_INET6 both.example",
- gethostbyname2 ("both.example", AF_INET6),
- "name: both.example\n"
+ check_hostent ("gethostbyname2 AF_INET6 qam.example",
+ gethostbyname2 ("qam.example", AF_INET6),
+ "name: qam.example\n"
"address: 2001:db8::1\n");
+ check_hostent ("gethostbyname2 AF_INET6 qa.example",
+ gethostbyname2 ("qa.example", AF_INET6),
+ "name: qa.example\n"
+ "address: 2001:db8::1\n");
+ /* Additional AF_INET6 tests depend on RES_USE_INET6; see below. */
+}
+
+/* gethostbyname2 tests with RES_USE_INET6 disabled. */
+static void
+test_get2_no_inet6 (void)
+{
+ test_get2_any ();
+
+ check_hostent ("gethostbyname2 AF_INET6 am.example",
+ gethostbyname2 ("am.example", AF_INET6),
+ "error: NO_ADDRESS\n");
+ check_hostent ("gethostbyname2 AF_INET6 a.example",
+ gethostbyname2 ("a.example", AF_INET6),
+ "error: NO_RECOVERY\n");
+}
+
+/* gethostbyname2 tests with RES_USE_INET6 enabled. */
+static void
+test_get2_inet6 (void)
+{
+ test_get2_any ();
+
+ check_hostent ("gethostbyname2 AF_INET6 am.example",
+ gethostbyname2 ("am.example", AF_INET6),
+ "name: am.example\n"
+ "address: ::ffff:192.0.2.17\n");
+ check_hostent ("gethostbyname2 AF_INET6 a.example",
+ gethostbyname2 ("a.example", AF_INET6),
+ "error: NO_RECOVERY\n");
+}
+
+/* Collection of tests which assume no RES_USE_INET6 flag. */
+static void
+test_no_inet6 (void)
+{
+ check_hostent ("gethostbyname (\"a.example\")",
+ gethostbyname ("a.example"),
+ "name: a.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("gethostbyname (\"qa.example\")",
+ gethostbyname ("qa.example"),
+ "name: qa.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("gethostbyname (\"am.example\")",
+ gethostbyname ("am.example"),
+ "name: am.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("gethostbyname (\"qam.example\")",
+ gethostbyname ("qam.example"),
+ "name: qam.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("gethostbyname (\"q.example\")",
+ gethostbyname ("q.example"),
+ "error: NO_RECOVERY\n");
+ check_hostent ("gethostbyname (\"qm.example\")",
+ gethostbyname ("qm.example"),
+ "error: NO_ADDRESS\n");
+ test_get2_no_inet6 ();
+ test_get2_no_inet6 ();
+ test_gai ();
+ test_get2_no_inet6 ();
+ test_get2_no_inet6 ();
}
static void *
@@ -153,28 +280,42 @@ threadfunc (void *ignored)
.response_callback = response
});
- check_hostent ("gethostbyname (\"www1.example\")",
- gethostbyname ("www1.example"),
- "name: www1.example\n"
- "address: 192.0.2.17\n");
- check_hostent ("gethostbyname (\"both.example\")",
- gethostbyname ("both.example"),
- "name: both.example\n"
- "address: 192.0.2.17\n");
- test_get2 ();
- test_gai ();
+ TEST_VERIFY ((_res.options & RES_USE_INET6) == 0);
+ test_no_inet6 ();
_res.options |= RES_USE_INET6;
- check_hostent ("gethostbyname (\"www1.example\")",
- gethostbyname ("www1.example"),
- "name: www1.example\n"
+ check_hostent ("gethostbyname (\"a.inet6.example\")",
+ gethostbyname ("a.inet6.example"),
+ "error: NO_RECOVERY\n");
+ check_hostent ("gethostbyname (\"am.inet6.example\")",
+ gethostbyname ("am.inet6.example"),
+ "name: am.inet6.example\n"
+ "address: ::ffff:192.0.2.17\n");
+ check_hostent ("gethostbyname (\"qa.inet6.example\")",
+ gethostbyname ("qa.inet6.example"),
+ "name: qa.inet6.example\n"
+ "address: 2001:db8::1\n");
+ check_hostent ("gethostbyname (\"qam.inet6.example\")",
+ gethostbyname ("qam.inet6.example"),
+ "name: qam.inet6.example\n"
"address: 2001:db8::1\n");
- check_hostent ("gethostbyname (\"both.example\")",
- gethostbyname ("both.example"),
- "name: both.example\n"
+ check_hostent ("gethostbyname (\"q.inet6.example\")",
+ gethostbyname ("q.inet6.example"),
+ "name: q.inet6.example\n"
"address: 2001:db8::1\n");
- test_get2 ();
+ check_hostent ("gethostbyname (\"qm.inet6.example\")",
+ gethostbyname ("qm.inet6.example"),
+ "name: qm.inet6.example\n"
+ "address: 2001:db8::1\n");
+ test_get2_inet6 ();
+ test_get2_inet6 ();
test_gai ();
+ test_get2_inet6 ();
+ test_get2_inet6 ();
+
+ TEST_VERIFY (_res.options & RES_USE_INET6);
+ _res.options &= ~RES_USE_INET6;
+ test_no_inet6 ();
resolv_test_end (obj);

View File

@ -0,0 +1,352 @@
commit c3261cdb5b739c1e814de32e40ecd712ad987cdb
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Apr 4 17:31:52 2017 +0200
resolv: Add tst-resolv-canonname
diff --git a/resolv/Makefile b/resolv/Makefile
index 8441f9d30d83a209..db287947a4f7e9a6 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -51,6 +51,13 @@ tests += \
tst-resolv-network \
tst-resolv-search \
+# These tests need libdl.
+ifeq (yes,$(build-shared))
+tests += \
+ tst-resolv-canonname \
+
+endif
+
# This test sends millions of packets and is rather slow.
xtests += tst-resolv-qtypes
endif
@@ -130,6 +137,8 @@ $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-canonname: \
+ $(libdl) $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-ns_name: $(objpfx)libresolv.so
$(objpfx)tst-ns_name.out: tst-ns_name.data
diff --git a/resolv/tst-resolv-canonname.c b/resolv/tst-resolv-canonname.c
new file mode 100644
index 0000000000000000..5daac33882957791
--- /dev/null
+++ b/resolv/tst-resolv-canonname.c
@@ -0,0 +1,313 @@
+/* Test _nss_dns_getcanonname_r corner cases.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <gnu/lib-names.h>
+#include <netdb.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+/* _nss_dns_getcanonname_r is not called during regular operation
+ because nss_dns directly provides a canonical name, so we have to
+ test it directly. The function pointer is initialized by do_test
+ below. */
+static enum nss_status
+(*getcanonname) (const char *name, char *buffer, size_t buflen,
+ char **result, int *errnop, int *h_errnop);
+
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ int code;
+ {
+ char *tail;
+ if (sscanf (qname, "code%d.%ms", &code, &tail) != 2
+ || strcmp (tail, "example") != 0)
+ FAIL_EXIT1 ("error: invalid QNAME: %s\n", qname);
+ free (tail);
+ }
+
+ switch (code)
+ {
+ case 1:
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, "www.example", qclass, qtype, 0);
+ resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
+ resolv_response_close_record (b);
+ break;
+ case 2:
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ if (qtype == T_AAAA)
+ {
+ resolv_response_open_record (b, "www.example", qclass, qtype, 0);
+ resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
+ resolv_response_close_record (b);
+ for (int i = 0; i < 30000; ++i)
+ resolv_response_add_data (b, "", 1);
+ }
+ break;
+ case 3:
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ if (qtype == T_AAAA)
+ {
+ resolv_response_open_record (b, "www.example", qclass, qtype, 0);
+ resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
+ resolv_response_close_record (b);
+ }
+ else
+ {
+ for (int i = 0; i < 30000; ++i)
+ resolv_response_add_data (b, "", 1);
+ }
+ break;
+ case 4:
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
+ resolv_response_add_name (b, "www.example");
+ resolv_response_close_record (b);
+ resolv_response_open_record (b, "www.example", qclass, qtype, 0);
+ resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
+ resolv_response_close_record (b);
+ break;
+ case 5:
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
+ resolv_response_add_name (b, "www.example");
+ resolv_response_close_record (b);
+ resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
+ resolv_response_add_name (b, "www1.example");
+ resolv_response_close_record (b);
+ resolv_response_open_record (b, "www1.example", qclass, qtype, 0);
+ resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
+ resolv_response_close_record (b);
+ break;
+ case 6:
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
+ resolv_response_add_name (b, "www.example");
+ resolv_response_close_record (b);
+ resolv_response_open_record (b, qname, qclass, 46 /* RRSIG */, 0);
+ resolv_response_add_name (b, ".");
+ resolv_response_close_record (b);
+ resolv_response_open_record (b, "www.example", qclass, qtype, 0);
+ resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
+ resolv_response_close_record (b);
+ break;
+ case 102:
+ if (!ctx->tcp)
+ {
+ resolv_response_init (b, (struct resolv_response_flags) {.tc = true});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ }
+ else
+ {
+ resolv_response_init
+ (b, (struct resolv_response_flags) {.ancount = 1});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
+ size_t to_fill = 65535 - resolv_response_length (b)
+ - 2 /* length, "n" */ - 2 /* compression reference */
+ - 2 /* RR type */;
+ for (size_t i = 0; i < to_fill; ++i)
+ resolv_response_add_data (b, "", 1);
+ resolv_response_close_record (b);
+ resolv_response_add_name (b, "n.example");
+ uint16_t rrtype = htons (T_CNAME);
+ resolv_response_add_data (b, &rrtype, sizeof (rrtype));
+ }
+ break;
+ case 103:
+ /* NODATA repsonse. */
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ break;
+ case 104:
+ resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ /* No RR metadata. */
+ resolv_response_add_name (b, "www.example");
+ break;
+ case 105:
+ if (qtype == T_A)
+ {
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ /* No data, trigger AAAA query. */
+ }
+ else
+ {
+ resolv_response_init
+ (b, (struct resolv_response_flags) {.ancount = 1});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ /* No RR metadata. */
+ resolv_response_add_name
+ (b, "long-name-exceed-previously-initialized-buffer.example");
+ }
+ break;
+ case 106:
+ resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ /* No RR metadata. */
+ resolv_response_add_name (b, "www.example");
+ resolv_response_add_data (b, "\xff\xff", 2);
+ break;
+ case 107:
+ if (qtype == T_A)
+ {
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ /* No data, trigger AAAA query. */
+ }
+ else
+ {
+ resolv_response_init
+ (b, (struct resolv_response_flags) {.ancount = 1});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ /* No RR metadata. */
+ resolv_response_add_name (b, "www.example");
+ resolv_response_add_data (b, "\xff\xff", 2);
+ }
+ break;
+ default:
+ FAIL_EXIT1 ("error: invalid QNAME: %s (code %d)\n", qname, code);
+ }
+}
+
+static void
+check (int code, const char *expected)
+{
+ char qname[200];
+ snprintf (qname, sizeof (qname), "code%d.example", code);
+ char *result;
+ enum nss_status status;
+ {
+ enum { buffer_size = 4096 };
+ char *buffer = xmalloc (buffer_size);
+ char *temp_result;
+ int temp_errno;
+ int temp_herrno;
+ status = getcanonname
+ (qname, buffer, buffer_size, &temp_result, &temp_errno, &temp_herrno);
+ if (status == NSS_STATUS_SUCCESS)
+ result = xstrdup (temp_result);
+ else
+ {
+ errno = temp_errno;
+ h_errno = temp_herrno;
+ }
+ free (buffer);
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ if (expected != NULL)
+ {
+ if (strcmp (result, expected) != 0)
+ {
+ support_record_failure ();
+ printf ("error: getcanonname (%s) failed\n", qname);
+ printf ("error: expected: %s\n", expected);
+ printf ("error: actual: %s\n", result);
+ free (result);
+ return;
+ }
+ }
+ else
+ {
+ support_record_failure ();
+ printf ("error: getcanonname (%s) unexpected success\n", qname);
+ printf ("error: actual: %s\n", result);
+ free (result);
+ return;
+ }
+ free (result);
+ }
+ else
+ {
+ if (expected != NULL)
+ {
+ support_record_failure ();
+ printf ("error: getcanonname (%s) failed\n", qname);
+ printf ("error: expected: %s\n", expected);
+ return;
+ }
+ }
+}
+
+
+static int
+do_test (void)
+{
+ void *nss_dns_handle = dlopen (LIBNSS_DNS_SO, RTLD_LAZY);
+ if (nss_dns_handle == NULL)
+ FAIL_EXIT1 ("could not dlopen %s: %s", LIBNSS_DNS_SO, dlerror ());
+ {
+ const char *func = "_nss_dns_getcanonname_r";
+ void *ptr = dlsym (nss_dns_handle, func);
+ if (ptr == NULL)
+ FAIL_EXIT1 ("could not look up %s: %s", func, dlerror ());
+ getcanonname = ptr;
+ }
+
+ struct resolv_test *aux = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response,
+ });
+
+ check (1, "www.example");
+ check (2, "www.example");
+ check (3, "www.example");
+ check (4, "www.example");
+ check (5, "www1.example");
+
+ /* This should really result in "www.example", but the fake RRSIG
+ record causes the current implementation to stop parsing. */
+ check (6, NULL);
+
+ for (int i = 102; i <= 107; ++i)
+ check (i, NULL);
+
+ resolv_test_end (aux);
+
+ TEST_VERIFY (dlclose (nss_dns_handle) == 0);
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,46 @@
commit a9270e673dcc1ef1d2c2d96fa09d468c59883d88
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 30 18:02:11 2017 +0200
resolv: Improve debugging output from tst-resolv-res_init
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index 2b68c5ff9a69a291..b5fe2cfb002679f2 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -257,6 +257,15 @@ enum test_init
test_init_method_last = test_getaddrinfo
};
+static const char *const test_init_names[] =
+ {
+ [test_init] = "res_init",
+ [test_ninit] = "res_init",
+ [test_mkquery] = "res_mkquery",
+ [test_gethostbyname] = "gethostbyname",
+ [test_getaddrinfo] = "getaddrinfo",
+ };
+
/* Closure argument for run_res_init. */
struct test_context
{
@@ -507,7 +516,8 @@ test_file_contents (const struct test_case *t)
++init_method)
{
if (test_verbose > 0)
- printf ("info: testing init method %d\n", init_method);
+ printf ("info: testing init method %s\n",
+ test_init_names[init_method]);
struct test_context ctx = { .init = init_method, .t = t };
void (*func) (void *) = run_res_init;
#if TEST_THREAD
@@ -519,7 +529,8 @@ test_file_contents (const struct test_case *t)
if (strcmp (proc.out.buffer, t->expected) != 0)
{
support_record_failure ();
- printf ("error: output mismatch for %s\n", t->name);
+ printf ("error: output mismatch for %s (init method %s)\n",
+ t->name, test_init_names[init_method]);
support_run_diff ("expected", t->expected,
"actual", proc.out.buffer);
}

View File

@ -1,6 +1,6 @@
%define glibcsrcdir glibc-2.25-3-g93cf93e
%define glibcsrcdir glibc-2.25-123-gedcf13e25c
%define glibcversion 2.25
%define glibcrelease 3%{?dist}
%define glibcrelease 13%{?dist}
# Pre-release tarballs are pulled in from git using a command that is
# effectively:
#
@ -9,7 +9,8 @@
# gzip -9 $(git describe --match 'glibc-*').tar
#
# glibc_release_url is only defined when we have a release tarball.
%define glibc_release_url http://ftp.gnu.org/gnu/glibc/
%{lua: if string.match(rpm.expand("%glibcsrcdir"), "^glibc%-[0-9.]+$") then
rpm.define("glibc_release_url https://ftp.gnu.org/gnu/glibc/") end}
##############################################################################
# We support hte following options:
# --with/--without,
@ -131,14 +132,6 @@
# will be created for the architecture.
%define debuginfocommonarches %{biarcharches} alpha alphaev6
##############################################################################
# If the architecture has multiarch support in glibc then it should be listed
# here to enable support in the build. Multiarch support is a single library
# with implementations of certain functions for multiple architectures. The
# most optimal function is selected at runtime based on the hardware that is
# detected by glibc. The underlying support for function selection and
# execution is provided by STT_GNU_IFUNC.
%define multiarcharches %{power64} %{ix86} x86_64 %{sparc}
##############################################################################
# Add -s for a less verbose build output.
%define silentrules PARALLELMFLAGS=
##############################################################################
@ -251,9 +244,6 @@ Patch0059: glibc-c-utf8-locale.patch
# Build libcrypt twice, with and without NSS.
Patch0060: glibc-rh1324623.patch
# Fix -Wstrict-overflow issues with gcc 7.0.
Patch0061: glibc-gcc-strict-overflow.patch
##############################################################################
#
# Patches from upstream
@ -290,6 +280,7 @@ Patch2036: glibc-gcc-PR69537.patch
# extend_alloca removal, BZ 18023
Patch2037: glibc-rh1315108.patch
Patch2038: glibc-rh1315108-glob.patch
# Upstream BZ 20313
Patch2110: glibc-rh1351108-update-to-unicode-9.0.0.patch
@ -297,6 +288,72 @@ Patch2110: glibc-rh1351108-update-to-unicode-9.0.0.patch
# sln implemented by ldconfig, to conserve disk space.
Patch2112: glibc-rh1315476-2.patch
Patch61: glibc-nscd-reproducible.patch
Patch62: glibc-nss_compat.patch
Patch63: glibc-rh1416405.patch
Patch64: glibc-bits-types-res_state.patch
Patch69: glibc-libc_diag.patch
Patch77: glibc-alloc_buffer-2.patch
Patch79: glibc-rh168253-network-dn_expand-cleanup.patch
Patch80: glibc-rh168253-nss_dns-declaration-cleanup.patch
Patch81: glibc-rh168253-tst-resolv-canonname.patch
Patch82: glibc-rh168253-remove-iquery.patch
Patch83: glibc-rh168253-resolv-h-definitions-cleanup.patch
Patch85: glibc-rh168253-remove-ends-fallback.patch
Patch86: glibc-rh168253-sock_cloexec.patch
Patch87: glibc-rh168253-builtin_expect.patch
Patch88: glibc-rh168253-builtin_expect-fixup.patch
Patch89: glibc-rh168253-res_dflretry.patch
Patch94: glibc-rh168253-res_init-tests.patch
Patch97: glibc-rh168253-getaddrinfo-malloc-canonname-strdup-3.patch
Patch98: glibc-rh168253-res_vinit-hidden.patch
Patch99: glibc-rh168253-res_randomid-reorg.patch
Patch100: glibc-rh168253-res-close.patch
Patch101: glibc-rh168253-res_setoptions-debug-cleanup.patch
Patch102: glibc-rh168253-is_sort_mask.patch
Patch103: glibc-rh168253-res_vinit-gnu-style.patch
Patch104: glibc-rh168253-res_vinit-check-allocations.patch
Patch105: glibc-rh168253-res_vinit_1-getline.patch
Patch106: glibc-rh168253-tst-inet6_scopeid_pton-getaddrinfo.patch
Patch107: glibc-rh168253-inet_pton_length.patch
Patch109: glibc-rh168253-inet6_scopeid_pton-node-local.patch
Patch110: glibc-rh168253-__res_initstamp-cleanup.patch
Patch111: glibc-rh168253-res_libc-gnu-style.patch
Patch112: glibc-rh168253-inet_pton-leading-zeros.patch
Patch114: glibc-rh168253-getaddrinfo-tests-bug21295.patch
Patch115: glibc-rh168253-_-res_vinit-_res_hconf_init.patch
Patch116: glibc-rh168253-resolv-tests-timeout.patch
Patch117: glibc-rh168253-res_rotate-random.patch
Patch118: glibc-rh168253-res_mkquery-debug-cleanup.patch
Patch119: glibc-rh168253-res_mkquery-gnu-style.patch
Patch120: glibc-rh168253-res_mkquery-reorg.patch
Patch121: glibc-rh168253-res_send-debug-cleanup.patch
Patch122: glibc-rh168253-res_debug-removal.patch
Patch123: glibc-rh168253-fp_nquery-reorg.patch
Patch124: glibc-rh168253-_res_opcodes-compat.patch
Patch125: glibc-rh168253-res_isourserver-reorg.patch
Patch126: glibc-rh168253-res_query-reorg.patch
Patch127: glibc-rh168253-res_data-gnu-style.patch
Patch128: glibc-rh168253-res_query-debug-cleanup.patch
Patch129: glibc-rh168253-res_options-source-cleanup.patch
Patch130: glibc-rh168253-tst-resolv-res_init-debugging.patch
Patch131: glibc-rh168253-resolv-tests-preinit.patch
Patch132: glibc-rh168253-struct-resolv_context.patch
Patch133: glibc-rh168253-struct-resolv_conf.patch
Patch134: glibc-rh168253-search-list-limit.patch
Patch135: glibc-rh168253-resolv_conf-full-config.patch
Patch136: glibc-rh168253-resolv-conf-reload.patch
Patch137: glibc-rh168253-resolv_conf-free-list.patch
Patch138: glibc-rh168253-__resolv_conf_attach-assert.patch
Patch139: glibc-rh168253-resolv_conf-_res-matching.patch
Patch140: glibc-rh168253-support_chroot.patch
Patch141: glibc-rh168253-resolv-tests-no-patching.patch
Patch142: glibc-rh168253-resolv-tests-nondeterministic.patch
Patch151: glibc-rh168253-tst-res_use_inet6-mapping.patch
Patch152: glibc-rh168253-nss_dns-dead-code.patch
Patch153: glibc-rh168253-resolv-oom-memory-leak.patch
Patch154: glibc-rh168253-__resolv_conf_attach-improper-free.patch
##############################################################################
# End of glibc patches.
##############################################################################
@ -380,29 +437,9 @@ Conflicts: kernel < %{enablekernel}
%endif
%endif
%ifarch %{multiarcharches}
# Need STT_IFUNC support
%ifarch %{power64}
BuildRequires: binutils >= 2.20.51.0.2
Conflicts: binutils < 2.20.51.0.2
%else
%ifarch s390 s390x
# Needed for STT_GNU_IFUNC support for s390/390x
BuildRequires: binutils >= 2.23.52.0.1-8
Conflicts: binutils < 2.23.52.0.1-8
%else
# Default to this version
BuildRequires: binutils >= 2.19.51.0.10
Conflicts: binutils < 2.19.51.0.10
%endif
%endif
BuildRequires: binutils >= 2.25
# Earlier releases have broken support for IRELATIVE relocations
Conflicts: prelink < 0.4.2
%else
# Need AS_NEEDED directive
# Need --hash-style=* support
BuildRequires: binutils >= 2.17.50.0.2-5
%endif
BuildRequires: gcc >= 3.2.1-5
%ifarch s390 s390x
@ -607,47 +644,92 @@ The sources for all locales provided in the language packs.
If you are building custom locales you will most likely use
these sources as the basis for your new locale.
%define lang_package()\
%package langpack-%{1}\
Summary: Locale data for %{1}\
Provides: glibc-langpack = %{version}-%{release}\
Requires: %{name} = %{version}-%{release}\
Requires: %{name}-common = %{version}-%{release}\
%define supplements_list %(cat %{SOURCE11} | grep ^%{1}_ | cut -d / -f 1 | cut -d @ -f 1 | cut -d . -f 1 | sort -u | tr "\\\\n" " " | sed 's/ $//' | sed 's/ / or langpacks-/g' | sed 's/^/ or langpacks-/')\
Supplements: (glibc = %{version}-%{release} and (langpacks-%{1}%{supplements_list}))\
Group: System Environment/Base\
%description langpack-%{1}\
The glibc-langpack-%{1} package includes the basic information required\
to support the %{1} language in your applications.\
%ifnarch %{auxarches}\
%files -f langpack-%{1}.filelist langpack-%{1}\
%defattr(-,root,root)\
%endif\
%{nil}
%{lua:
-- Array of languages (ISO-639 codes).
local languages = {}
-- Dictionary from language codes (as in the languages array) to arrays
-- of regions.
local supplements = {}
do
-- Parse the SUPPORTED file. Eliminate duplicates.
local lang_region_seen = {}
for line in io.lines(rpm.expand("%{SOURCE11}")) do
-- Match lines which contain a language (eo) or language/region
-- (en_US) strings.
local lang_region = string.match(line, "^([a-z][^/@.]+)")
if lang_region ~= nil then
if lang_region_seen[lang_region] == nil then
lang_region_seen[lang_region] = true
# language_list will contain a list of all supported language
# names in iso-639 format, i.e. something like "aa af ... yue zh zu"
# We add "eo" (Esperanto) manually because currently glibc has no
# Esperanto locale in SUPPORTED but translations for Esperanto exist.
# Therefore, we want a glibc-langpack-eo sub-package containing these
# translations.
%define language_list eo %(cat %{SOURCE11} | grep -E '^[a-z]+_' | cut -d _ -f 1 | sort -u | tr "\\\\n" " " | sed 's/ $//')
-- Split language/region pair.
local lang, region = string.match(lang_region, "^(.+)_(.+)")
if lang == nil then
-- Region is missing, use only the language.
lang = lang_region
end
local suppl = supplements[lang]
if suppl == nil then
suppl = {}
supplements[lang] = suppl
-- New language not seen before.
languages[#languages + 1] = lang
end
if region ~= nil then
-- New region because of the check against
-- lang_region_seen above.
suppl[#suppl + 1] = region
end
end
end
end
-- Sort for determinism.
table.sort(languages)
for _, supples in pairs(supplements) do
table.sort(supplements)
end
end
%define create_lang_packages()\
%{lua:\
local languages = rpm.expand("%1")\
string.gsub(languages, "(%a+)",\
function(i) print(rpm.expand("%lang_package "..i.."")) end)}\
%{nil}
-- Compute the Supplements: list for a language, based on the regions.
local function compute_supplements(lang)
result = "langpacks-" .. lang
regions = supplements[lang]
if regions ~= nil then
for i = 1, #regions do
result = result .. " or langpacks-" .. lang .. "_" .. regions[i]
end
end
return result
end
%create_lang_packages %language_list
-- Emit the definition of a language pack package.
local function lang_package(lang)
local suppl = compute_supplements(lang)
print(rpm.expand([[
%define require_langpacks()\
%{lua:\
local languages = rpm.expand("%1")\
string.gsub(languages, "(%a+)",\
function(i) print(rpm.expand("Requires: %{name}-langpack-"..i.." = %{version}-%{release}\\n")) end)}\
%{nil}
%package langpack-]]..lang..[[
Summary: Locale data for ]]..lang..[[
Provides: glibc-langpack = %{version}-%{release}
Requires: %{name} = %{version}-%{release}
Requires: %{name}-common = %{version}-%{release}
Supplements: (glibc = %{version}-%{release} and (]]..suppl..[[))
%description langpack-]]..lang..[[
The glibc-langpack-]]..lang..[[ package includes the basic information required
to support the ]]..lang..[[ language in your applications.
%ifnarch %{auxarches}
%files -f langpack-]]..lang..[[.filelist langpack-]]..lang..[[
%defattr(-,root,root)
%endif
]]))
end
for i = 1, #languages do
lang_package(languages[i])
end
}
# The glibc-all-langpacks provides the virtual glibc-langpack,
# and thus satisfies glibc's requirement for installed locales.
@ -720,9 +802,9 @@ Group: System Environment/Base
Requires: %{name}%{_isa} = %{version}-%{release}
%description -n nss_nis
The nss_nis, nss_nisplus, and nss_compat Name Service Switch modules
uses the Network Information System (NIS) to obtain user, group, host
name, and other data.
The nss_nis and nss_nisplus Name Service Switch modules uses the
Network Information System (NIS) to obtain user, group, host name, and
other data.
%package -n nss_hesiod
Summary: Name Service Switch (NSS) module using Hesiod
@ -863,9 +945,74 @@ microbenchmark tests on the system.
%patch0060 -p1
%patch2036 -p1
%patch2037 -p1
%patch2038 -p1
%patch2110 -p1
%patch2112 -p1
%patch0061 -p1
%patch61 -p1
%patch62 -p1
%patch63 -p1
%patch64 -p1
%patch69 -p1
%patch77 -p1
%patch79 -p1
%patch80 -p1
%patch81 -p1
%patch82 -p1
%patch83 -p1
%patch85 -p1
%patch86 -p1
%patch87 -p1
%patch88 -p1
%patch89 -p1
%patch94 -p1
%patch97 -p1
%patch98 -p1
%patch99 -p1
%patch100 -p1
%patch101 -p1
%patch102 -p1
%patch103 -p1
%patch104 -p1
%patch105 -p1
%patch106 -p1
%patch107 -p1
%patch109 -p1
%patch110 -p1
%patch111 -p1
%patch112 -p1
%patch114 -p1
%patch115 -p1
%patch116 -p1
%patch117 -p1
%patch118 -p1
%patch119 -p1
%patch120 -p1
%patch121 -p1
%patch122 -p1
%patch123 -p1
%patch124 -p1
%patch125 -p1
%patch126 -p1
%patch127 -p1
%patch128 -p1
%patch129 -p1
%patch130 -p1
%patch131 -p1
%patch132 -p1
%patch133 -p1
%patch134 -p1
%patch135 -p1
%patch136 -p1
%patch137 -p1
%patch138 -p1
%patch139 -p1
%patch140 -p1
%patch141 -p1
%patch142 -p1
%patch151 -p1
%patch152 -p1
%patch153 -p1
%patch154 -p1
##############################################################################
# %%prep - Additional prep required...
@ -1012,7 +1159,7 @@ AddOns=`echo */configure | sed -e 's!/configure!!g;s!\(nptl\|powerpc-cpu\)\( \|$
# Build glibc in `build-%{target}$1', passing the rest of the arguments
# as CFLAGS to the build (not the same as configure CFLAGS). Several
# global values are used to determine build flags, add-ons, kernel
# version, multiarch support, system tap support, etc.
# version, system tap support, etc.
##############################################################################
build()
{
@ -1030,14 +1177,14 @@ build()
--enable-add-ons=$AddOns \
--with-headers=%{_prefix}/include $EnableKernel --enable-bind-now \
--build=%{target} \
%ifarch %{multiarcharches}
--enable-multi-arch \
%endif
--enable-stack-protector=strong \
--enable-tunables \
--enable-obsolete-rpc \
--enable-systemtap \
${core_with_options} \
%ifarch %{ix86}
--disable-multi-arch \
%endif
%ifarch %{lock_elision_arches}
--enable-lock-elision \
%endif
@ -1629,18 +1776,18 @@ for module in db nis nisplus compat hesiod files dns; do
grep -E "/libnss_$module(\.so\.[0-9.]+|-[0-9.]+\.so)$" \
rpm.filelist > nss_$module.filelist
done
# nis includes nisplus and compat
cat nss_nisplus.filelist nss_compat.filelist >> nss_nis.filelist
# nis includes nisplus
cat nss_nisplus.filelist >> nss_nis.filelist
# Symlinks go into the nss-devel package (instead of the main devel
# package).
grep '/libnss_[a-z]*\.so$' devel.filelist > nss-devel.filelist
# /var/db/Makefile goes into nss_hesiod, remove the other files from
# /var/db/Makefile goes into nss_db, remove the other files from
# the main and devel file list.
sed -i -e '\,/libnss_.*\.so[0-9.]*$,d' \
-e '\,/var/db/Makefile,d' \
rpm.filelist devel.filelist
# Restore the built-in NSS modules.
cat nss_files.filelist nss_dns.filelist >> rpm.filelist
cat nss_files.filelist nss_dns.filelist nss_compat.filelist >> rpm.filelist
# Prepare the libcrypt-related file lists.
grep '/libcrypt-[0-9.]*.so$' rpm.filelist > libcrypt.filelist
@ -1786,9 +1933,7 @@ find_debuginfo_args="$find_debuginfo_args \
-l nosegneg.filelist"
%endif
%endif
eval /usr/lib/rpm/find-debuginfo.sh \
"$find_debuginfo_args" \
-o debuginfo.filelist
/usr/lib/rpm/find-debuginfo.sh $find_debuginfo_args -o debuginfo.filelist
# List all of the *.a archives in the debug directory.
list_debug_archives()
@ -2239,9 +2384,9 @@ rm -f *.filelist*
%endif
%files -f nss_db.filelist -n nss_db
/var/db/Makefile
%files -f nss_nis.filelist -n nss_nis
%files -f nss_hesiod.filelist -n nss_hesiod
/var/db/Makefile
%doc hesiod/README.hesiod
%files -f nss-devel.filelist nss-devel
@ -2270,6 +2415,85 @@ rm -f *.filelist*
%endif
%changelog
* Wed Jan 17 2018 Florian Weimer <fweimer@redhat.com> - 2.25-13
- PTHREAD_STACK_MIN is too small on x86-64 (#1527887)
- CVE-2018-1000001: Make getcwd fail if it cannot obtain an absolute path
(#1533837)
- CVE-2017-16997: Check for empty tokens before dynamic string token
expansion in the dynamic linker (#1526866)
- CVE-2017-15804: glob: Fix overflow in GLOB_TILDE unescaping (swbz#22332)
- CVE-2017-15670: glob: Fix one-byte overflow (#1504807)
- CVE-2017-15671: glob: Fix memory leak (#1504807)
- Auto-sync with upstream branch release/2.25/master,
commit edcf13e25c1559558a6f12ff5a71d4136a39235e:
- nss_files: Avoid large buffers with many host addresses (swbz#22078)
- nss_files: Use struct scratch_buffer for gethostbyname (swbz#18023)
- posix: Fix improper assert in Linux posix_spawn (BZ#22273)
- Don't use IFUNC resolver for longjmp or system in libpthread (swbz#21041)
- x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve (swbz#21265)
* Wed Oct 11 2017 Florian Weimer <fweimer@redhat.com> - 2.25-12
- Support an arbitrary number of search domains (#168253)
- Detect and apply /etc/resolv.conf changes in libresolv (#1374239)
- CVE-2015-5180: DNS stub resolver crash with crafted record type (#1251403)
- Auto-sync with upstream branch release/2.25/master,
commit 595f287ae092dd973f6d5fb748cbe31ef7d82b2d.
* Mon Oct 09 2017 Florian Weimer <fweimer@redhat.com> - 2.25-11
- Move /var/db/Makefile to nss_db (#1498900)
- Move nss_compat to the main glibc package (#1400538)
- iconv: Support the IBM858 character set (#1416405)
- Auto-sync with upstream branch release/2.25/master,
commit 864ea5f6579edfee41f7d4a778807045b5aff66b:
- nss: Fix pointer alignment/endianness issue in group merging (#1471985)
- elf: Place $(elf-objpfx)sofini.os last (swbz#22051)
* Mon Aug 28 2017 Florian Weimer <fweimer@redhat.com> - 2.25-10
- Auto-sync with upstream release/2.25/master,
commit bc5ace67fe9823757532e0273f6c1cdfda065433:
- mutex: Fix robust mutex lock acquire (#1485900)
- rwlock: Fix explicit hand-over (swbz#21298)
* Tue Aug 22 2017 Florian Weimer <fweimer@redhat.com> - 2.25-9
- Auto-sync with upstream release/2.25/master,
commit 02aaa3c749bf18a3dbafff4c1f0180f135cad7ed:
- assert: Support types without operator== (int) (#1483005)
* Wed Aug 16 2017 Florian Weimer <fweimer@redhat.com> - 2.25-8
- Disable SSE2 usage on i686 (#1471427)
- Auto-sync with upstream release/2.25/master,
commit 47db584c74e2bbcf1ba55e62d949c1a738da5e0a:
- CVE-2017-12132: Reduce EDNS payload size to 1200 bytes (#1477530)
- Call exit directly in clone (swbz#21512)
- assert: Suppress pedantic warning caused by statement expression (swbz#21242)
- x86-64: Use _dl_runtime_resolve_opt only with AVX512F (swbz#21871)
- powerpc: Fix logbl on power7 (swbz#21280)
- Avoid .symver on common symbols (swbz#21666)
- aarch64: Use hidden __GI__dl_argv in rtld startup code
* Thu Jul 06 2017 Florian Weimer <fweimer@redhat.com> - 2.25-7
- Auto-sync with upstream release/2.25/master,
commit 49f97e641e4e84a42246655d30adbc4756e67114:
- x86-64: Align the stack in __tls_get_addr (#1440287)
* Tue Jun 20 2017 Florian Weimer <fweimer@redhat.com> - 2.25-6
- Auto-sync with upstream release/2.25/master,
commit adc7e06fb412a2a1ee52f8cb788caf436335b9f3, fixing:
- CVE-2017-1000366: Avoid large allocas in the dynamic linker (#1462820)
- Ignore and remove LD_HWCAP_MASK for AT_SECURE programs (swbz#21209)
- Correct collation rules for Malayalam (swbz#19922, swbz#19919)
- fork: Remove bogus parent PID assertions (swbz#21386)
* Mon Jun 05 2017 Arjun Shankar <arjun.is@lostca.se> - 2.25-5
- Auto-sync with upstream release/2.25/master,
commit 34b6f41c14d09fe627c6a6224880d76d0959079e, fixing:
- Fix test-math-vector-sincos.h aliasing (ffe308e)
* Thu Mar 02 2017 Florian Weimer <fweimer@redhat.com> - 2.25-4
- Auto-sync with upstream release/2.25/master,
commit 69e0a87cc4c570e3b7218392fc3e743b5bddcce2, fixing:
- Build all DSOs with BIND_NOW (#1406731)
* Wed Mar 1 2017 Jakub Hrozek <jhrozek@redhat.com> - 2.25-3
- NSS: Prefer sss service for passwd, group databases (#1427646)

View File

@ -1 +1 @@
SHA512 (glibc-2.25-3-g93cf93e.tar.gz) = 2fc0b4e1edade43ba7cd59a6eff0eb77058a742ae6b112e76ddde7c5ac951d361f5da74f7cf1bf5b404e1ca1439609cc49a26a2cd2143bec008ffbf2aecafd51
SHA512 (glibc-2.25-123-gedcf13e25c.tar.gz) = b9eb5ae4c2f1f26d5bc9a21e2f59e700cf5a3fe01501e19c5da762e92e493fd0da9476536b4e0724cb0751cb0cb6884d91a26c4a6a2c32a4d1154f5a30f4dbea