mm: create the new vm_fault_t type
[linux-2.6-microblaze.git] / net / netfilter / xt_cgroup.c
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
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>");
25 MODULE_DESCRIPTION("Xtables: process control group matching");
26 MODULE_ALIAS("ipt_cgroup");
27 MODULE_ALIAS("ip6t_cgroup");
28
29 static 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
39 static 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
71 static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
72 {
73         struct xt_cgroup_info_v2 *info = par->matchinfo;
74         struct cgroup *cgrp;
75
76         if ((info->invert_path & ~1) || (info->invert_classid & ~1))
77                 return -EINVAL;
78
79         if (!info->has_path && !info->has_classid) {
80                 pr_info("xt_cgroup: no path or classid specified\n");
81                 return -EINVAL;
82         }
83
84         if (info->has_path && info->has_classid) {
85                 pr_info_ratelimited("path and classid specified\n");
86                 return -EINVAL;
87         }
88
89         info->priv = NULL;
90         if (info->has_path) {
91                 cgrp = cgroup_get_from_path(info->path);
92                 if (IS_ERR(cgrp)) {
93                         pr_info_ratelimited("invalid path, errno=%ld\n",
94                                             PTR_ERR(cgrp));
95                         return -EINVAL;
96                 }
97                 info->priv = cgrp;
98         }
99
100         return 0;
101 }
102
103 static bool
104 cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
105 {
106         const struct xt_cgroup_info_v0 *info = par->matchinfo;
107         struct sock *sk = skb->sk;
108
109         if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
110                 return false;
111
112         return (info->id == sock_cgroup_classid(&skb->sk->sk_cgrp_data)) ^
113                 info->invert;
114 }
115
116 static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
117 {
118         const struct xt_cgroup_info_v1 *info = par->matchinfo;
119         struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data;
120         struct cgroup *ancestor = info->priv;
121         struct sock *sk = skb->sk;
122
123         if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
124                 return false;
125
126         if (ancestor)
127                 return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^
128                         info->invert_path;
129         else
130                 return (info->classid == sock_cgroup_classid(skcd)) ^
131                         info->invert_classid;
132 }
133
134 static bool cgroup_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
135 {
136         const struct xt_cgroup_info_v2 *info = par->matchinfo;
137         struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data;
138         struct cgroup *ancestor = info->priv;
139         struct sock *sk = skb->sk;
140
141         if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
142                 return false;
143
144         if (ancestor)
145                 return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^
146                         info->invert_path;
147         else
148                 return (info->classid == sock_cgroup_classid(skcd)) ^
149                         info->invert_classid;
150 }
151
152 static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par)
153 {
154         struct xt_cgroup_info_v1 *info = par->matchinfo;
155
156         if (info->priv)
157                 cgroup_put(info->priv);
158 }
159
160 static void cgroup_mt_destroy_v2(const struct xt_mtdtor_param *par)
161 {
162         struct xt_cgroup_info_v2 *info = par->matchinfo;
163
164         if (info->priv)
165                 cgroup_put(info->priv);
166 }
167
168 static struct xt_match cgroup_mt_reg[] __read_mostly = {
169         {
170                 .name           = "cgroup",
171                 .revision       = 0,
172                 .family         = NFPROTO_UNSPEC,
173                 .checkentry     = cgroup_mt_check_v0,
174                 .match          = cgroup_mt_v0,
175                 .matchsize      = sizeof(struct xt_cgroup_info_v0),
176                 .me             = THIS_MODULE,
177                 .hooks          = (1 << NF_INET_LOCAL_OUT) |
178                                   (1 << NF_INET_POST_ROUTING) |
179                                   (1 << NF_INET_LOCAL_IN),
180         },
181         {
182                 .name           = "cgroup",
183                 .revision       = 1,
184                 .family         = NFPROTO_UNSPEC,
185                 .checkentry     = cgroup_mt_check_v1,
186                 .match          = cgroup_mt_v1,
187                 .matchsize      = sizeof(struct xt_cgroup_info_v1),
188                 .usersize       = offsetof(struct xt_cgroup_info_v1, priv),
189                 .destroy        = cgroup_mt_destroy_v1,
190                 .me             = THIS_MODULE,
191                 .hooks          = (1 << NF_INET_LOCAL_OUT) |
192                                   (1 << NF_INET_POST_ROUTING) |
193                                   (1 << NF_INET_LOCAL_IN),
194         },
195         {
196                 .name           = "cgroup",
197                 .revision       = 2,
198                 .family         = NFPROTO_UNSPEC,
199                 .checkentry     = cgroup_mt_check_v2,
200                 .match          = cgroup_mt_v2,
201                 .matchsize      = sizeof(struct xt_cgroup_info_v2),
202                 .usersize       = offsetof(struct xt_cgroup_info_v2, priv),
203                 .destroy        = cgroup_mt_destroy_v2,
204                 .me             = THIS_MODULE,
205                 .hooks          = (1 << NF_INET_LOCAL_OUT) |
206                                   (1 << NF_INET_POST_ROUTING) |
207                                   (1 << NF_INET_LOCAL_IN),
208         },
209 };
210
211 static int __init cgroup_mt_init(void)
212 {
213         return xt_register_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg));
214 }
215
216 static void __exit cgroup_mt_exit(void)
217 {
218         xt_unregister_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg));
219 }
220
221 module_init(cgroup_mt_init);
222 module_exit(cgroup_mt_exit);