[Devel] [PATCH RHEL COMMIT] ve/net: introduce vz_security_*_check checks

Konstantin Khorenko khorenko at virtuozzo.com
Fri Sep 24 15:02:30 MSK 2021


The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after ark-5.14
------>
commit 3315a0bba6d9be6512e5c3b3015d36c9a28bba65
Author: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
Date:   Fri Sep 24 15:02:30 2021 +0300

    ve/net: introduce vz_security_*_check checks
    
    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 fa7323272deb..d5825ce3b30e 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -89,6 +89,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)
@@ -114,6 +117,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 1002af9dcc38..ab2a16435ea1 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -21,6 +21,7 @@
 #include <linux/kmapset.h>
 #include <linux/mm.h>
 #include <uapi/linux/vzcalluser.h>
+#include <net/rtnetlink.h>
 
 #include "../cgroup/cgroup-internal.h" /* For cgroup_task_count() */
 
@@ -130,6 +131,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;


More information about the Devel mailing list