From 253b34d8ac08e9443d5ab19c5528ee85118ddd5a Mon Sep 17 00:00:00 2001
From: dongshengyuan <545258830@qq.com>
Date: Thu, 13 Aug 2026 10:54:02 +0800
Subject: [PATCH] resolvconf: reject malformed stdin without changing link
state
The resolvconf compatibility parser ignored errors from
nameserver, domain, and search lines. If one of those lines was
malformed, resolvectl could still send the partially parsed
configuration to resolved and overwrite the previous link state.
Reproducer:
IF=enp1s0
TMP="$(mktemp -d)"
ln -s "$(command -v resolvectl)" "$TMP/resolvconf"
sudo resolvectl dns "$IF" 1.1.1.1
sudo resolvectl domain "$IF" keep.example
resolvectl domain "$IF"
printf 'nameserver 1.1.1.1\nsearch "unterminated\n' |
sudo "$TMP/resolvconf" -a "$IF" || true
resolvectl domain "$IF"
Before:
The malformed search line was ignored and the previous domain
was cleared:
Link 2 (enp1s0): keep.example
Link 2 (enp1s0):
After:
The malformed input fails before updating resolved, so
keep.example remains configured.
Follow-up for: 097f130731513bd934ed74975ac34070197614af
---
NEWS | 3 +++
man/resolvectl.xml | 3 ++-
src/resolve/resolvconf-compat.c | 8 ++++++--
test/units/TEST-75-RESOLVED.sh | 3 +++
4 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/NEWS b/NEWS
index ccadaa256d..c5686b929f 100644
--- a/NEWS
+++ b/NEWS
@@ -454,6 +454,9 @@ CHANGES WITH 261:
Changes in systemd-resolved:
+ * The resolvconf compatibility mode now rejects malformed stdin input
+ and leaves the existing per-link DNS configuration unchanged.
+
* systemd-resolved will now read additional DNS resource record
definitions to resolve locally from JSON drop-in files in
{/etc,/run,/usr/local/lib,/usr/lib}/systemd/resolve/static.d/. This
diff --git a/man/resolvectl.xml b/man/resolvectl.xml
index e908345d48..fabd64e81e 100644
--- a/man/resolvectl.xml
+++ b/man/resolvectl.xml
@@ -564,7 +564,8 @@
DNS configuration data from its standard input. Relevant fields are nameserver and
domain/search. This command is mostly identical to invoking
resolvectl with a combination of and
- commands.
+ commands. If a relevant input line has invalid syntax, the command fails and leaves the existing
+ per-interface configuration unchanged.
diff --git a/src/resolve/resolvconf-compat.c b/src/resolve/resolvconf-compat.c
index d3ddec755a..dcac5c130e 100644
--- a/src/resolve/resolvconf-compat.c
+++ b/src/resolve/resolvconf-compat.c
@@ -116,7 +116,9 @@ static int parse_stdin(LookupType lookup_type) {
a = first_word(line, "nameserver");
if (a) {
- (void) parse_nameserver(a);
+ r = parse_nameserver(a);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resolv.conf nameserver line: %m");
continue;
}
@@ -124,7 +126,9 @@ static int parse_stdin(LookupType lookup_type) {
if (!a)
a = first_word(line, "search");
if (a) {
- (void) parse_search_domain(a);
+ r = parse_search_domain(a);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resolv.conf domain/search line: %m");
continue;
}
diff --git a/test/units/TEST-75-RESOLVED.sh b/test/units/TEST-75-RESOLVED.sh
index 707a6f3011..e3055616cb 100755
--- a/test/units/TEST-75-RESOLVED.sh
+++ b/test/units/TEST-75-RESOLVED.sh
@@ -273,6 +273,9 @@ manual_testcase_01_resolvectl() {
assert_in 'test-domain1.example.com' "$(resolvectl domain hoge)"
assert_in 'test-domain2.example.com' "$(resolvectl domain hoge)"
assert_in 'test-search-domain.example.com' "$(resolvectl domain hoge)"
+ resolvectl domain hoge keep.example
+ (! echo -e "nameserver 10.0.2.1\nsearch \"unterminated" | SYSTEMD_INVOKED_AS=resolvconf resolvectl -a hoge)
+ assert_in 'keep.example' "$(resolvectl domain hoge)"
# Tests for 'resolvconf -x'
echo nameserver 10.0.2.1 | SYSTEMD_INVOKED_AS=resolvconf resolvectl -x -a hoge