[Bug 290893] netlink: genl_register_family function does not release the lock if the family name is already in use

From: <bugzilla-noreply_at_freebsd.org>
Date: Sat, 08 Nov 2025 12:26:54 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=290893

            Bug ID: 290893
           Summary: netlink: genl_register_family function does not
                    release the lock if the family name is already in use
           Product: Base System
           Version: 15.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: bruno.silvestre@gmail.com

The function genl_register_family() returns an error if the name of the family
is already in use, but does not release the lock.
The next call to genl_register_family() will block indefinitely.

A side comment, why does the function panic if the maximum number of families
are already registered? It could just return an error.

--- netlink_generic.old.c       2025-11-08 08:55:46.012479000 -0300
+++ netlink_generic.c   2025-11-08 09:00:00.541146000 -0300
@@ -366,8 +366,10 @@
        GENL_LOCK();
        for (u_int i = 0; i < MAX_FAMILIES; i++)
                if (families[i].family_name != NULL &&
-                   strcmp(families[i].family_name, family_name) == 0)
+                   strcmp(families[i].family_name, family_name) == 0) {
+                       GENL_UNLOCK();
                        return (0);
+               }

        /* Microoptimization: index 0 is reserved for the control family. */
        gf = NULL;
@@ -376,6 +378,10 @@
                        gf = &families[i];
                        break;
                }
+
+       //
+       //XXX: Why kernel panic? It could return 0 as register group below.
+       //
        KASSERT(gf, ("%s: maximum of %u generic netlink families allocated",
            __func__, MAX_FAMILIES));


//----------------------------------------------------------------------------

To test the bug, just creates a module that register a family.
You load and unload it 3 times: 1st ok, 2nd error, 3rd deadlock.

#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>

#include <netlink/netlink.h>
#include <netlink/netlink_ctl.h>
#include <netlink/netlink_generic.h>


static int
genltest_modevent(module_t mod __unused, int event, void *arg __unused)
{
        int error = 0;
        switch (event) {
        case MOD_LOAD:
                uprintf("Generic netlink load\n");
                uint16_t id = genl_register_family("genltest", 0, 2, 0);
                uprintf("Register: %d\n", id);
                break;
        case MOD_UNLOAD:
                uprintf("Generic netlink unload\n");
                break;
        default:
                error = EOPNOTSUPP;
                break;
        }
        return (error);
}

static moduledata_t genltest_mod = {
        "genltest",
        genltest_modevent,
        NULL
};

DECLARE_MODULE(genltest, genltest_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);

-- 
You are receiving this mail because:
You are the assignee for the bug.