Fix incorrect double-checked locking related to _res_hconf.initialized.

_res_hconf.initialized was not suitable for use in a multi-threaded
environment due to the lack of atomics and memory barriers.  Use of it was
also unnecessary because _res_hconf_init did the right thing by using
__libc_once.  This patch fixes the glibc-internal uses by just calling
_res_hconf_init unconditionally, and switches to a release MO atomic store
for _res_hconf.initialized to fix the glibc side of the synchronization
problem (which will maintain backward compatibility, but cannot fix the
lack of acquire MO on any glibc-external loads).

	[BZ #20477]
	* resolv/res_hconf.c (do_init): Use atomic access.
	* resolv/res_hconf.h: Add comments.
	* nscd/aicache.c (addhstaiX): Call _res_hconf_init unconditionally.
	* nss/getXXbyYY_r.c (REENTRANT_NAME): Likewise.
	* sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise.
This commit is contained in:
Torvald Riegel 2016-08-17 13:56:11 +02:00
parent b65f0b7b2e
commit 6f9d4f595e
6 changed files with 23 additions and 7 deletions

View File

@ -1,3 +1,12 @@
2016-08-18 Torvald Riegel <triegel@redhat.com>
[BZ #20477]
* resolv/res_hconf.c (do_init): Use atomic access.
* resolv/res_hconf.h: Add comments.
* nscd/aicache.c (addhstaiX): Call _res_hconf_init unconditionally.
* nss/getXXbyYY_r.c (REENTRANT_NAME): Likewise.
* sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise.
2016-08-18 Stefan Liebler <stli@linux.vnet.ibm.com>
* sysdeps/ieee754/dbl-64/k_rem_pio2.c (__kernel_rem_pio2):

View File

@ -101,8 +101,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
nip = hosts_database;
/* Initialize configurations. */
if (__glibc_unlikely (!_res_hconf.initialized))
_res_hconf_init ();
_res_hconf_init ();
if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;

View File

@ -274,8 +274,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
}
#endif /* need _res */
#ifdef NEED__RES_HCONF
if (!_res_hconf.initialized)
_res_hconf_init ();
_res_hconf_init ();
#endif /* need _res_hconf */
void *tmp_ptr = fct.l;

View File

@ -348,7 +348,8 @@ do_init (void)
arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval);
}
_res_hconf.initialized = 1;
/* See comments on the declaration of _res_hconf. */
atomic_store_release (&_res_hconf.initialized, 1);
}

View File

@ -25,6 +25,15 @@
struct hconf
{
/* We keep the INITIALIZED member only for backwards compatibility. New
code should just call _res_hconf_init unconditionally. For this field
to be used safely, users must ensure that either (1) a call to
_res_hconf_init happens-before any load from INITIALIZED, or (2) an
assignment of zero to INITIALIZED happens-before any load from it, and
these loads use acquire MO if the intent is to skip calling
_res_hconf_init if the load returns a nonzero value. Such acquire MO
loads will then synchronize with the release MO store to INITIALIZED
in do_init in res_hconf.c; see pthread_once for more detail. */
int initialized;
int unused1;
int unused2[4];

View File

@ -816,8 +816,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
nip = __nss_hosts_database;
/* Initialize configurations. */
if (__glibc_unlikely (!_res_hconf.initialized))
_res_hconf_init ();
_res_hconf_init ();
if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;