[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