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 */
 

Reply via email to