NetBSD Problem Report #60488
From www@netbsd.org Thu Jul 23 19:31:23 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature RSA-PSS (2048 bits) client-digest SHA256)
(Client CN "mail.netbsd.org", Issuer "YR2" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 51E6D1A923B
for <gnats-bugs@gnats.NetBSD.org>; Thu, 23 Jul 2026 19:31:23 +0000 (UTC)
Message-Id: <20260723193121.B10CD1A923C@mollari.NetBSD.org>
Date: Thu, 23 Jul 2026 19:31:21 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: nd6: two-byte buffer overread in source/target linkaddr options
X-Send-Pr-Version: www-1.0
X-From4GNATS: "campbell+netbsd@mumble.net via gnats" <gnats-admin@NetBSD.org>
>Number: 60488
>Category: kern
>Synopsis: nd6: two-byte buffer overread in source/target linkaddr options
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: needs-pullups
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Jul 23 19:35:00 +0000 2026
>Closed-Date:
>Last-Modified: Thu Jul 23 22:09:05 +0000 2026
>Originator: Taylor R Campbell
>Release: current, 11, 10, 9, ...
>Organization:
The NeighBSD Discoverflow, Inc.
>Environment:
>Description:
In both nd6_ns_input and nd6_na_input, the option length in
struct nd_opt_hdr::nd_opt_len is taken to be the length of the
payload _excluding_ the headder, but what the protocol
specifies, and what is verified in nd6.c, is that nd_opt_len is
the length of the whole option _including_ the header:
185 if (ndopts.nd_opts_src_lladdr) {
186 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
187 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
188 }
https://nxr.netbsd.org/xref/src/sys/netinet6/nd6_nbr.c?r=1.186#185
678 if (ndopts.nd_opts_tgt_lladdr != NULL) {
679 struct ifnet *ifp_ll;
680 struct psref psref_ll;
681
682 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
683 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
https://nxr.netbsd.org/xref/src/sys/netinet6/nd6_nbr.c?r=1.186#678
This lladdrlen is later used as a source buffer size for
sockaddr_dl_init:
322 if (lladdr != NULL)
323 sdlp = sockaddr_dl_init(&sdl, sizeof(sdl),
324 ifp->if_index, ifp->if_type,
325 NULL, 0, lladdr, lladdrlen);
https://nxr.netbsd.org/xref/src/sys/netinet6/nd6_nbr.c?r=1.186#322
716 if (lladdr != NULL)
717 sdlp = sockaddr_dl_init(&sdl, sizeof(sdl),
718 ifp->if_index, ifp->if_type,
719 NULL, 0, lladdr, lladdrlen);
https://nxr.netbsd.org/xref/src/sys/netinet6/nd6_nbr.c?r=1.186#716
That can lead sockaddr_dl_init to read past the verified end of
the option buffer by two bytes.
Note: The ND_OPT_TARGET_LINKADDR case appears to check the
lladdrlen against ((ifp->if_addrlen + 2 + 7) & ~7) exactly, so
there is probably no overread in that case.
>How-To-Repeat:
convince NetBSD to process an nd6 packet with
ND_OPT_TARGET_LINKADDR
>Fix:
subtract two from lladdrlen
>Release-Note:
>Audit-Trail:
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/60488 CVS commit: src/sys/netinet6
Date: Thu, 23 Jul 2026 19:52:48 +0000
Module Name: src
Committed By: riastradh
Date: Thu Jul 23 19:52:48 UTC 2026
Modified Files:
src/sys/netinet6: nd6_nbr.c
Log Message:
nd6: Avoid buffer overread of link-layer address options.
PR kern/60488: nd6: two-byte buffer overread in source/target
linkaddr options
To generate a diff of this commit:
cvs rdiff -u -r1.186 -r1.187 src/sys/netinet6/nd6_nbr.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/60488 CVS commit: src/sys/netinet6
Date: Thu, 23 Jul 2026 20:25:49 +0000
Module Name: src
Committed By: riastradh
Date: Thu Jul 23 20:25:49 UTC 2026
Modified Files:
src/sys/netinet6: nd6_nbr.c
Log Message:
nd6: Redo previous avoidance of buffer overread.
Previous change invalidated two checks of the length:
285 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
286 nd6log(LOG_INFO, "lladdrlen mismatch for %s "
287 "(if %d, NS packet %d)\n",
288 IN6_PRINT(ip6buf, &taddr6),
289 ifp->if_addrlen, lladdrlen - 2);
290 goto bad;
291 }
https://nxr.netbsd.org/xref/src/sys/netinet6/nd6_nbr.c?r=1.186#285
685 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
686 nd6log(LOG_INFO, "lladdrlen mismatch for %s "
687 "(if %d, NA packet %d)\n",
688 IN6_PRINT(ip6buf, &taddr6),
689 ifp->if_addrlen, lladdrlen - 2);
690 goto bad;
691 }
https://nxr.netbsd.org/xref/src/sys/netinet6/nd6_nbr.c?r=1.186#685
Even if we readjust it for the checks, it's still basically wrong:
the buffer may have extra padding in there to round it up to a
multiple of eight bytes, so we have to know what the correct length
is for the interface anyway. And we do: it's ifp->if_addrlen. So
just use that, after verifying the option has enough space for an
address of that length.
To make sure there are no accidental references to the option length
(including header) lying around, I've renamed the variable lladdrlen
to lladdroptlen.
PR kern/60488: nd6: two-byte buffer overread in source/target
linkaddr options
To generate a diff of this commit:
cvs rdiff -u -r1.187 -r1.188 src/sys/netinet6/nd6_nbr.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: open->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Thu, 23 Jul 2026 22:09:05 +0000
State-Changed-Why:
fixed in HEAD, needs pullup-11, pullup-10, pullup-9
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.