[Devel] [PATCH RH9 10/11] ve/net: introduce vz_security_*_check checks

Alexander Mikhalitsyn alexander.mikhalitsyn at virtuozzo.com
Thu Sep 23 18:02:34 MSK 2021


From: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>

Signed-off-by: Konstantin Khlebnikov <khlebnikov at openvz.org>

+++
ve/netlink: allow messages with family PF_BRIDGE type RTM_xxxNEIGH in CT

While reproducing the problem mentioned in patch 1 I found that
we need it to be able to configure vxlan fdb (Forwarding Database entry).

https://jira.sw.ru/browse/PSBM-53629

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Acked-by: Andrei Vagin <avagin at virtuozzo.com>

(cherry picked from vz7 commit da2b4bd3e7a5 ("ve/netlink: allow messages
with family PF_BRIDGE type RTM_xxxNEIGH in CT"))

VZ 8 rebase part https://jira.sw.ru/browse/PSBM-127783

Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn at virtuozzo.com>

+++
ve: Change error code in vz_security_protocol_check to -EPROTONOSUPPORT

'vz_security_protocol_check' is a part of socket creation routine.
Socket creation can be split into separate stages:
 - family validation and family specific object creation
 - protocol validation and protocol specific object creation
First family argument is validated. If family is ok, then the code
can proceeds to further work with protocol agrument.

As part of family validation procedure for containers
vz_security_family_check is called. If family is not supported in
container environment and the current context is container the
function returns with -EAFNOSUPPORT code.

As part of protocol validation procedure for containers
vz_security_protocol_check is called. If protocol is not supported
in container environment and the current context is container the
function CURRENTLY returns with -EAFNOSUPPORT code, although by
context of the current socket preparation step it should instead
return -EPROTONOSUPPORT.

https://jira.sw.ru/browse/PSBM-104225

Signed-off-by: Valeriy Vdovin <valeriy.vdovin at virtuozzo.com>
Acked-by: Konstantin Khorenko <khorenko at virtuozzo.com>

+++
ve/net: allow IPPROTO_ICMPV6 protocol inside a Container

This patch allows "ping6" utility to work via ICMP socket
without necessity to failback to RAW socket for ipv6.

We do allow this for ipv4, let's allow ICMP socket for ipv6 as well.

Note: by default ping6 will still use RAW socket because of default
settings in "net.ipv4.ping_group_range", but this is another side of the
problem.

https://jira.sw.ru/browse/PSBM-104225

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

https://jira.sw.ru/browse/PSBM-133986

(cherry picked from commit 6b08f48fc06695995e8388ca9de5acf91f125cdb)
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn at virtuozzo.com>
---
 include/linux/ve.h   |  6 +++++
 kernel/ve/ve.c       | 54 ++++++++++++++++++++++++++++++++++++++++++++
 net/core/rtnetlink.c | 10 ++++++++
 net/ipv4/af_inet.c   |  5 ++++
 net/ipv6/af_inet6.c  |  5 ++++
 net/socket.c         |  6 +++++
 6 files changed, 86 insertions(+)

diff --git a/include/linux/ve.h b/include/linux/ve.h
index f8fd5b67ffb8..bbc7ebb87a9d 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -85,6 +85,9 @@ extern struct cgroup *cgroup_get_ve_root1(struct cgroup *cgrp);
 
 #define ve_uevent_seqnum       (get_exec_env()->_uevent_seqnum)
 
+extern int vz_security_family_check(struct net *net, int family, int type);
+extern int vz_security_protocol_check(struct net *net, int protocol);
+
 #else	/* CONFIG_VE */
 #define get_ve(ve)	(NULL)
 #define put_ve(ve)	do { } while (0)
@@ -105,6 +108,9 @@ static inline struct cgroup *cgroup_get_ve_root1(struct cgroup *cgrp)
 }
 #define ve_uevent_seqnum uevent_seqnum
 
+static inline int vz_security_family_check(struct net *net, int family, int type) { return 0; }
+static inline int vz_security_protocol_check(struct net *net, int protocol) { return 0; }
+
 #endif	/* CONFIG_VE */
 
 #endif /* _LINUX_VE_H */
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 1cce1a51b2ee..325d3977d870 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -20,6 +20,7 @@
 #include <linux/mutex.h>
 #include <linux/kmapset.h>
 #include <uapi/linux/vzcalluser.h>
+#include <net/rtnetlink.h>
 
 #include "../cgroup/cgroup-internal.h" /* For cgroup_task_count() */
 
@@ -123,6 +124,59 @@ struct ve_struct *get_ve_by_id(envid_t veid)
 }
 EXPORT_SYMBOL(get_ve_by_id);
 
