Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30cc13fe authored by Ido Schimmel's avatar Ido Schimmel Committed by Greg Kroah-Hartman
Browse files

genetlink: add CAP_NET_ADMIN test for multicast bind

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: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7c62ae9b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 */
struct genl_multicast_group {
	char			name[GENL_NAMSIZ];
	u8			flags;
};

struct genl_ops;
+32 −0
Original line number Diff line number Diff line
@@ -961,11 +961,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 */