]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
genetlink: add CAP_NET_ADMIN test for multicast bind
authorIdo Schimmel <idosch@nvidia.com>
Mon, 11 Dec 2023 12:42:59 +0000 (14:42 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Dec 2023 15:46:17 +0000 (16:46 +0100)
This is a partial backport of upstream commit 4d54cc32112d ("mptcp:
avoid lock_fast usage in accept path"). It is only a partial backport
because the patch in the link below was erroneously squash-merged into
upstream commit 4d54cc32112d ("mptcp: avoid lock_fast usage in accept
path"). Below is the original patch description from Florian Westphal:

"
genetlink sets NL_CFG_F_NONROOT_RECV for its netlink socket so anyone can
subscribe to multicast messages.

rtnetlink doesn't allow this unconditionally,  rtnetlink_bind() restricts
bind requests to CAP_NET_ADMIN for a few groups.

This allows to set GENL_UNS_ADMIN_PERM flag on genl mcast groups to
mandate CAP_NET_ADMIN.

This will be used by the upcoming mptcp netlink event facility which
exposes the token (mptcp connection identifier) to userspace.
"

Link: https://lore.kernel.org/mptcp/20210213000001.379332-8-mathew.j.martineau@linux.intel.com/
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/net/genetlink.h
net/netlink/genetlink.c

index c25b2e75732b3cbf39a6897453e581f540d56aa7..d9c4936c9941b15023e052a3df98a6d8133cf8cb 100644 (file)
@@ -14,6 +14,7 @@
  */
 struct genl_multicast_group {
        char                    name[GENL_NAMSIZ];
+       u8                      flags;
 };
 
 struct genl_ops;
index 7bc631bfb101e43e3ec722a962f8b3feac81ed9f..366206078b1150fba5f5b21f896a89bf36153a04 100644 (file)
@@ -959,11 +959,43 @@ static struct genl_family genl_ctrl __ro_after_init = {
        .netnsok = true,
 };
 
+static int genl_bind(struct net *net, int group)
+{
+       const struct genl_family *family;
+       unsigned int id;
+       int ret = 0;
+
+       genl_lock_all();
+
+       idr_for_each_entry(&genl_fam_idr, family, id) {
+               const struct genl_multicast_group *grp;
+               int i;
+
+               if (family->n_mcgrps == 0)
+                       continue;
+
+               i = group - family->mcgrp_offset;
+               if (i < 0 || i >= family->n_mcgrps)
+                       continue;
+
+               grp = &family->mcgrps[i];
+               if ((grp->flags & GENL_UNS_ADMIN_PERM) &&
+                   !ns_capable(net->user_ns, CAP_NET_ADMIN))
+                       ret = -EPERM;
+
+               break;
+       }
+
+       genl_unlock_all();
+       return ret;
+}
+
 static int __net_init genl_pernet_init(struct net *net)
 {
        struct netlink_kernel_cfg cfg = {
                .input          = genl_rcv,
                .flags          = NL_CFG_F_NONROOT_RECV,
+               .bind           = genl_bind,
        };
 
        /* we'll bump the group number right afterwards */