+int vz_security_family_check(struct net *net, int family, int type)
+{
+	if (ve_is_super(net->owner_ve))
+		return 0;
+
+	switch (family) {
+	case PF_UNSPEC:
+	case PF_PACKET:
+	case PF_NETLINK:
+	case PF_UNIX:
+	case PF_INET:
+	case PF_INET6:
+	case PF_PPPOX:
+	case PF_KEY:
+		return 0;
+	case PF_BRIDGE:
+		if (type)
+			switch (type) {
+				case RTM_NEWNEIGH:
+				case RTM_DELNEIGH:
+				case RTM_GETNEIGH:
+					return 0;
+			}
+	default:
+		return -EAFNOSUPPORT;
+	}
+}
+EXPORT_SYMBOL_GPL(vz_security_family_check);
+
+int vz_security_protocol_check(struct net *net, int protocol)
+{
+	if (ve_is_super(net->owner_ve))
+		return 0;
+
+	switch (protocol) {
+	case  IPPROTO_IP:
+	case  IPPROTO_ICMP:
+	case  IPPROTO_ICMPV6:
+	case  IPPROTO_TCP:
+	case  IPPROTO_UDP:
+	case  IPPROTO_RAW:
+	case  IPPROTO_DCCP:
+	case  IPPROTO_GRE:
+	case  IPPROTO_ESP:
+	case  IPPROTO_AH:
+	case  IPPROTO_SCTP:
+		return 0;
+	default:
+		return -EPROTONOSUPPORT;
+	}
+}
+EXPORT_SYMBOL_GPL(vz_security_protocol_check);
+
 /* Check if current user_ns is initial for current ve */
 bool current_user_ns_initial(void)
 {
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 662eb1c37f47..f323214ef0a0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -54,6 +54,8 @@
 #include <net/rtnetlink.h>
 #include <net/net_namespace.h>
 
+#include <linux/ve.h>
+
 #define RTNL_MAX_TYPE		50
 #define RTNL_SLAVE_MAX_TYPE	40
 
@@ -3758,6 +3760,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 	int s_idx = cb->family;
 	int type = cb->nlh->nlmsg_type - RTM_BASE;
 	int ret = 0;
+	struct net *net = sock_net(skb->sk);
 
 	if (s_idx == 0)
 		s_idx = 1;
@@ -3785,6 +3788,9 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 		if (!dumpit)
 			continue;
 
+		if (vz_security_family_check(net, idx, cb->nlh->nlmsg_type))
+			continue;
+
 		if (idx > s_idx) {
 			memset(&cb->args[0], 0, sizeof(cb->args));
 			cb->prev_seq = 0;
@@ -5497,6 +5503,10 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return 0;
 
 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
+
+	if (vz_security_family_check(net, family, nlh->nlmsg_type))
+		return -EAFNOSUPPORT;
+
 	kind = type&3;
 
 	if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN))
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 54648181dd56..cf1ac3fab7d7 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -85,6 +85,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/random.h>
 #include <linux/slab.h>
+#include <linux/ve.h>
 
 #include <linux/uaccess.h>
 
@@ -306,6 +307,10 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
 			goto out_rcu_unlock;
 	}
 
+	err = vz_security_protocol_check(net, answer->protocol);
+	if (err < 0)
+		goto out_rcu_unlock;
+
 	err = -EPERM;
 	if (sock->type == SOCK_RAW && !kern &&
 	    !ns_capable(net->user_ns, CAP_NET_RAW))
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 2389ff702f51..870c224d5333 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -34,6 +34,7 @@
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ve.h>
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -167,6 +168,10 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
 			goto out_rcu_unlock;
 	}
 
+	err = vz_security_protocol_check(net, answer->protocol);
+	if (err < 0)
+		goto out_rcu_unlock;
+
 	err = -EPERM;
 	if (sock->type == SOCK_RAW && !kern &&
 	    !ns_capable(net->user_ns, CAP_NET_RAW))
diff --git a/net/socket.c b/net/socket.c
index 95a3e3bcb5be..e84f116ba1da 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -86,6 +86,7 @@
 #include <linux/xattr.h>
 #include <linux/nospec.h>
 #include <linux/indirect_call_wrapper.h>
+#include <linux/ve.h>
 
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
@@ -1403,6 +1404,11 @@ int __sock_create(struct net *net, int family, int type, int protocol,
 		family = PF_PACKET;
 	}
 
+	/* VZ compatibility layer */
+	err = vz_security_family_check(net, family, 0);
+	if (err < 0)
+		return err;
+
 	err = security_socket_create(family, type, protocol, kern);
 	if (err)
 		return err;
-- 
2.31.1



More information about the Devel mailing list