The branch main has been updated by glebius:

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

commit d4062b9f16e46f039f2b5b40dd35592b5dabf00c
Author:     Gleb Smirnoff <[email protected]>
AuthorDate: 2025-12-17 21:05:04 +0000
Commit:     Gleb Smirnoff <[email protected]>
CommitDate: 2025-12-17 21:13:42 +0000

    vlan: plug a new panic associated with interface removal
    
    The ac6a7f621668 enabled execution of vlan_clone_dump_nl(), which
    previously was effectively disabled.  The function itself was added back
    in 089104e0e01f0.  This exposed a bug when Netlink dumps info on all
    interfaces using a dangerous KPI if_foreach_sleep(), which may call its
    callbacks on completely detached interfaces, hanging on the last
    reference.  The ifc_dump_ifp_nl_default() is able to digest such interface
    without a panic, but vlan_clone_dump_nl() can't.  Neither of the above
    revisions is the actual culprit, rather it is design problem of detaching
    interfaces and if_foreach_sleep().
    
    Plug the problem with removing pointer to freed memory on detach and
    making a NULL check later.
    
    Reported by:    pho
---
 sys/net/if_vlan.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 61000018e5a4..afc3fa3fc79e 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1341,12 +1341,19 @@ vlan_clone_modify_nl(struct ifnet *ifp, struct 
ifc_data_nl *ifd)
 static void
 vlan_clone_dump_nl(struct ifnet *ifp, struct nl_writer *nw)
 {
+       struct ifvlan *ifv;
        uint32_t parent_index = 0;
        uint16_t vlan_id = 0;
        uint16_t vlan_proto = 0;
 
        VLAN_SLOCK();
-       struct ifvlan *ifv = ifp->if_softc;
+       if (__predict_false((ifv = ifp->if_softc) == NULL)) {
+               /*
+                * XXXGL: the interface already went through if_dead().  This
+                * check to be removed when we got better interface removal.
+                */
+               return;
+       }
        if (TRUNK(ifv) != NULL)
                parent_index = PARENT(ifv)->if_index;
        vlan_id = ifv->ifv_vid;
@@ -1390,6 +1397,7 @@ vlan_clone_destroy(struct if_clone *ifc, struct ifnet 
*ifp, uint32_t flags)
         */
        taskqueue_drain(taskqueue_thread, &ifv->lladdr_task);
        NET_EPOCH_WAIT();
+       ifp->if_softc = NULL;
        if_free(ifp);
        free(ifv, M_VLAN);
        if (unit != IF_DUNIT_NONE)

Reply via email to