lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 29 Mar 2023 11:25:42 -0700
From:   Anjali Kulkarni <anjali.k.kulkarni@...cle.com>
To:     davem@...emloft.net
Cc:     edumazet@...gle.com, kuba@...nel.org, pabeni@...hat.com,
        zbr@...emap.net, brauner@...nel.org, johannes@...solutions.net,
        ecree.xilinx@...il.com, leon@...nel.org, keescook@...omium.org,
        socketcan@...tkopp.net, petrm@...dia.com,
        linux-kernel@...r.kernel.org, netdev@...r.kernel.org,
        anjali.k.kulkarni@...cle.com
Subject: [PATCH v3 6/7] netlink: Add multicast group level permissions

A new field perm_groups is added in netlink_sock to store the protocol's
multicast group access permissions. This is to allow for a more fine
grained access control than just at the protocol level. These
permissions can be supplied by the protocol via the netlink_kernel_cfg.
A new function netlink_multicast_allowed() is added, which checks if
the protocol's multicast group has non-root access before allowing bind.

Signed-off-by: Anjali Kulkarni <anjali.k.kulkarni@...cle.com>
---
 include/linux/netlink.h  |  1 +
 net/netlink/af_netlink.c | 25 +++++++++++++++++++++++--
 net/netlink/af_netlink.h |  2 ++
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 05a316aa93b4..253cbcd7a290 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -46,6 +46,7 @@ void netlink_table_ungrab(void);
 struct netlink_kernel_cfg {
 	unsigned int	groups;
 	unsigned int	flags;
+	long unsigned 	perm_groups;
 	void		(*input)(struct sk_buff *skb);
 	struct mutex	*cb_mutex;
 	int		(*bind)(struct net *net, int group);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index dc7880055705..f31173d28dd0 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -679,6 +679,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
 	void (*unbind)(struct net *net, int group);
 	void (*release)(struct sock *sock, unsigned long *groups);
 	int err = 0;
+	unsigned long perm_groups;
 
 	sock->state = SS_UNCONNECTED;
 
@@ -706,6 +707,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
 	bind = nl_table[protocol].bind;
 	unbind = nl_table[protocol].unbind;
 	release = nl_table[protocol].release;
+	perm_groups = nl_table[protocol].perm_groups;
 	netlink_unlock_table();
 
 	if (err < 0)
@@ -722,6 +724,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
 	nlk->netlink_bind = bind;
 	nlk->netlink_unbind = unbind;
 	nlk->netlink_release = release;
+	nlk->perm_groups = perm_groups;
 out:
 	return err;
 
@@ -938,6 +941,20 @@ bool netlink_net_capable(const struct sk_buff *skb, int cap)
 }
 EXPORT_SYMBOL(netlink_net_capable);
 
+static inline bool netlink_multicast_allowed(unsigned long perm_groups,
+					     unsigned long groups)
+{
+	int group;
+
+	for (group = 0; group < BITS_PER_TYPE(u32); group++) {
+		if (test_bit(group, &groups)) {
+			if (!test_bit(group, &perm_groups))
+				return false;
+		}
+	}
+	return true;
+}
+
 static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
 {
 	return (nl_table[sock->sk->sk_protocol].flags & flag) ||
@@ -1023,8 +1040,11 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
 
 	/* Only superuser is allowed to listen multicasts */
 	if (groups) {
-		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
-			return -EPERM;
+		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) {
+			if (!netlink_multicast_allowed(nlk->perm_groups,
+						       groups))
+				return -EPERM;
+		}
 		err = netlink_realloc_groups(sk);
 		if (err)
 			return err;
@@ -2124,6 +2144,7 @@ __netlink_kernel_create(struct net *net, int unit, struct module *module,
 			nl_table[unit].unbind = cfg->unbind;
 			nl_table[unit].release = cfg->release;
 			nl_table[unit].flags = cfg->flags;
+			nl_table[unit].perm_groups = cfg->perm_groups;
 			if (cfg->compare)
 				nl_table[unit].compare = cfg->compare;
 		}
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index 054335a34804..b7880254c716 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -29,6 +29,7 @@ struct netlink_sock {
 	u32			flags;
 	u32			subscriptions;
 	u32			ngroups;
+	unsigned long		perm_groups;
 	unsigned long		*groups;
 	unsigned long		state;
 	size_t			max_recvmsg_len;
@@ -62,6 +63,7 @@ struct netlink_table {
 	struct listeners __rcu	*listeners;
 	unsigned int		flags;
 	unsigned int		groups;
+	unsigned long		perm_groups;
 	struct mutex		*cb_mutex;
 	struct module		*module;
 	int			(*bind)(struct net *net, int group);
-- 
2.40.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