commit 9dbf3a16d9e2ebfb707a7d7aae54301e51e11b4b Author: Andrey V. Elsukov Date: Thu Oct 14 09:24:21 2021 +0300 Introduce nd6_ifinfo() function that returns pointer to nd_ifinfo It does check that ifnet is valid and has initialized nd_ifinfo structure, otherwise NULL. Use it in several places to reduce the chance of possible page fault due to access to if_afdata that is already freed during domifdetach. diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 356f27f31c0f..03fb9f244c4c 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2108,12 +2108,14 @@ icmp6_reflect(struct mbuf *m, size_t off) ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); if (ia != NULL && !(ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) { + struct nd_ifinfo *ndi = nd6_ifinfo(m->m_pkthdr.rcvif); + src6 = ia->ia_addr.sin6_addr; srcp = &src6; - if (m->m_pkthdr.rcvif != NULL) { + if (ndi != NULL) { /* XXX: This may not be the outgoing interface */ - hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim; + hlim = ndi->chlim; } else hlim = V_ip6_defhlim; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index fe47049e772b..bba7388e2f69 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1558,9 +1558,10 @@ in6ifa_llaonifp(struct ifnet *ifp) struct epoch_tracker et; struct sockaddr_in6 *sin6; struct ifaddr *ifa; + struct nd_ifinfo *ndi; - - if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) + if ((ndi = nd6_ifinfo(ifp)) == NULL || + (ndi->flags & ND6_IFF_IFDISABLED) != 0) return (NULL); NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { @@ -1950,13 +1951,14 @@ in6_if_up(struct ifnet *ifp) int in6if_do_dad(struct ifnet *ifp) { + struct nd_ifinfo *ndi; if ((ifp->if_flags & IFF_LOOPBACK) != 0) return (0); if ((ifp->if_flags & IFF_MULTICAST) == 0) return (0); - if ((ND_IFINFO(ifp)->flags & - (ND6_IFF_IFDISABLED | ND6_IFF_NO_DAD)) != 0) + if ((ndi = nd6_ifinfo(ifp)) == NULL || + (ndi->flags & (ND6_IFF_IFDISABLED | ND6_IFF_NO_DAD)) != 0) return (0); return (1); } @@ -2476,8 +2478,8 @@ in6_domifdetach(struct ifnet *ifp, void *aux) mld_domifdetach(ifp); scope6_ifdetach(ext->scope6_id); - nd6_ifdetach(ifp, ext->nd_ifinfo); lltable_free(ext->lltable); + nd6_ifdetach(ifp, ext->nd_ifinfo); COUNTER_ARRAY_FREE(ext->in6_ifstat, sizeof(struct in6_ifstat) / sizeof(uint64_t)); free(ext->in6_ifstat, M_IFADDR); diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 81cd24823f10..94650dc1f9f3 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -672,8 +672,9 @@ void in6_ifattach(struct ifnet *ifp, struct ifnet *altifp) { struct in6_ifaddr *ia; + struct nd_ifinfo *ndi; - if (ifp->if_afdata[AF_INET6] == NULL) + if ((ndi = nd6_ifinfo(ifp)) == NULL) return; /* * quirks based on interface type @@ -686,8 +687,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp) * linklocals for 6to4 interface, but there's no use and * it is rather harmful to have one. */ - ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; - ND_IFINFO(ifp)->flags |= ND6_IFF_NO_DAD; + ndi->flags &= ~ND6_IFF_AUTO_LINKLOCAL; + ndi->flags |= ND6_IFF_NO_DAD; break; default: break; @@ -720,8 +721,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp) /* * assign a link-local address, if there's none. */ - if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && - ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) { + if ((ndi->flags & ND6_IFF_IFDISABLED) == 0 && + (ndi->flags & ND6_IFF_AUTO_LINKLOCAL) != 0) { struct epoch_tracker et; NET_EPOCH_ENTER(et); @@ -802,8 +803,8 @@ int in6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf, const u_int8_t *baseid, int generate) { + struct nd_ifinfo *ndi = nd6_ifinfo(ifp); u_int8_t nullbuf[8]; - struct nd_ifinfo *ndi = ND_IFINFO(ifp); bzero(nullbuf, sizeof(nullbuf)); if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { @@ -837,9 +838,8 @@ in6_tmpaddrtimer(void *arg) bzero(nullbuf, sizeof(nullbuf)); CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { - if (ifp->if_afdata[AF_INET6] == NULL) + if ((ndi = nd6_ifinfo(ifp)) == NULL) continue; - ndi = ND_IFINFO(ifp); if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { /* * We've been generating a random ID on this interface. diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index ae4cb2c125b7..d497e5ded82d 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -536,6 +536,7 @@ ip6_input(struct mbuf *m) struct ip6_hdr *ip6; struct in6_ifaddr *ia; struct ifnet *rcvif; + struct nd_ifinfo *ndi; u_int32_t plen; u_int32_t rtalert = ~0; int off = sizeof(struct ip6_hdr), nest; @@ -546,7 +547,8 @@ ip6_input(struct mbuf *m) * Drop the packet if IPv6 operation is disabled on the interface. */ rcvif = m->m_pkthdr.rcvif; - if ((ND_IFINFO(rcvif)->flags & ND6_IFF_IFDISABLED)) + if ((ndi = nd6_ifinfo(rcvif)) == NULL || + (ndi->flags & ND6_IFF_IFDISABLED) != 0) goto bad; #if defined(IPSEC) || defined(IPSEC_SUPPORT) diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index bb488dbc6ff1..289688aabcac 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -327,10 +327,12 @@ nd6_ifdetach(struct ifnet *ifp, struct nd_ifinfo *nd) void nd6_setmtu(struct ifnet *ifp) { - if (ifp->if_afdata[AF_INET6] == NULL) + struct nd_ifinfo *ndi; + + if ((ndi = nd6_ifinfo(ifp)) == NULL) return; - nd6_setmtu0(ifp, ND_IFINFO(ifp)); + nd6_setmtu0(ifp, ndi); } /* XXX todo: do not maintain copy of ifp->if_mtu in ndi->maxmtu */ @@ -772,8 +774,9 @@ nd6_llinfo_timer(void *arg) return; } NET_EPOCH_ENTER(et); - ndi = ND_IFINFO(ifp); send_ns = 0; + if ((ndi = nd6_ifinfo(ifp)) == NULL) + goto done; dst = &ln->r_l3addr.addr6; pdst = dst; @@ -2215,8 +2218,9 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags, struct llentry **plle) { - struct llentry *ln = NULL; const struct sockaddr_in6 *dst6; + struct nd_ifinfo *ndi; + struct llentry *ln = NULL; NET_EPOCH_ASSERT(); @@ -2226,7 +2230,8 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, dst6 = (const struct sockaddr_in6 *)sa_dst; /* discard the packet if IPv6 operation is disabled on the interface */ - if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { + if ((ndi = nd6_ifinfo(ifp)) == NULL || + (ndi->flags & ND6_IFF_IFDISABLED) != 0) { m_freem(m); return (ENETDOWN); /* better error? */ } diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index a64c786efcc8..20dac4064315 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -105,6 +105,16 @@ struct nd_ifinfo { ? ND_IFINFO(ifp)->linkmtu \ : ((ND_IFINFO(ifp)->maxmtu && ND_IFINFO(ifp)->maxmtu < (ifp)->if_mtu) \ ? ND_IFINFO(ifp)->maxmtu : (ifp)->if_mtu)) + +static inline struct nd_ifinfo * +nd6_ifinfo(struct ifnet *ifp) +{ + //NET_EPOCH_ASSERT(); + if (ifp != NULL && (ifp->if_flags & IFF_DYING) == 0 && + ifp->if_afdata[AF_INET6] != NULL) + return (ND_IFINFO(ifp)); + return (NULL); +} #endif struct in6_nbrinfo { diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 20364e03ffe1..d63e6ca02065 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1339,13 +1339,15 @@ nd6_dad_timer(struct dadq *dp) struct ifaddr *ifa = dp->dad_ifa; struct ifnet *ifp = dp->dad_ifa->ifa_ifp; struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; + struct nd_ifinfo *ndi; char ip6buf[INET6_ADDRSTRLEN]; struct epoch_tracker et; KASSERT(ia != NULL, ("DAD entry %p with no address", dp)); NET_EPOCH_ENTER(et); - if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { + if ((ndi = nd6_ifinfo(ifp)) == NULL || + (ndi->flags & ND6_IFF_IFDISABLED) != 0) { /* Do not need DAD for ifdisabled interface. */ log(LOG_ERR, "nd6_dad_timer: cancel DAD on %s because of " "ND6_IFF_IFDISABLED.\n", ifp->if_xname); @@ -1423,7 +1425,7 @@ nd6_dad_timer(struct dadq *dp) * again in case that it is changed between the * beginning of this function and here. */ - if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) == 0) + if ((ndi->flags & ND6_IFF_IFDISABLED) == 0) ia->ia6_flags &= ~IN6_IFF_TENTATIVE; nd6log((LOG_DEBUG,