The branch main has been updated by ae: URL: https://cgit.FreeBSD.org/src/commit/?id=6a97fbe6fcb3f9d413384c6b3594346aebc42e59
commit 6a97fbe6fcb3f9d413384c6b3594346aebc42e59 Author: Andrey V. Elsukov <a...@freebsd.org> AuthorDate: 2025-05-24 08:18:31 +0000 Commit: Andrey V. Elsukov <a...@freebsd.org> CommitDate: 2025-05-24 08:18:31 +0000 carp: fix mbuf_tag usage in carp_macmatch6 carp_macmatch6() had two issues that affect IPv6 processing: 1) it returns sc->sc_addr pointer that might become invalid after softc destroying. 2) carp_output() expects carp vhid to be stored in the mtag, not the pointer to softc. Fix these issues. Allocate enough space in mtag to keep both vhid and mac address. Copy vhid first to fix issue with carp_output(), then copy sc_addr and return pointer to this copy. mtag will be alive until mbuf is used. This fixes problem when IPv6 packets originated from CARP IPv6 address use incorrect mac address due to mbuf_tag has invalid data. Reviewed by: zlei, kp, glebius Obtained from: Yandex LLC Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D50455 --- sys/netinet/ip_carp.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 0ead7149c1e2..d3d7957cf087 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -206,8 +206,6 @@ struct carpkreq { * * Known issues with locking: * - * - Sending ad, we put the pointer to the softc in an mtag, and no reference - * counting is done on the softc. * - On module unload we may race (?) with packet processing thread * dereferencing our function pointers. */ @@ -1688,6 +1686,7 @@ char * carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) { struct ifaddr *ifa; + char *mac = NULL; NET_EPOCH_ASSERT(); @@ -1698,18 +1697,26 @@ carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) struct m_tag *mtag; mtag = m_tag_get(PACKET_TAG_CARP, - sizeof(struct carp_softc *), M_NOWAIT); - if (mtag == NULL) - /* Better a bit than nothing. */ - return (sc->sc_addr); + sizeof(sc->sc_vhid) + sizeof(sc->sc_addr), + M_NOWAIT); + if (mtag == NULL) { + CARPSTATS_INC(carps_onomem); + break; + } + /* carp_output expects sc_vhid first. */ + bcopy(&sc->sc_vhid, mtag + 1, sizeof(sc->sc_vhid)); + /* + * Save sc_addr into mtag data after sc_vhid to avoid + * possible access to destroyed softc. + */ + mac = (char *)(mtag + 1) + sizeof(sc->sc_vhid); + bcopy(sc->sc_addr, mac, sizeof(sc->sc_addr)); - bcopy(&sc, mtag + 1, sizeof(sc)); m_tag_prepend(m, mtag); - - return (sc->sc_addr); + break; } - return (NULL); + return (mac); } #endif /* INET6 */