aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2020-01-21 17:38:15 +0100
committerFlorian Weimer <fweimer@redhat.com>2020-02-14 08:14:07 +0100
commitfa00db0a6eb755837ae5d413515e0da582b304f3 (patch)
treea93122a684888db52a32b30868c0733ed229a094
parentdd0b4df329ff7ff2a656404db271c8ee8379ff9d (diff)
downloadglibc-fa00db0a6eb755837ae5d413515e0da582b304f3.tar
glibc-fa00db0a6eb755837ae5d413515e0da582b304f3.tar.gz
glibc-fa00db0a6eb755837ae5d413515e0da582b304f3.tar.bz2
glibc-fa00db0a6eb755837ae5d413515e0da582b304f3.zip
resolv: Fix ABA race in /etc/resolv.conf change detection [BZ #25420]
__resolv_conf_get_current should only record the initial file change data if after verifying that file just read matches the original measurement. Fixes commit aef16cc8a4c670036d45590877 ("resolv: Automatically reload a changed /etc/resolv.conf file [BZ #984]"). Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
-rw-r--r--resolv/resolv_conf.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index bdd2ebb909..29a1f4fb94 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -136,18 +136,25 @@ __resolv_conf_get_current (void)
{
/* Parse configuration while holding the lock. This avoids
duplicate work. */
- conf = __resolv_conf_load (NULL, NULL);
+ struct file_change_detection after_load;
+ conf = __resolv_conf_load (NULL, &after_load);
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->file_resolve_conf = initial;
+ /* Update file change detection data, but only if it matches
+ the initial measurement. This avoids an ABA race in case
+ /etc/resolv.conf is temporarily replaced while the file
+ is read (after the initial measurement), and restored to
+ the initial version later. */
+ if (file_is_unchanged (&initial, &after_load))
+ global_copy->file_resolve_conf = after_load;
+ else
+ /* If there is a discrepancy, trigger a reload during the
+ next use. */
+ global_copy->file_resolve_conf.size = -1;
}
}