[Devel,RHEL7,COMMIT] ve/netlink: allow IPVS netlink messages to CT init userns

Submitted by Konstantin Khorenko on April 26, 2017, 8:19 a.m.

Details

Message ID 201704260819.v3Q8JeiO001840@finist_cl7.x64_64.work.ct
State New
Series "net/ipvs: allow IPVS in CT"
Headers show

Commit Message

Konstantin Khorenko April 26, 2017, 8:19 a.m.
The commit is pushed to "PSBM-63883-Docker-Swarm" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-514.16.1.vz7.30.7
------>
commit e70e1f7b6f01d438e69c5724a19ece1cab2fd162
Author: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Date:   Wed Apr 26 12:19:40 2017 +0400

    ve/netlink: allow IPVS netlink messages to CT init userns
    
    Docker swarm tries to setup IPVS via netlink, so let him do it.
    It can be done through setsockopt as each IPVS_CMD_* had it's
    IP_VS_SO_SET_* analogy.
    
    https://jira.sw.ru/browse/PSBM-63883
    Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
    Reviewed-by: Andrew Vagin <avagin@virtuozzo.com>
---
 include/linux/netlink.h        |  1 +
 include/uapi/linux/genetlink.h |  1 +
 net/netfilter/ipvs/ip_vs_ctl.c | 32 ++++++++++++++++----------------
 net/netlink/af_netlink.c       | 19 +++++++++++++++++++
 net/netlink/genetlink.c        |  4 ++++
 5 files changed, 41 insertions(+), 16 deletions(-)

Patch hide | download patch | download mbox

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index ef68e5b..645127e 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -179,6 +179,7 @@  bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
 			  struct user_namespace *ns, int cap);
 bool netlink_ns_capable(const struct sk_buff *skb,
 			struct user_namespace *ns, int cap);
+bool netlink_ve_capable(const struct sk_buff *skb, int cap);
 bool netlink_capable(const struct sk_buff *skb, int cap);
 bool netlink_net_capable(const struct sk_buff *skb, int cap);
 
diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h
index 5512c90..481704f 100644
--- a/include/uapi/linux/genetlink.h
+++ b/include/uapi/linux/genetlink.h
@@ -22,6 +22,7 @@  struct genlmsghdr {
 #define GENL_CMD_CAP_DUMP	0x04
 #define GENL_CMD_CAP_HASPOL	0x08
 #define GENL_UNS_ADMIN_PERM	0x10
+#define GENL_VE_ADMIN_PERM	0x80
 
 /*
  * List of reserved static generic netlink identifiers:
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index db4563d..c924ab2 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3596,95 +3596,95 @@  out:
 static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
 	{
 		.cmd	= IPVS_CMD_NEW_SERVICE,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_SET_SERVICE,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_DEL_SERVICE,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_GET_SERVICE,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.doit	= ip_vs_genl_get_cmd,
 		.dumpit	= ip_vs_genl_dump_services,
 		.policy	= ip_vs_cmd_policy,
 	},
 	{
 		.cmd	= IPVS_CMD_NEW_DEST,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_SET_DEST,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_DEL_DEST,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_GET_DEST,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.dumpit	= ip_vs_genl_dump_dests,
 	},
 	{
 		.cmd	= IPVS_CMD_NEW_DAEMON,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_daemon,
 	},
 	{
 		.cmd	= IPVS_CMD_DEL_DAEMON,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_daemon,
 	},
 	{
 		.cmd	= IPVS_CMD_GET_DAEMON,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.dumpit	= ip_vs_genl_dump_daemons,
 	},
 	{
 		.cmd	= IPVS_CMD_SET_CONFIG,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_GET_CONFIG,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.doit	= ip_vs_genl_get_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_GET_INFO,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.doit	= ip_vs_genl_get_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_ZERO,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.policy	= ip_vs_cmd_policy,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 	{
 		.cmd	= IPVS_CMD_FLUSH,
-		.flags	= GENL_ADMIN_PERM,
+		.flags	= GENL_VE_ADMIN_PERM,
 		.doit	= ip_vs_genl_set_cmd,
 	},
 };
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index d0af224..1a395b2 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1350,6 +1350,25 @@  bool netlink_ns_capable(const struct sk_buff *skb,
 }
 EXPORT_SYMBOL(netlink_ns_capable);
 
+#ifdef CONFIG_VE
+bool netlink_ve_capable(const struct sk_buff *skb, int cap)
+{
+	struct cred *cred = get_exec_env()->init_cred;
+
+	if (cred == NULL) /* ve isn't running */
+		cred = ve0.init_cred;
+
+	return netlink_ns_capable(skb, cred->user_ns, cap);
+}
+#else
+bool netlink_ve_capable(const struct sk_buff *skb, int cap)
+{
+	return netlink_capable(skb, cap);
+}
+#endif
+
+EXPORT_SYMBOL(netlink_ve_capable);
+
 /**
  * netlink_capable - Netlink global message capability test
  * @skb: socket buffer holding a netlink command from userspace
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index a93aabe..870a3dd 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -560,6 +560,10 @@  static int genl_family_rcv_msg(struct genl_family *family,
 	    !netlink_capable(skb, CAP_NET_ADMIN))
 		return -EPERM;
 
+	if ((ops->flags & GENL_VE_ADMIN_PERM) &&
+	    !netlink_ve_capable(skb, CAP_NET_ADMIN))
+		return -EPERM;
+
 	if ((ops->flags & GENL_UNS_ADMIN_PERM) &&
 	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
 		return -EPERM;