genl_bind() checks the GENL_MCAST_CAP_* flags of a group only when a family owns it. For a group ID that no family owns, it returns 0, so any user can join it. A family registered later can get that ID, and the socket stays a member: nothing checks it again. An unprivileged user can join the free IDs, load a family module with CTRL_CMD_GETFAMILY, which calls request_module(), and then receive the notifications of a group with GENL_MCAST_CAP_NET_ADMIN or GENL_MCAST_CAP_SYS_ADMIN. For example the drop_monitor "events" group always gets ID 1, and is free until the drop_monitor module is loaded. Fix by returning -ENOENT from genl_bind() when no family owns the group. Nothing is ever sent to such a group, so joining it has no use. Found by the Sashiko review of the gtp multicast group fix. Tested as an unprivileged user who joins all free IDs, then loads gtp and drop_monitor: Before: joins: ok=62 EPERM=2 gtp/gtp (ID 15): member NET_DM/events (ID 1): member After: joins: ok=19 ENOENT=43 EPERM=2 gtp/gtp (ID 15): not member NET_DM/events (ID 1): not member Link: https://lore.kernel.org/netdev/179324692107.3134.14443689892607921337@kernel.org/ Fixes: e03781879a0d ("drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group") Reviewed-by: Nicolas Dichtel Reviewed-by: Ido Schimmel Signed-off-by: Anil Kaushik --- net/netlink/genetlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 5cc1037d4917..f038f04ef4ea 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1825,7 +1825,7 @@ static int genl_bind(struct net *net, int group) { const struct genl_family *family; unsigned int id; - int ret = 0; + int ret = -ENOENT; down_read(&cb_lock); @@ -1841,6 +1841,7 @@ static int genl_bind(struct net *net, int group) continue; grp = &family->mcgrps[i]; + ret = 0; if ((grp->flags & GENL_MCAST_CAP_NET_ADMIN) && !ns_capable(net->user_ns, CAP_NET_ADMIN)) ret = -EPERM; -- 2.25.1