Merge tag 'xfs-4.20-merge-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-block.git] / net / netfilter / xt_cgroup.c
index 5d92e178198088b85d040473f909aa9eab78c18e..5cb1ecb29ea4d5c4f5df9fc325aac8e81d0bde58 100644 (file)
@@ -68,6 +68,38 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
        return 0;
 }
 
+static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+{
+       struct xt_cgroup_info_v2 *info = par->matchinfo;
+       struct cgroup *cgrp;
+
+       if ((info->invert_path & ~1) || (info->invert_classid & ~1))
+               return -EINVAL;
+
+       if (!info->has_path && !info->has_classid) {
+               pr_info("xt_cgroup: no path or classid specified\n");
+               return -EINVAL;
+       }
+
+       if (info->has_path && info->has_classid) {
+               pr_info_ratelimited("path and classid specified\n");
+               return -EINVAL;
+       }
+
+       info->priv = NULL;
+       if (info->has_path) {
+               cgrp = cgroup_get_from_path(info->path);
+               if (IS_ERR(cgrp)) {
+                       pr_info_ratelimited("invalid path, errno=%ld\n",
+                                           PTR_ERR(cgrp));
+                       return -EINVAL;
+               }
+               info->priv = cgrp;
+       }
+
+       return 0;
+}
+
 static bool
 cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
 {
@@ -99,6 +131,24 @@ static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
                        info->invert_classid;
 }
 
+static bool cgroup_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       const struct xt_cgroup_info_v2 *info = par->matchinfo;
+       struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data;
+       struct cgroup *ancestor = info->priv;
+       struct sock *sk = skb->sk;
+
+       if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
+               return false;
+
+       if (ancestor)
+               return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^
+                       info->invert_path;
+       else
+               return (info->classid == sock_cgroup_classid(skcd)) ^
+                       info->invert_classid;
+}
+
 static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par)
 {
        struct xt_cgroup_info_v1 *info = par->matchinfo;
@@ -107,6 +157,14 @@ static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par)
                cgroup_put(info->priv);
 }
 
+static void cgroup_mt_destroy_v2(const struct xt_mtdtor_param *par)
+{
+       struct xt_cgroup_info_v2 *info = par->matchinfo;
+
+       if (info->priv)
+               cgroup_put(info->priv);
+}
+
 static struct xt_match cgroup_mt_reg[] __read_mostly = {
        {
                .name           = "cgroup",
@@ -134,6 +192,20 @@ static struct xt_match cgroup_mt_reg[] __read_mostly = {
                                  (1 << NF_INET_POST_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),
        },
+       {
+               .name           = "cgroup",
+               .revision       = 2,
+               .family         = NFPROTO_UNSPEC,
+               .checkentry     = cgroup_mt_check_v2,
+               .match          = cgroup_mt_v2,
+               .matchsize      = sizeof(struct xt_cgroup_info_v2),
+               .usersize       = offsetof(struct xt_cgroup_info_v2, priv),
+               .destroy        = cgroup_mt_destroy_v2,
+               .me             = THIS_MODULE,
+               .hooks          = (1 << NF_INET_LOCAL_OUT) |
+                                 (1 << NF_INET_POST_ROUTING) |
+                                 (1 << NF_INET_LOCAL_IN),
+       },
 };
 
 static int __init cgroup_mt_init(void)