GNU Linux-libre 4.19.286-gnu1
[releases.git] / net / netfilter / nf_conntrack_helper.c
1 /* Helper handling for netfilter. */
2
3 /* (C) 1999-2001 Paul `Rusty' Russell
4  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5  * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
6  * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/types.h>
14 #include <linux/netfilter.h>
15 #include <linux/module.h>
16 #include <linux/skbuff.h>
17 #include <linux/vmalloc.h>
18 #include <linux/stddef.h>
19 #include <linux/random.h>
20 #include <linux/err.h>
21 #include <linux/kernel.h>
22 #include <linux/netdevice.h>
23 #include <linux/rculist.h>
24 #include <linux/rtnetlink.h>
25
26 #include <net/netfilter/nf_conntrack.h>
27 #include <net/netfilter/nf_conntrack_l4proto.h>
28 #include <net/netfilter/nf_conntrack_helper.h>
29 #include <net/netfilter/nf_conntrack_core.h>
30 #include <net/netfilter/nf_conntrack_extend.h>
31 #include <net/netfilter/nf_log.h>
32
33 static DEFINE_MUTEX(nf_ct_helper_mutex);
34 struct hlist_head *nf_ct_helper_hash __read_mostly;
35 EXPORT_SYMBOL_GPL(nf_ct_helper_hash);
36 unsigned int nf_ct_helper_hsize __read_mostly;
37 EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
38 static unsigned int nf_ct_helper_count __read_mostly;
39
40 static bool nf_ct_auto_assign_helper __read_mostly = false;
41 module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
42 MODULE_PARM_DESC(nf_conntrack_helper,
43                  "Enable automatic conntrack helper assignment (default 0)");
44
45 #ifdef CONFIG_SYSCTL
46 static struct ctl_table helper_sysctl_table[] = {
47         {
48                 .procname       = "nf_conntrack_helper",
49                 .data           = &init_net.ct.sysctl_auto_assign_helper,
50                 .maxlen         = sizeof(unsigned int),
51                 .mode           = 0644,
52                 .proc_handler   = proc_dointvec,
53         },
54         {}
55 };
56
57 static int nf_conntrack_helper_init_sysctl(struct net *net)
58 {
59         struct ctl_table *table;
60
61         table = kmemdup(helper_sysctl_table, sizeof(helper_sysctl_table),
62                         GFP_KERNEL);
63         if (!table)
64                 goto out;
65
66         table[0].data = &net->ct.sysctl_auto_assign_helper;
67
68         /* Don't export sysctls to unprivileged users */
69         if (net->user_ns != &init_user_ns)
70                 table[0].procname = NULL;
71
72         net->ct.helper_sysctl_header =
73                 register_net_sysctl(net, "net/netfilter", table);
74
75         if (!net->ct.helper_sysctl_header) {
76                 pr_err("nf_conntrack_helper: can't register to sysctl.\n");
77                 goto out_register;
78         }
79         return 0;
80
81 out_register:
82         kfree(table);
83 out:
84         return -ENOMEM;
85 }
86
87 static void nf_conntrack_helper_fini_sysctl(struct net *net)
88 {
89         struct ctl_table *table;
90
91         table = net->ct.helper_sysctl_header->ctl_table_arg;
92         unregister_net_sysctl_table(net->ct.helper_sysctl_header);
93         kfree(table);
94 }
95 #else
96 static int nf_conntrack_helper_init_sysctl(struct net *net)
97 {
98         return 0;
99 }
100
101 static void nf_conntrack_helper_fini_sysctl(struct net *net)
102 {
103 }
104 #endif /* CONFIG_SYSCTL */
105
106 /* Stupid hash, but collision free for the default registrations of the
107  * helpers currently in the kernel. */
108 static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
109 {
110         return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
111                 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
112 }
113
114 static struct nf_conntrack_helper *
115 __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
116 {
117         struct nf_conntrack_helper *helper;
118         struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
119         unsigned int h;
120
121         if (!nf_ct_helper_count)
122                 return NULL;
123
124         h = helper_hash(tuple);
125         hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) {
126                 if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
127                         return helper;
128         }
129         return NULL;
130 }
131
132 struct nf_conntrack_helper *
133 __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
134 {
135         struct nf_conntrack_helper *h;
136         unsigned int i;
137
138         for (i = 0; i < nf_ct_helper_hsize; i++) {
139                 hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
140                         if (strcmp(h->name, name))
141                                 continue;
142
143                         if (h->tuple.src.l3num != NFPROTO_UNSPEC &&
144                             h->tuple.src.l3num != l3num)
145                                 continue;
146
147                         if (h->tuple.dst.protonum == protonum)
148                                 return h;
149                 }
150         }
151         return NULL;
152 }
153 EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find);
154
155 struct nf_conntrack_helper *
156 nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
157 {
158         struct nf_conntrack_helper *h;
159
160         rcu_read_lock();
161
162         h = __nf_conntrack_helper_find(name, l3num, protonum);
163 #ifdef CONFIG_MODULES
164         if (h == NULL) {
165                 rcu_read_unlock();
166                 if (request_module("nfct-helper-%s", name) == 0) {
167                         rcu_read_lock();
168                         h = __nf_conntrack_helper_find(name, l3num, protonum);
169                 } else {
170                         return h;
171                 }
172         }
173 #endif
174         if (h != NULL && !try_module_get(h->me))
175                 h = NULL;
176         if (h != NULL && !refcount_inc_not_zero(&h->refcnt)) {
177                 module_put(h->me);
178                 h = NULL;
179         }
180
181         rcu_read_unlock();
182
183         return h;
184 }
185 EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
186
187 void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
188 {
189         refcount_dec(&helper->refcnt);
190         module_put(helper->me);
191 }
192 EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);
193
194 struct nf_conn_help *
195 nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
196 {
197         struct nf_conn_help *help;
198
199         help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
200         if (help)
201                 INIT_HLIST_HEAD(&help->expectations);
202         else
203                 pr_debug("failed to add helper extension area");
204         return help;
205 }
206 EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
207
208 static struct nf_conntrack_helper *
209 nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
210 {
211         if (!net->ct.sysctl_auto_assign_helper) {
212                 if (net->ct.auto_assign_helper_warned)
213                         return NULL;
214                 if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple))
215                         return NULL;
216                 pr_info("nf_conntrack: default automatic helper assignment "
217                         "has been turned off for security reasons and CT-based "
218                         " firewall rule not found. Use the iptables CT target "
219                         "to attach helpers instead.\n");
220                 net->ct.auto_assign_helper_warned = 1;
221                 return NULL;
222         }
223
224         return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
225 }
226
227
228 int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
229                               gfp_t flags)
230 {
231         struct nf_conntrack_helper *helper = NULL;
232         struct nf_conn_help *help;
233         struct net *net = nf_ct_net(ct);
234
235         /* We already got a helper explicitly attached. The function
236          * nf_conntrack_alter_reply - in case NAT is in use - asks for looking
237          * the helper up again. Since now the user is in full control of
238          * making consistent helper configurations, skip this automatic
239          * re-lookup, otherwise we'll lose the helper.
240          */
241         if (test_bit(IPS_HELPER_BIT, &ct->status))
242                 return 0;
243
244         if (tmpl != NULL) {
245                 help = nfct_help(tmpl);
246                 if (help != NULL) {
247                         helper = help->helper;
248                         set_bit(IPS_HELPER_BIT, &ct->status);
249                 }
250         }
251
252         help = nfct_help(ct);
253
254         if (helper == NULL) {
255                 helper = nf_ct_lookup_helper(ct, net);
256                 if (helper == NULL) {
257                         if (help)
258                                 RCU_INIT_POINTER(help->helper, NULL);
259                         return 0;
260                 }
261         }
262
263         if (help == NULL) {
264                 help = nf_ct_helper_ext_add(ct, flags);
265                 if (help == NULL)
266                         return -ENOMEM;
267         } else {
268                 /* We only allow helper re-assignment of the same sort since
269                  * we cannot reallocate the helper extension area.
270                  */
271                 struct nf_conntrack_helper *tmp = rcu_dereference(help->helper);
272
273                 if (tmp && tmp->help != helper->help) {
274                         RCU_INIT_POINTER(help->helper, NULL);
275                         return 0;
276                 }
277         }
278
279         rcu_assign_pointer(help->helper, helper);
280
281         return 0;
282 }
283 EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
284
285 /* appropriate ct lock protecting must be taken by caller */
286 static int unhelp(struct nf_conn *ct, void *me)
287 {
288         struct nf_conn_help *help = nfct_help(ct);
289
290         if (help && rcu_dereference_raw(help->helper) == me) {
291                 nf_conntrack_event(IPCT_HELPER, ct);
292                 RCU_INIT_POINTER(help->helper, NULL);
293         }
294
295         /* We are not intended to delete this conntrack. */
296         return 0;
297 }
298
299 void nf_ct_helper_destroy(struct nf_conn *ct)
300 {
301         struct nf_conn_help *help = nfct_help(ct);
302         struct nf_conntrack_helper *helper;
303
304         if (help) {
305                 rcu_read_lock();
306                 helper = rcu_dereference(help->helper);
307                 if (helper && helper->destroy)
308                         helper->destroy(ct);
309                 rcu_read_unlock();
310         }
311 }
312
313 static LIST_HEAD(nf_ct_helper_expectfn_list);
314
315 void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
316 {
317         spin_lock_bh(&nf_conntrack_expect_lock);
318         list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
319         spin_unlock_bh(&nf_conntrack_expect_lock);
320 }
321 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
322
323 void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
324 {
325         spin_lock_bh(&nf_conntrack_expect_lock);
326         list_del_rcu(&n->head);
327         spin_unlock_bh(&nf_conntrack_expect_lock);
328 }
329 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
330
331 /* Caller should hold the rcu lock */
332 struct nf_ct_helper_expectfn *
333 nf_ct_helper_expectfn_find_by_name(const char *name)
334 {
335         struct nf_ct_helper_expectfn *cur;
336         bool found = false;
337
338         list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
339                 if (!strcmp(cur->name, name)) {
340                         found = true;
341                         break;
342                 }
343         }
344         return found ? cur : NULL;
345 }
346 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
347
348 /* Caller should hold the rcu lock */
349 struct nf_ct_helper_expectfn *
350 nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
351 {
352         struct nf_ct_helper_expectfn *cur;
353         bool found = false;
354
355         list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
356                 if (cur->expectfn == symbol) {
357                         found = true;
358                         break;
359                 }
360         }
361         return found ? cur : NULL;
362 }
363 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
364
365 __printf(3, 4)
366 void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
367                       const char *fmt, ...)
368 {
369         const struct nf_conn_help *help;
370         const struct nf_conntrack_helper *helper;
371         struct va_format vaf;
372         va_list args;
373
374         va_start(args, fmt);
375
376         vaf.fmt = fmt;
377         vaf.va = &args;
378
379         /* Called from the helper function, this call never fails */
380         help = nfct_help(ct);
381
382         /* rcu_read_lock()ed by nf_hook_thresh */
383         helper = rcu_dereference(help->helper);
384
385         nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
386                       "nf_ct_%s: dropping packet: %pV ", helper->name, &vaf);
387
388         va_end(args);
389 }
390 EXPORT_SYMBOL_GPL(nf_ct_helper_log);
391
392 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
393 {
394         struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
395         unsigned int h = helper_hash(&me->tuple);
396         struct nf_conntrack_helper *cur;
397         int ret = 0, i;
398
399         BUG_ON(me->expect_policy == NULL);
400         BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
401         BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
402
403         if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
404                 return -EINVAL;
405
406         mutex_lock(&nf_ct_helper_mutex);
407         for (i = 0; i < nf_ct_helper_hsize; i++) {
408                 hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) {
409                         if (!strcmp(cur->name, me->name) &&
410                             (cur->tuple.src.l3num == NFPROTO_UNSPEC ||
411                              cur->tuple.src.l3num == me->tuple.src.l3num) &&
412                             cur->tuple.dst.protonum == me->tuple.dst.protonum) {
413                                 ret = -EEXIST;
414                                 goto out;
415                         }
416                 }
417         }
418
419         /* avoid unpredictable behaviour for auto_assign_helper */
420         if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) {
421                 hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
422                         if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple,
423                                                      &mask)) {
424                                 ret = -EEXIST;
425                                 goto out;
426                         }
427                 }
428         }
429         refcount_set(&me->refcnt, 1);
430         hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
431         nf_ct_helper_count++;
432 out:
433         mutex_unlock(&nf_ct_helper_mutex);
434         return ret;
435 }
436 EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
437
438 static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
439 {
440         struct nf_conn_help *help = nfct_help(exp->master);
441         const struct nf_conntrack_helper *me = data;
442         const struct nf_conntrack_helper *this;
443
444         if (exp->helper == me)
445                 return true;
446
447         this = rcu_dereference_protected(help->helper,
448                                          lockdep_is_held(&nf_conntrack_expect_lock));
449         return this == me;
450 }
451
452 void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
453 {
454         mutex_lock(&nf_ct_helper_mutex);
455         hlist_del_rcu(&me->hnode);
456         nf_ct_helper_count--;
457         mutex_unlock(&nf_ct_helper_mutex);
458
459         /* Make sure every nothing is still using the helper unless its a
460          * connection in the hash.
461          */
462         synchronize_rcu();
463
464         nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
465         nf_ct_iterate_destroy(unhelp, me);
466
467         /* Maybe someone has gotten the helper already when unhelp above.
468          * So need to wait it.
469          */
470         synchronize_rcu();
471 }
472 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
473
474 void nf_ct_helper_init(struct nf_conntrack_helper *helper,
475                        u16 l3num, u16 protonum, const char *name,
476                        u16 default_port, u16 spec_port, u32 id,
477                        const struct nf_conntrack_expect_policy *exp_pol,
478                        u32 expect_class_max,
479                        int (*help)(struct sk_buff *skb, unsigned int protoff,
480                                    struct nf_conn *ct,
481                                    enum ip_conntrack_info ctinfo),
482                        int (*from_nlattr)(struct nlattr *attr,
483                                           struct nf_conn *ct),
484                        struct module *module)
485 {
486         helper->tuple.src.l3num = l3num;
487         helper->tuple.dst.protonum = protonum;
488         helper->tuple.src.u.all = htons(spec_port);
489         helper->expect_policy = exp_pol;
490         helper->expect_class_max = expect_class_max;
491         helper->help = help;
492         helper->from_nlattr = from_nlattr;
493         helper->me = module;
494
495         if (spec_port == default_port)
496                 snprintf(helper->name, sizeof(helper->name), "%s", name);
497         else
498                 snprintf(helper->name, sizeof(helper->name), "%s-%u", name, id);
499 }
500 EXPORT_SYMBOL_GPL(nf_ct_helper_init);
501
502 int nf_conntrack_helpers_register(struct nf_conntrack_helper *helper,
503                                   unsigned int n)
504 {
505         unsigned int i;
506         int err = 0;
507
508         for (i = 0; i < n; i++) {
509                 err = nf_conntrack_helper_register(&helper[i]);
510                 if (err < 0)
511                         goto err;
512         }
513
514         return err;
515 err:
516         if (i > 0)
517                 nf_conntrack_helpers_unregister(helper, i);
518         return err;
519 }
520 EXPORT_SYMBOL_GPL(nf_conntrack_helpers_register);
521
522 void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *helper,
523                                 unsigned int n)
524 {
525         while (n-- > 0)
526                 nf_conntrack_helper_unregister(&helper[n]);
527 }
528 EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
529
530 static const struct nf_ct_ext_type helper_extend = {
531         .len    = sizeof(struct nf_conn_help),
532         .align  = __alignof__(struct nf_conn_help),
533         .id     = NF_CT_EXT_HELPER,
534 };
535
536 int nf_conntrack_helper_pernet_init(struct net *net)
537 {
538         net->ct.auto_assign_helper_warned = false;
539         net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
540         return nf_conntrack_helper_init_sysctl(net);
541 }
542
543 void nf_conntrack_helper_pernet_fini(struct net *net)
544 {
545         nf_conntrack_helper_fini_sysctl(net);
546 }
547
548 int nf_conntrack_helper_init(void)
549 {
550         int ret;
551         nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
552         nf_ct_helper_hash =
553                 nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
554         if (!nf_ct_helper_hash)
555                 return -ENOMEM;
556
557         ret = nf_ct_extend_register(&helper_extend);
558         if (ret < 0) {
559                 pr_err("nf_ct_helper: Unable to register helper extension.\n");
560                 goto out_extend;
561         }
562
563         return 0;
564 out_extend:
565         kvfree(nf_ct_helper_hash);
566         return ret;
567 }
568
569 void nf_conntrack_helper_fini(void)
570 {
571         nf_ct_extend_unregister(&helper_extend);
572         kvfree(nf_ct_helper_hash);
573 }