From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=ZtsR8afj; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 2A2B95A0772 for ; Mon, 05 Jan 2026 08:53:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1767599619; bh=UYym0kLBNIx1FcKrn8GrX16eZXFh6tUAb6cY1ENQqUw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZtsR8afjtilrNAoz+gJfnJP0mOxGwHEfhgaViloPKJjgkbEWWJAaAZArMqDpQM4CZ WhHudGv494zvKB2mBD5/cT6xb7jYoIL45taCOtlyD+8OILWUU1C4E/3u5oLhuFC20A aqW316alsfzOVFLYYYgMNQlMrPCs+vLoOK4QKPcVly5Ni/orlO7fD7FfUm+pNFiBzZ kczuiLnfcGPeQ7AMxhnWxxuU5kAFXTRmOXFvzXObs9xV3sT4MlE0gpgU0Dzg9VCPgi jfQaGHRd9/MYIb0pfWab1Va8h5t5Sd+9/UvpKBs32JfQTuXsYAQ+25X3ymVTJtNW8n XAVnGDwdAXkmA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dl64M1YXzz4wCy; Mon, 05 Jan 2026 18:53:39 +1100 (AEDT) From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH 3/5] treewide: Don't rely on terminator records in ip[46].dns arrays Date: Mon, 5 Jan 2026 18:53:35 +1100 Message-ID: <20260105075337.1724962-4-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260105075337.1724962-1-david@gibson.dropbear.id.au> References: <20260105075337.1724962-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: FP43DGRZDKOI4ARDKPSZVVH3J4EOX52J X-Message-ID-Hash: FP43DGRZDKOI4ARDKPSZVVH3J4EOX52J X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: In our arrays of DNS resolvers to pass to the guest we use a blank entry to indicate the end of the list. We rely on this when scanning the array, not having separate bounds checking. clang-tidy 21.1.7 has fancier checking for array overruns in loops, but it's not able to reason that there's always a terminating entry, so complains. Indeed, it's correct to do so in this case. Although we allow space in the arrays for the terminator (size MAXNS + 1), add_dns[46]() check only for idx >= ARRAY_SIZE() before adding an entry. This allows it to consume the last slot with a "real" entry, meaning the places where we scan really could overrun. Fix the bug, and make it easier to reason about (for both clang-tidy and people) by using ARRAY_SIZE() base bounds checking. Treat the terminator explicitly as an early exit case using 'break'. Signed-off-by: David Gibson --- conf.c | 8 ++++++-- dhcp.c | 4 +++- dhcpv6.c | 4 +++- ndp.c | 4 +++- passt.h | 4 ++-- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/conf.c b/conf.c index 84ae12b2..ceb9aa55 100644 --- a/conf.c +++ b/conf.c @@ -1159,7 +1159,9 @@ static void conf_print(const struct ctx *c) buf4, sizeof(buf4))); } - for (i = 0; !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); i++) { + for (i = 0; i < ARRAY_SIZE(c->ip4.dns); i++) { + if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i])) + break; if (!i) info("DNS:"); inet_ntop(AF_INET, &c->ip4.dns[i], buf4, sizeof(buf4)); @@ -1197,7 +1199,9 @@ static void conf_print(const struct ctx *c) buf6, sizeof(buf6))); dns6: - for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i]); i++) { + for (i = 0; i < ARRAY_SIZE(c->ip6.dns); i++) { + if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i])) + break; if (!i) info("DNS:"); inet_ntop(AF_INET6, &c->ip6.dns[i], buf6, sizeof(buf6)); diff --git a/dhcp.c b/dhcp.c index 6b9c2e3b..1ff8cba9 100644 --- a/dhcp.c +++ b/dhcp.c @@ -430,7 +430,9 @@ int dhcp(const struct ctx *c, struct iov_tail *data) } for (i = 0, opts[6].slen = 0; - !c->no_dhcp_dns && !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); i++) { + !c->no_dhcp_dns && i < ARRAY_SIZE(c->ip4.dns); i++) { + if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i])) + break; ((struct in_addr *)opts[6].s)[i] = c->ip4.dns[i]; opts[6].slen += sizeof(uint32_t); } diff --git a/dhcpv6.c b/dhcpv6.c index e4df0db5..d94be23a 100644 --- a/dhcpv6.c +++ b/dhcpv6.c @@ -425,7 +425,9 @@ static size_t dhcpv6_dns_fill(const struct ctx *c, char *buf, int offset) if (c->no_dhcp_dns) goto search; - for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i]); i++) { + for (i = 0; i < ARRAY_SIZE(c->ip6.dns); i++) { + if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i])) + break; if (!i) { srv = (struct opt_dns_servers *)(buf + offset); offset += sizeof(struct opt_hdr); diff --git a/ndp.c b/ndp.c index eb9e3139..1f2bcb0c 100644 --- a/ndp.c +++ b/ndp.c @@ -285,7 +285,9 @@ static void ndp_ra(const struct ctx *c, const struct in6_addr *dst) size_t dns_s_len = 0; int i, n; - for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[n]); n++); + for (n = 0; n < ARRAY_SIZE(c->ip6.dns); n++) + if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[n])) + break; if (n) { struct opt_rdnss *rdnss = (struct opt_rdnss *)ptr; *rdnss = (struct opt_rdnss) { diff --git a/passt.h b/passt.h index 79d01ddb..87da76d3 100644 --- a/passt.h +++ b/passt.h @@ -91,7 +91,7 @@ struct ip4_ctx { struct in_addr guest_gw; struct in_addr map_host_loopback; struct in_addr map_guest_addr; - struct in_addr dns[MAXNS + 1]; + struct in_addr dns[MAXNS]; struct in_addr dns_match; struct in_addr our_tap_addr; @@ -132,7 +132,7 @@ struct ip6_ctx { struct in6_addr guest_gw; struct in6_addr map_host_loopback; struct in6_addr map_guest_addr; - struct in6_addr dns[MAXNS + 1]; + struct in6_addr dns[MAXNS]; struct in6_addr dns_match; struct in6_addr our_tap_ll; -- 2.52.0