From: Ido Schimmel idosch@nvidia.com
stable inclusion from stable-v5.10.204 commit 015870c10c45902882d2d4adad17f162df144104 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
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@lin... Signed-off-by: Ido Schimmel idosch@nvidia.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zhengchao Shao shaozhengchao@huawei.com --- include/net/genetlink.h | 1 + net/netlink/genetlink.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/net/genetlink.h b/include/net/genetlink.h index f927ba671e4b..99bcf268b1b9 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -15,6 +15,7 @@ */ struct genl_multicast_group { char name[GENL_NAMSIZ]; + u8 flags; };
struct genl_ops; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 9fd7ba01b9f8..4dce39013d75 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1364,11 +1364,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 */