The branch main has been updated by mjg:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=efd368784eebcc62324f7e1884776a22a73c4688

commit efd368784eebcc62324f7e1884776a22a73c4688
Author:     Mateusz Guzik <m...@freebsd.org>
AuthorDate: 2025-02-10 14:44:39 +0000
Commit:     Mateusz Guzik <m...@freebsd.org>
CommitDate: 2025-02-10 14:45:32 +0000

    mroute: serialize parallel teardown of the same vnet
    
    Otherwise 2 threads calling here can crash the kernel.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netinet/ip_mroute.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 501b3e0d9a43..6e6ecd43e9fe 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -139,6 +139,13 @@ static MALLOC_DEFINE(M_MRTABLE, "mroutetbl", "multicast 
forwarding cache");
  * structures.
  */
 
+static struct sx __exclusive_cache_line mrouter_teardown;
+#define        MRW_TEARDOWN_WLOCK()    sx_xlock(&mrouter_teardown)
+#define        MRW_TEARDOWN_WUNLOCK()  sx_xunlock(&mrouter_teardown)
+#define        MRW_TEARDOWN_LOCK_INIT()                                \
+       sx_init(&mrouter_teardown, "IPv4 multicast forwarding teardown")
+#define        MRW_TEARDOWN_LOCK_DESTROY()     sx_destroy(&mrouter_teardown)
+
 static struct rwlock mrouter_lock;
 #define        MRW_RLOCK()             rw_rlock(&mrouter_lock)
 #define        MRW_WLOCK()             rw_wlock(&mrouter_lock)
@@ -692,15 +699,18 @@ ip_mrouter_init(struct socket *so, int version)
        if (version != 1)
                return ENOPROTOOPT;
 
+       MRW_TEARDOWN_WLOCK();
        MRW_WLOCK();
 
        if (ip_mrouter_unloading) {
                MRW_WUNLOCK();
+               MRW_TEARDOWN_WUNLOCK();
                return ENOPROTOOPT;
        }
 
        if (V_ip_mrouter != NULL) {
                MRW_WUNLOCK();
+               MRW_TEARDOWN_WUNLOCK();
                return EADDRINUSE;
        }
 
@@ -708,6 +718,7 @@ ip_mrouter_init(struct socket *so, int version)
            HASH_NOWAIT);
        if (V_mfchashtbl == NULL) {
                MRW_WUNLOCK();
+               MRW_TEARDOWN_WUNLOCK();
                return (ENOMEM);
        }
 
@@ -717,6 +728,7 @@ ip_mrouter_init(struct socket *so, int version)
            M_NOWAIT, &V_bw_upcalls_ring_mtx);
        if (!V_bw_upcalls_ring) {
                MRW_WUNLOCK();
+               MRW_TEARDOWN_WUNLOCK();
                return (ENOMEM);
        }
 
@@ -736,6 +748,7 @@ ip_mrouter_init(struct socket *so, int version)
        mtx_init(&V_buf_ring_mtx, "mroute buf_ring mtx", NULL, MTX_DEF);
 
        MRW_WUNLOCK();
+       MRW_TEARDOWN_WUNLOCK();
 
        CTR1(KTR_IPMF, "%s: done", __func__);
 
@@ -754,8 +767,12 @@ X_ip_mrouter_done(void)
        vifi_t vifi;
        struct bw_upcall *bu;
 
-       if (V_ip_mrouter == NULL)
+       MRW_TEARDOWN_WLOCK();
+
+       if (V_ip_mrouter == NULL) {
+               MRW_TEARDOWN_WUNLOCK();
                return (EINVAL);
+       }
 
        /*
         * Detach/disable hooks to the reset of the system.
@@ -830,6 +847,7 @@ X_ip_mrouter_done(void)
        mtx_destroy(&V_buf_ring_mtx);
 
        MRW_WUNLOCK();
+       MRW_TEARDOWN_WUNLOCK();
 
        /*
         * Now drop our claim on promiscuous multicast on the interfaces 
recorded
@@ -2809,6 +2827,7 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
 
        switch (type) {
        case MOD_LOAD:
+               MRW_TEARDOWN_LOCK_INIT();
                MRW_LOCK_INIT();
 
                if_detach_event_tag = 
EVENTHANDLER_REGISTER(ifnet_departure_event,
@@ -2880,6 +2899,7 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
                rsvp_input_p = NULL;
 
                MRW_LOCK_DESTROY();
+               MRW_TEARDOWN_LOCK_DESTROY();
                break;
 
        default:

Reply via email to