]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/netfilter/xt_CT.c
netfilter: xt_CT: allocation has to be GFP_ATOMIC under rcu_read_lock section
[mirror_ubuntu-bionic-kernel.git] / net / netfilter / xt_CT.c
CommitLineData
84f3bb9a
PM
1/*
2 * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
a7fed762 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
84f3bb9a 9#include <linux/module.h>
5a0e3ad6 10#include <linux/gfp.h>
84f3bb9a 11#include <linux/skbuff.h>
84f3bb9a
PM
12#include <linux/netfilter_ipv4/ip_tables.h>
13#include <linux/netfilter_ipv6/ip6_tables.h>
14#include <linux/netfilter/x_tables.h>
15#include <linux/netfilter/xt_CT.h>
16#include <net/netfilter/nf_conntrack.h>
eeb4cb95 17#include <net/netfilter/nf_conntrack_l4proto.h>
84f3bb9a
PM
18#include <net/netfilter/nf_conntrack_helper.h>
19#include <net/netfilter/nf_conntrack_ecache.h>
c1ebd7df 20#include <net/netfilter/nf_conntrack_l4proto.h>
24de58f4 21#include <net/netfilter/nf_conntrack_timeout.h>
5d0aa2cc 22#include <net/netfilter/nf_conntrack_zones.h>
84f3bb9a 23
24de58f4
PNA
24static unsigned int xt_ct_target_v0(struct sk_buff *skb,
25 const struct xt_action_param *par)
84f3bb9a
PM
26{
27 const struct xt_ct_target_info *info = par->targinfo;
28 struct nf_conn *ct = info->ct;
29
30 /* Previously seen (loopback)? Ignore. */
31 if (skb->nfct != NULL)
32 return XT_CONTINUE;
33
34 atomic_inc(&ct->ct_general.use);
35 skb->nfct = &ct->ct_general;
36 skb->nfctinfo = IP_CT_NEW;
37
38 return XT_CONTINUE;
39}
40
24de58f4
PNA
41static unsigned int xt_ct_target_v1(struct sk_buff *skb,
42 const struct xt_action_param *par)
43{
44 const struct xt_ct_target_info_v1 *info = par->targinfo;
45 struct nf_conn *ct = info->ct;
46
47 /* Previously seen (loopback)? Ignore. */
48 if (skb->nfct != NULL)
49 return XT_CONTINUE;
50
51 atomic_inc(&ct->ct_general.use);
52 skb->nfct = &ct->ct_general;
53 skb->nfctinfo = IP_CT_NEW;
54
55 return XT_CONTINUE;
56}
57
84f3bb9a
PM
58static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
59{
076f7839 60 if (par->family == NFPROTO_IPV4) {
84f3bb9a
PM
61 const struct ipt_entry *e = par->entryinfo;
62
63 if (e->ip.invflags & IPT_INV_PROTO)
64 return 0;
65 return e->ip.proto;
076f7839 66 } else if (par->family == NFPROTO_IPV6) {
84f3bb9a
PM
67 const struct ip6t_entry *e = par->entryinfo;
68
69 if (e->ipv6.invflags & IP6T_INV_PROTO)
70 return 0;
71 return e->ipv6.proto;
72 } else
73 return 0;
74}
75
24de58f4 76static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
84f3bb9a
PM
77{
78 struct xt_ct_target_info *info = par->targinfo;
79 struct nf_conntrack_tuple t;
80 struct nf_conn_help *help;
81 struct nf_conn *ct;
4a5a5c73 82 int ret = 0;
84f3bb9a
PM
83 u8 proto;
84
9bf04646
PNA
85 if (info->flags & ~XT_CT_NOTRACK)
86 return -EINVAL;
84f3bb9a
PM
87
88 if (info->flags & XT_CT_NOTRACK) {
5bfddbd4 89 ct = nf_ct_untracked_get();
84f3bb9a
PM
90 atomic_inc(&ct->ct_general.use);
91 goto out;
92 }
93
5d0aa2cc
PM
94#ifndef CONFIG_NF_CONNTRACK_ZONES
95 if (info->zone)
96 goto err1;
97#endif
98
4a5a5c73
JE
99 ret = nf_ct_l3proto_try_module_get(par->family);
100 if (ret < 0)
84f3bb9a
PM
101 goto err1;
102
103 memset(&t, 0, sizeof(t));
5d0aa2cc 104 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
4a5a5c73 105 ret = PTR_ERR(ct);
84f3bb9a
PM
106 if (IS_ERR(ct))
107 goto err2;
108
4a5a5c73 109 ret = 0;
84f3bb9a
PM
110 if ((info->ct_events || info->exp_events) &&
111 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
112 GFP_KERNEL))
113 goto err3;
114
9bf04646 115 if (info->helper[0]) {
4a5a5c73 116 ret = -ENOENT;
84f3bb9a 117 proto = xt_ct_find_proto(par);
a7fed762
JE
118 if (!proto) {
119 pr_info("You must specify a L4 protocol, "
120 "and not use inversions on it.\n");
84f3bb9a 121 goto err3;
a7fed762 122 }
84f3bb9a 123
4a5a5c73 124 ret = -ENOMEM;
84f3bb9a
PM
125 help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
126 if (help == NULL)
127 goto err3;
128
4a5a5c73 129 ret = -ENOENT;
84f3bb9a
PM
130 help->helper = nf_conntrack_helper_try_module_get(info->helper,
131 par->family,
132 proto);
a7fed762
JE
133 if (help->helper == NULL) {
134 pr_info("No such helper \"%s\"\n", info->helper);
84f3bb9a 135 goto err3;
a7fed762 136 }
84f3bb9a
PM
137 }
138
139 __set_bit(IPS_TEMPLATE_BIT, &ct->status);
140 __set_bit(IPS_CONFIRMED_BIT, &ct->status);
141out:
142 info->ct = ct;
d6b00a53 143 return 0;
84f3bb9a
PM
144
145err3:
146 nf_conntrack_free(ct);
147err2:
148 nf_ct_l3proto_module_put(par->family);
149err1:
4a5a5c73 150 return ret;
84f3bb9a
PM
151}
152
24de58f4
PNA
153static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
154{
155 struct xt_ct_target_info_v1 *info = par->targinfo;
156 struct nf_conntrack_tuple t;
157 struct nf_conn_help *help;
158 struct nf_conn *ct;
159 int ret = 0;
160 u8 proto;
161
162 if (info->flags & ~XT_CT_NOTRACK)
163 return -EINVAL;
164
165 if (info->flags & XT_CT_NOTRACK) {
166 ct = nf_ct_untracked_get();
167 atomic_inc(&ct->ct_general.use);
168 goto out;
169 }
170
171#ifndef CONFIG_NF_CONNTRACK_ZONES
172 if (info->zone)
173 goto err1;
174#endif
175
176 ret = nf_ct_l3proto_try_module_get(par->family);
177 if (ret < 0)
178 goto err1;
179
180 memset(&t, 0, sizeof(t));
181 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
182 ret = PTR_ERR(ct);
183 if (IS_ERR(ct))
184 goto err2;
185
186 ret = 0;
187 if ((info->ct_events || info->exp_events) &&
188 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
189 GFP_KERNEL))
190 goto err3;
191
192 if (info->helper[0]) {
193 ret = -ENOENT;
194 proto = xt_ct_find_proto(par);
195 if (!proto) {
196 pr_info("You must specify a L4 protocol, "
197 "and not use inversions on it.\n");
198 goto err3;
199 }
200
201 ret = -ENOMEM;
202 help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
203 if (help == NULL)
204 goto err3;
205
206 ret = -ENOENT;
207 help->helper = nf_conntrack_helper_try_module_get(info->helper,
208 par->family,
209 proto);
210 if (help->helper == NULL) {
211 pr_info("No such helper \"%s\"\n", info->helper);
212 goto err3;
213 }
214 }
215
216#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
217 if (info->timeout) {
218 typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
219 struct ctnl_timeout *timeout;
220 struct nf_conn_timeout *timeout_ext;
221
1ac0bf99 222 rcu_read_lock();
24de58f4
PNA
223 timeout_find_get =
224 rcu_dereference(nf_ct_timeout_find_get_hook);
225
226 if (timeout_find_get) {
227 const struct ipt_entry *e = par->entryinfo;
eeb4cb95 228 struct nf_conntrack_l4proto *l4proto;
24de58f4
PNA
229
230 if (e->ip.invflags & IPT_INV_PROTO) {
231 ret = -EINVAL;
232 pr_info("You cannot use inversion on "
233 "L4 protocol\n");
1ac0bf99 234 goto err4;
24de58f4
PNA
235 }
236 timeout = timeout_find_get(info->timeout);
237 if (timeout == NULL) {
238 ret = -ENOENT;
239 pr_info("No such timeout policy \"%s\"\n",
240 info->timeout);
1ac0bf99 241 goto err4;
24de58f4
PNA
242 }
243 if (timeout->l3num != par->family) {
244 ret = -EINVAL;
245 pr_info("Timeout policy `%s' can only be "
246 "used by L3 protocol number %d\n",
247 info->timeout, timeout->l3num);
1ac0bf99 248 goto err4;
24de58f4 249 }
eeb4cb95
PNA
250 /* Make sure the timeout policy matches any existing
251 * protocol tracker, otherwise default to generic.
252 */
253 l4proto = __nf_ct_l4proto_find(par->family,
254 e->ip.proto);
255 if (timeout->l4proto->l4proto != l4proto->l4proto) {
24de58f4
PNA
256 ret = -EINVAL;
257 pr_info("Timeout policy `%s' can only be "
258 "used by L4 protocol number %d\n",
c1ebd7df
PNA
259 info->timeout,
260 timeout->l4proto->l4proto);
1ac0bf99 261 goto err4;
24de58f4
PNA
262 }
263 timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
ca53e440 264 GFP_ATOMIC);
24de58f4
PNA
265 if (timeout_ext == NULL) {
266 ret = -ENOMEM;
1ac0bf99 267 goto err4;
24de58f4
PNA
268 }
269 } else {
270 ret = -ENOENT;
271 pr_info("Timeout policy base is empty\n");
1ac0bf99 272 goto err4;
24de58f4 273 }
1ac0bf99 274 rcu_read_unlock();
24de58f4
PNA
275 }
276#endif
277
278 __set_bit(IPS_TEMPLATE_BIT, &ct->status);
279 __set_bit(IPS_CONFIRMED_BIT, &ct->status);
280out:
281 info->ct = ct;
282 return 0;
283
44b52bcc 284#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
1ac0bf99
PNA
285err4:
286 rcu_read_unlock();
44b52bcc 287#endif
24de58f4
PNA
288err3:
289 nf_conntrack_free(ct);
290err2:
291 nf_ct_l3proto_module_put(par->family);
292err1:
293 return ret;
294}
295
296static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
84f3bb9a
PM
297{
298 struct xt_ct_target_info *info = par->targinfo;
299 struct nf_conn *ct = info->ct;
300 struct nf_conn_help *help;
301
5bfddbd4 302 if (!nf_ct_is_untracked(ct)) {
84f3bb9a
PM
303 help = nfct_help(ct);
304 if (help)
305 module_put(help->helper->me);
306
307 nf_ct_l3proto_module_put(par->family);
308 }
309 nf_ct_put(info->ct);
310}
311
24de58f4
PNA
312static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
313{
314 struct xt_ct_target_info_v1 *info = par->targinfo;
315 struct nf_conn *ct = info->ct;
316 struct nf_conn_help *help;
317#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
318 struct nf_conn_timeout *timeout_ext;
319 typeof(nf_ct_timeout_put_hook) timeout_put;
320#endif
321 if (!nf_ct_is_untracked(ct)) {
322 help = nfct_help(ct);
323 if (help)
324 module_put(help->helper->me);
325
326 nf_ct_l3proto_module_put(par->family);
327
328#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
1ac0bf99 329 rcu_read_lock();
24de58f4
PNA
330 timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
331
332 if (timeout_put) {
333 timeout_ext = nf_ct_timeout_find(ct);
334 if (timeout_ext)
335 timeout_put(timeout_ext->timeout);
336 }
1ac0bf99 337 rcu_read_unlock();
24de58f4
PNA
338#endif
339 }
340 nf_ct_put(info->ct);
341}
342
343static struct xt_target xt_ct_tg_reg[] __read_mostly = {
344 {
345 .name = "CT",
346 .family = NFPROTO_UNSPEC,
347 .targetsize = sizeof(struct xt_ct_target_info),
348 .checkentry = xt_ct_tg_check_v0,
349 .destroy = xt_ct_tg_destroy_v0,
350 .target = xt_ct_target_v0,
351 .table = "raw",
352 .me = THIS_MODULE,
353 },
354 {
355 .name = "CT",
356 .family = NFPROTO_UNSPEC,
357 .revision = 1,
358 .targetsize = sizeof(struct xt_ct_target_info_v1),
359 .checkentry = xt_ct_tg_check_v1,
360 .destroy = xt_ct_tg_destroy_v1,
361 .target = xt_ct_target_v1,
362 .table = "raw",
363 .me = THIS_MODULE,
364 },
84f3bb9a
PM
365};
366
367static int __init xt_ct_tg_init(void)
368{
24de58f4 369 return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
84f3bb9a
PM
370}
371
372static void __exit xt_ct_tg_exit(void)
373{
24de58f4 374 xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
84f3bb9a
PM
375}
376
377module_init(xt_ct_tg_init);
378module_exit(xt_ct_tg_exit);
379
380MODULE_LICENSE("GPL");
381MODULE_DESCRIPTION("Xtables: connection tracking target");
382MODULE_ALIAS("ipt_CT");
383MODULE_ALIAS("ip6t_CT");