From: Lennart Poettering Date: Fri, 8 Dec 2017 15:51:46 +0000 (+0100) Subject: resolved: fix a minimal race, when reading /etc/resolv.conf X-Git-Tag: v236~21^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=043d3928780b474c38c3d7d0f5a5ef785fd7bc10;p=thirdparty%2Fsystemd.git resolved: fix a minimal race, when reading /etc/resolv.conf The user might replace a foreign /etc/resolv.conf with a symlink to one of ours between the time we did stat() and open the file. Hence, let's check the fstat() data right after opening the file, a second time. --- diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index b182f4319ed..a84b0fde1c7 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -32,9 +32,29 @@ #include "string-util.h" #include "strv.h" +static bool file_is_our_own(const struct stat *st) { + struct stat own1, own2; + + assert(st); + + /* Is it symlinked to our own file? */ + if (stat(PRIVATE_UPLINK_RESOLV_CONF, &own1) >= 0 && + st->st_dev == own1.st_dev && + st->st_ino == own1.st_ino) + return true; + + /* Is it symlinked to our own stub file? */ + if (stat(PRIVATE_STUB_RESOLV_CONF, &own2) >= 0 && + st->st_dev == own2.st_dev && + st->st_ino == own2.st_ino) + return true; + + return false; +} + int manager_read_resolv_conf(Manager *m) { _cleanup_fclose_ FILE *f = NULL; - struct stat st, own; + struct stat st; char line[LINE_MAX]; usec_t t; int r; @@ -61,16 +81,7 @@ int manager_read_resolv_conf(Manager *m) { if (t == m->resolv_conf_mtime) return 0; - /* Is it symlinked to our own file? */ - if (stat(PRIVATE_UPLINK_RESOLV_CONF, &own) >= 0 && - st.st_dev == own.st_dev && - st.st_ino == own.st_ino) - return 0; - - /* Is it symlinked to our own stub file? */ - if (stat(PRIVATE_STUB_RESOLV_CONF, &own) >= 0 && - st.st_dev == own.st_dev && - st.st_ino == own.st_ino) + if (file_is_our_own(&st)) return 0; f = fopen("/etc/resolv.conf", "re"); @@ -87,6 +98,9 @@ int manager_read_resolv_conf(Manager *m) { goto clear; } + if (file_is_our_own(&st)) + return 0; + dns_server_mark_all(m->dns_servers); dns_search_domain_mark_all(m->search_domains);