From 3a57ef91005472e5b4735b56dd19a3b4688ef250 Mon Sep 17 00:00:00 2001 From: florian Date: Fri, 2 Sep 2022 09:39:55 +0000 Subject: [PATCH] Write /etc/resolv.conf in a more atomic manner. There were few reports were /etc/resolv.conf would lose user-managed lines, possibly caused by a system crash. While here add a call to fsync(2) which might also help. input otto input & OK deraadt, kn --- sbin/resolvd/resolvd.c | 53 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/sbin/resolvd/resolvd.c b/sbin/resolvd/resolvd.c index eba39826122..c17c6bf5561 100644 --- a/sbin/resolvd/resolvd.c +++ b/sbin/resolvd/resolvd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resolvd.c,v 1.27 2022/09/01 13:24:28 martijn Exp $ */ +/* $OpenBSD: resolvd.c,v 1.28 2022/09/02 09:39:55 florian Exp $ */ /* * Copyright (c) 2021 Florian Obser * Copyright (c) 2021 Theo de Raadt @@ -569,7 +569,8 @@ solicit_dns_proposals(int routesock) void regen_resolvconf(char *why) { - int i, fd; + struct iovec iov[UIO_MAXIOV]; + int i, fd, len, iovcnt = 0; linfo("rebuilding: %s", why); @@ -578,9 +579,18 @@ regen_resolvconf(char *why) return; } + memset(iov, 0, sizeof(iov)); + #ifndef SMALL - if (unwind_running) - dprintf(fd, "nameserver 127.0.0.1 # resolvd: unwind\n"); + if (unwind_running) { + len = asprintf((char **)&iov[iovcnt].iov_base, + "nameserver 127.0.0.1 # resolvd: unwind\n"); + if (len < 0) { + lwarn("asprintf"); + goto err; + } + iov[iovcnt++].iov_len = len; + } #endif /* SMALL */ for (i = 0; i < ASR_MAXNS; i++) { @@ -589,7 +599,8 @@ regen_resolvconf(char *why) ifnam = if_indextoname(learned[i].if_index, ifnambuf); - dprintf(fd, "%snameserver %s # resolvd: %s\n", + len = asprintf((char **)&iov[iovcnt].iov_base, + "%snameserver %s # resolvd: %s\n", #ifndef SMALL unwind_running ? "#" : "", #else @@ -597,6 +608,11 @@ regen_resolvconf(char *why) #endif learned[i].ip, ifnam ? ifnam : ""); + if (len < 0) { + lwarn("asprintf"); + goto err; + } + iov[iovcnt++].iov_len = len; } } @@ -624,12 +640,31 @@ regen_resolvconf(char *why) *end = '\0'; if (strstr(line, "# resolvd: ")) continue; - dprintf(fd, "%s\n", line); + len = asprintf((char **)&iov[iovcnt].iov_base, "%s\n", + line); + if (len < 0) { + lwarn("asprintf"); + goto err; + } + iov[iovcnt++].iov_len = len; + if (iovcnt >= UIO_MAXIOV) { + lwarnx("too many user-managed lines"); + goto err; + } } free(line); fclose(fp); } + if (writev(fd, iov, iovcnt) == -1) { + lwarn("writev"); + goto err; + } + + if (fsync(fd) == -1) { + lwarn("fsync"); + goto err; + } if (rename(_PATH_RESCONF_NEW, _PATH_RESCONF) == -1) goto err; @@ -642,12 +677,16 @@ regen_resolvconf(char *why) } newkevent = 1; - return; + goto out; err: if (fd != -1) close(fd); unlink(_PATH_RESCONF_NEW); + out: + for (i = 0; i < iovcnt; i++) + free(iov[i].iov_base); + } int -- 2.20.1