linux/net/netfilter/xt_cgroup.c
<<
>>
Prefs
   1/*
   2 * Xtables module to match the process control group.
   3 *
   4 * Might be used to implement individual "per-application" firewall
   5 * policies in contrast to global policies based on control groups.
   6 * Matching is based upon processes tagged to net_cls' classid marker.
   7 *
   8 * (C) 2013 Daniel Borkmann <dborkman@redhat.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  16
  17#include <linux/skbuff.h>
  18#include <linux/module.h>
  19#include <linux/netfilter/x_tables.h>
  20#include <linux/netfilter/xt_cgroup.h>
  21#include <net/sock.h>
  22
  23MODULE_LICENSE("GPL");
  24MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>");
  25MODULE_DESCRIPTION("Xtables: process control group matching");
  26MODULE_ALIAS("ipt_cgroup");
  27MODULE_ALIAS("ip6t_cgroup");
  28
  29static int cgroup_mt_check_v0(const struct xt_mtchk_param *par)
  30{
  31        struct xt_cgroup_info_v0 *info = par->matchinfo;
  32
  33        if (info->invert & ~1)
  34                return -EINVAL;
  35
  36        return 0;
  37}
  38
  39static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
  40{
  41        struct xt_cgroup_info_v1 *info = par->matchinfo;
  42        struct cgroup *cgrp;
  43
  44        if ((info->invert_path & ~1) || (info->invert_classid & ~1))
  45                return -EINVAL;
  46
  47        if (!info->has_path && !info->has_classid) {
  48                pr_info("xt_cgroup: no path or classid specified\n");
  49                return -EINVAL;
  50        }
  51
  52        if (info->has_path && info->has_classid) {
  53                pr_info_ratelimited("path and classid specified\n");
  54                return -EINVAL;
  55        }
  56
  57        info->priv = NULL;
  58        if (info->has_path) {
  59                cgrp = cgroup_get_from_path(info->path);
  60                if (IS_ERR(cgrp)) {
  61                        pr_info_ratelimited("invalid path, errno=%ld\n",
  62                                            PTR_ERR(cgrp));
  63                        return -EINVAL;
  64                }
  65                info->priv = cgrp;
  66        }
  67
  68        return 0;
  69}
  70
  71static bool
  72cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
  73{
  74        const struct xt_cgroup_info_v0 *info = par->matchinfo;
  75
  76        if (skb->sk == NULL || !sk_fullsock(skb->sk))
  77                return false;
  78
  79        return (info->id == sock_cgroup_classid(&skb->sk->sk_cgrp_data)) ^
  80                info->invert;
  81}
  82
  83static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
  84{
  85        const struct xt_cgroup_info_v1 *info = par->matchinfo;
  86        struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data;
  87        struct cgroup *ancestor = info->priv;
  88
  89        if (!skb->sk || !sk_fullsock(skb->sk))
  90                return false;
  91
  92        if (ancestor)
  93                return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^
  94                        info->invert_path;
  95        else
  96                return (info->classid == sock_cgroup_classid(skcd)) ^
  97                        info->invert_classid;
  98}
  99
 100static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par)
 101{
 102        struct xt_cgroup_info_v1 *info = par->matchinfo;
 103
 104        if (info->priv)
 105                cgroup_put(info->priv);
 106}
 107
 108static struct xt_match cgroup_mt_reg[] __read_mostly = {
 109        {
 110                .name           = "cgroup",
 111                .revision       = 0,
 112                .family         = NFPROTO_UNSPEC,
 113                .checkentry     = cgroup_mt_check_v0,
 114                .match          = cgroup_mt_v0,
 115                .matchsize      = sizeof(struct xt_cgroup_info_v0),
 116                .me             = THIS_MODULE,
 117                .hooks          = (1 << NF_INET_LOCAL_OUT) |
 118                                  (1 << NF_INET_POST_ROUTING) |
 119                                  (1 << NF_INET_LOCAL_IN),
 120        },
 121        {
 122                .name           = "cgroup",
 123                .revision       = 1,
 124                .family         = NFPROTO_UNSPEC,
 125                .checkentry     = cgroup_mt_check_v1,
 126                .match          = cgroup_mt_v1,
 127                .matchsize      = sizeof(struct xt_cgroup_info_v1),
 128                .usersize       = offsetof(struct xt_cgroup_info_v1, priv),
 129                .destroy        = cgroup_mt_destroy_v1,
 130                .me             = THIS_MODULE,
 131                .hooks          = (1 << NF_INET_LOCAL_OUT) |
 132                                  (1 << NF_INET_POST_ROUTING) |
 133                                  (1 << NF_INET_LOCAL_IN),
 134        },
 135};
 136
 137static int __init cgroup_mt_init(void)
 138{
 139        return xt_register_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg));
 140}
 141
 142static void __exit cgroup_mt_exit(void)
 143{
 144        xt_unregister_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg));
 145}
 146
 147module_init(cgroup_mt_init);
 148module_exit(cgroup_mt_exit);
 149