Source: connman
Version: 2.0-2
Severity: important
Tags: security upstream patch

Hi,

CVE-2026-115863 has no Debian bug yet, so I am filing this one so that the
fix does not get lost.

get_domains() in gdhcp/client.c copies a fixed NS_MAXDNAME bytes from the
DHCPv6 DOMAIN_LIST option into a stack buffer, regardless of the option
length, and then walks the labels with no bound. It is reached from a
DHCPv6 reply, and connmand runs as root. Per the CVE description, an
on-link attacker can trigger it without authentication.

The function is the same in 2.0-2 (sid), 1.44-3 (trixie) and 1.41-3
(bookworm). Upstream HEAD 9e46e4a0, the latest commit I could fetch, does
not change it.

Andrei Miu posted a fix to the connman list on 2026-10-23 (the thread is
linked from the tracker entry). The only reply so far is an unrelated form
letter, and it has not been applied upstream. I have attached that patch
unchanged.

What I checked:

- The patch applies to all three versions, with line offsets only on 1.44-3
and 1.41-3.
- I extracted the function before and after the patch and ran eight valid
DOMAIN_LIST values through it under ASan/UBSan, on all three versions:
single names, 63-byte labels, and lists of up to 40 names. The output was
identical before and after, with no sanitizer reports.
- From reading the patch, the copy is now bounded by the option length, the
buffer is NUL-terminated, and the label walk stops at the end of the copied
data.

What I did not test: I did not reproduce the overflow, and I did not run
malformed input through the patched code. I also did not do a full package
build or a run against a real DHCPv6 server. The function was compiled on
its own with a minimal stand-in for the GList calls.

Regards,
Sumit Verma
From 9c2e3f0f85370ecee33e09bfce1b8aa8c1c554d4 Mon Sep 17 00:00:00 2001
From: Andrei Miu <[email protected]>
Date: Thu, 23 Oct 2026 10:00:00 +0200
Subject: [PATCH] gdhcp: fix stack buffer overflow in get_domains()

get_domains() copied a fixed NS_MAXDNAME (1025) bytes from the
DOMAIN_LIST (option 24) value into the 1026-byte stack buffer
dns_name regardless of the actual option length, and then walked
DNS labels with an unbounded 'c += jump + 1' loop. A crafted
DHCPv6 REPLY with a DOMAIN_LIST option of >= 1025 non-zero bytes
makes the label walk leave the buffer and read/write '.' past its
end in attacker-chosen strides (stride = label byte + 1), i.e.
out-of-bounds writes into the canary/saved registers territory of
connmand (running as root). On stack-zeroing kernels the walk
performs an out-of-bounds read instead and exits at the first
zero byte.

DHCPv6 REPLY messages are unauthenticated and the transaction id
and CLIENTID DUID are observable on the wire (INFORMATION-REQUEST
is multicast to ff02::1:2), so any on-link attacker can trigger
this.

Fix by bounding the copy to the remaining option length,
NUL-terminating the buffer, and stopping the label walk at the
end of the copied data.

Fixes: bb06c47101ca24 ("gdhcp: Domain search list DHCPv6 option is checked")
---
 gdhcp/client.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/gdhcp/client.c b/gdhcp/client.c
index 976773ac..b594e349 100644
--- a/gdhcp/client.c
+++ b/gdhcp/client.c
@@ -2217,13 +2217,25 @@ static GList *get_domains(int maxlen, unsigned char *value)
 		return NULL;
 
 	while (pos < maxlen) {
-		strncpy(dns_name, (char *)&value[pos], NS_MAXDNAME);
+		int name_len = maxlen - pos;
+		char *name_end;
 
+		if (name_len > NS_MAXDNAME)
+			name_len = NS_MAXDNAME;
+
+		memcpy(dns_name, &value[pos], name_len);
+		dns_name[name_len] = '\0';
+
+		name_end = dns_name + name_len;
 		c = (unsigned char *)dns_name;
 		while (c && *c) {
 			int jump;
+			char *label = (char *)c;
+
 			jump = *c;
-			*c = '.';
+			if (label + jump + 1 > name_end)
+				break;
+			*label = '.';
 			c += jump + 1;
 		}
 		list = g_list_prepend(list, g_strdup(&dns_name[1]));
-- 
2.55.0

Reply via email to