NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/60488: nd6: two-byte buffer overread in source/target linkaddr options



>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:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 23 19:35:00 +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




Home | Main Index | Thread Index | Old Index