Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv6 / netfilter / ip6_tables.c
1 /*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6 * Copyright (c) 2006-2010 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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 #include <linux/capability.h>
14 #include <linux/in.h>
15 #include <linux/skbuff.h>
16 #include <linux/kmod.h>
17 #include <linux/vmalloc.h>
18 #include <linux/netdevice.h>
19 #include <linux/module.h>
20 #include <linux/poison.h>
21 #include <linux/icmpv6.h>
22 #include <net/ipv6.h>
23 #include <net/compat.h>
24 #include <asm/uaccess.h>
25 #include <linux/mutex.h>
26 #include <linux/proc_fs.h>
27 #include <linux/err.h>
28 #include <linux/cpumask.h>
29
30 #include <linux/netfilter_ipv6/ip6_tables.h>
31 #include <linux/netfilter/x_tables.h>
32 #include <net/netfilter/nf_log.h>
33 #include "../../netfilter/xt_repldata.h"
34
35 MODULE_LICENSE("GPL");
36 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
37 MODULE_DESCRIPTION("IPv6 packet filter");
38
39 /*#define DEBUG_IP_FIREWALL*/
40 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
41 /*#define DEBUG_IP_FIREWALL_USER*/
42
43 #ifdef DEBUG_IP_FIREWALL
44 #define dprintf(format, args...) pr_info(format , ## args)
45 #else
46 #define dprintf(format, args...)
47 #endif
48
49 #ifdef DEBUG_IP_FIREWALL_USER
50 #define duprintf(format, args...) pr_info(format , ## args)
51 #else
52 #define duprintf(format, args...)
53 #endif
54
55 #ifdef CONFIG_NETFILTER_DEBUG
56 #define IP_NF_ASSERT(x) WARN_ON(!(x))
57 #else
58 #define IP_NF_ASSERT(x)
59 #endif
60
61 #if 0
62 /* All the better to debug you with... */
63 #define static
64 #define inline
65 #endif
66
67 void *ip6t_alloc_initial_table(const struct xt_table *info)
68 {
69 return xt_alloc_initial_table(ip6t, IP6T);
70 }
71 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
72
73 /*
74 We keep a set of rules for each CPU, so we can avoid write-locking
75 them in the softirq when updating the counters and therefore
76 only need to read-lock in the softirq; doing a write_lock_bh() in user
77 context stops packets coming through and allows user context to read
78 the counters or update the rules.
79
80 Hence the start of any table is given by get_table() below. */
81
82 /* Returns whether matches rule or not. */
83 /* Performance critical - called for every packet */
84 static inline bool
85 ip6_packet_match(const struct sk_buff *skb,
86 const char *indev,
87 const char *outdev,
88 const struct ip6t_ip6 *ip6info,
89 unsigned int *protoff,
90 int *fragoff, bool *hotdrop)
91 {
92 unsigned long ret;
93 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
94
95 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
96
97 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
98 &ip6info->src), IP6T_INV_SRCIP) ||
99 FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
100 &ip6info->dst), IP6T_INV_DSTIP)) {
101 dprintf("Source or dest mismatch.\n");
102 /*
103 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
104 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
105 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
106 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
107 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
108 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
109 return false;
110 }
111
112 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
113
114 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
115 dprintf("VIA in mismatch (%s vs %s).%s\n",
116 indev, ip6info->iniface,
117 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
118 return false;
119 }
120
121 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
122
123 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
124 dprintf("VIA out mismatch (%s vs %s).%s\n",
125 outdev, ip6info->outiface,
126 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
127 return false;
128 }
129
130 /* ... might want to do something with class and flowlabel here ... */
131
132 /* look for the desired protocol header */
133 if((ip6info->flags & IP6T_F_PROTO)) {
134 int protohdr;
135 unsigned short _frag_off;
136
137 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
138 if (protohdr < 0) {
139 if (_frag_off == 0)
140 *hotdrop = true;
141 return false;
142 }
143 *fragoff = _frag_off;
144
145 dprintf("Packet protocol %hi ?= %s%hi.\n",
146 protohdr,
147 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
148 ip6info->proto);
149
150 if (ip6info->proto == protohdr) {
151 if(ip6info->invflags & IP6T_INV_PROTO) {
152 return false;
153 }
154 return true;
155 }
156
157 /* We need match for the '-p all', too! */
158 if ((ip6info->proto != 0) &&
159 !(ip6info->invflags & IP6T_INV_PROTO))
160 return false;
161 }
162 return true;
163 }
164
165 /* should be ip6 safe */
166 static bool
167 ip6_checkentry(const struct ip6t_ip6 *ipv6)
168 {
169 if (ipv6->flags & ~IP6T_F_MASK) {
170 duprintf("Unknown flag bits set: %08X\n",
171 ipv6->flags & ~IP6T_F_MASK);
172 return false;
173 }
174 if (ipv6->invflags & ~IP6T_INV_MASK) {
175 duprintf("Unknown invflag bits set: %08X\n",
176 ipv6->invflags & ~IP6T_INV_MASK);
177 return false;
178 }
179 return true;
180 }
181
182 static unsigned int
183 ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
184 {
185 net_info_ratelimited("error: `%s'\n", (const char *)par->targinfo);
186
187 return NF_DROP;
188 }
189
190 static inline struct ip6t_entry *
191 get_entry(const void *base, unsigned int offset)
192 {
193 return (struct ip6t_entry *)(base + offset);
194 }
195
196 /* All zeroes == unconditional rule. */
197 /* Mildly perf critical (only if packet tracing is on) */
198 static inline bool unconditional(const struct ip6t_ip6 *ipv6)
199 {
200 static const struct ip6t_ip6 uncond;
201
202 return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
203 }
204
205 static inline const struct xt_entry_target *
206 ip6t_get_target_c(const struct ip6t_entry *e)
207 {
208 return ip6t_get_target((struct ip6t_entry *)e);
209 }
210
211 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
212 /* This cries for unification! */
213 static const char *const hooknames[] = {
214 [NF_INET_PRE_ROUTING] = "PREROUTING",
215 [NF_INET_LOCAL_IN] = "INPUT",
216 [NF_INET_FORWARD] = "FORWARD",
217 [NF_INET_LOCAL_OUT] = "OUTPUT",
218 [NF_INET_POST_ROUTING] = "POSTROUTING",
219 };
220
221 enum nf_ip_trace_comments {
222 NF_IP6_TRACE_COMMENT_RULE,
223 NF_IP6_TRACE_COMMENT_RETURN,
224 NF_IP6_TRACE_COMMENT_POLICY,
225 };
226
227 static const char *const comments[] = {
228 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
229 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
230 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
231 };
232
233 static struct nf_loginfo trace_loginfo = {
234 .type = NF_LOG_TYPE_LOG,
235 .u = {
236 .log = {
237 .level = 4,
238 .logflags = NF_LOG_MASK,
239 },
240 },
241 };
242
243 /* Mildly perf critical (only if packet tracing is on) */
244 static inline int
245 get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
246 const char *hookname, const char **chainname,
247 const char **comment, unsigned int *rulenum)
248 {
249 const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
250
251 if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
252 /* Head of user chain: ERROR target with chainname */
253 *chainname = t->target.data;
254 (*rulenum) = 0;
255 } else if (s == e) {
256 (*rulenum)++;
257
258 if (s->target_offset == sizeof(struct ip6t_entry) &&
259 strcmp(t->target.u.kernel.target->name,
260 XT_STANDARD_TARGET) == 0 &&
261 t->verdict < 0 &&
262 unconditional(&s->ipv6)) {
263 /* Tail of chains: STANDARD target (return/policy) */
264 *comment = *chainname == hookname
265 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
266 : comments[NF_IP6_TRACE_COMMENT_RETURN];
267 }
268 return 1;
269 } else
270 (*rulenum)++;
271
272 return 0;
273 }
274
275 static void trace_packet(const struct sk_buff *skb,
276 unsigned int hook,
277 const struct net_device *in,
278 const struct net_device *out,
279 const char *tablename,
280 const struct xt_table_info *private,
281 const struct ip6t_entry *e)
282 {
283 const void *table_base;
284 const struct ip6t_entry *root;
285 const char *hookname, *chainname, *comment;
286 const struct ip6t_entry *iter;
287 unsigned int rulenum = 0;
288 struct net *net = dev_net(in ? in : out);
289
290 table_base = private->entries[smp_processor_id()];
291 root = get_entry(table_base, private->hook_entry[hook]);
292
293 hookname = chainname = hooknames[hook];
294 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
295
296 xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
297 if (get_chainname_rulenum(iter, e, hookname,
298 &chainname, &comment, &rulenum) != 0)
299 break;
300
301 nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
302 "TRACE: %s:%s:%s:%u ",
303 tablename, chainname, comment, rulenum);
304 }
305 #endif
306
307 static inline __pure struct ip6t_entry *
308 ip6t_next_entry(const struct ip6t_entry *entry)
309 {
310 return (void *)entry + entry->next_offset;
311 }
312
313 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
314 unsigned int
315 ip6t_do_table(struct sk_buff *skb,
316 unsigned int hook,
317 const struct net_device *in,
318 const struct net_device *out,
319 struct xt_table *table)
320 {
321 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
322 /* Initializing verdict to NF_DROP keeps gcc happy. */
323 unsigned int verdict = NF_DROP;
324 const char *indev, *outdev;
325 const void *table_base;
326 struct ip6t_entry *e, **jumpstack;
327 unsigned int *stackptr, origptr, cpu;
328 const struct xt_table_info *private;
329 struct xt_action_param acpar;
330 unsigned int addend;
331
332 /* Initialization */
333 indev = in ? in->name : nulldevname;
334 outdev = out ? out->name : nulldevname;
335 /* We handle fragments by dealing with the first fragment as
336 * if it was a normal packet. All other fragments are treated
337 * normally, except that they will NEVER match rules that ask
338 * things we don't know, ie. tcp syn flag or ports). If the
339 * rule is also a fragment-specific rule, non-fragments won't
340 * match it. */
341 acpar.hotdrop = false;
342 acpar.in = in;
343 acpar.out = out;
344 acpar.family = NFPROTO_IPV6;
345 acpar.hooknum = hook;
346
347 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
348
349 local_bh_disable();
350 addend = xt_write_recseq_begin();
351 private = table->private;
352 cpu = smp_processor_id();
353 table_base = private->entries[cpu];
354 jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
355 stackptr = per_cpu_ptr(private->stackptr, cpu);
356 origptr = *stackptr;
357
358 e = get_entry(table_base, private->hook_entry[hook]);
359
360 do {
361 const struct xt_entry_target *t;
362 const struct xt_entry_match *ematch;
363
364 IP_NF_ASSERT(e);
365 acpar.thoff = 0;
366 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
367 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
368 no_match:
369 e = ip6t_next_entry(e);
370 continue;
371 }
372
373 xt_ematch_foreach(ematch, e) {
374 acpar.match = ematch->u.kernel.match;
375 acpar.matchinfo = ematch->data;
376 if (!acpar.match->match(skb, &acpar))
377 goto no_match;
378 }
379
380 ADD_COUNTER(e->counters, skb->len, 1);
381
382 t = ip6t_get_target_c(e);
383 IP_NF_ASSERT(t->u.kernel.target);
384
385 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
386 /* The packet is traced: log it */
387 if (unlikely(skb->nf_trace))
388 trace_packet(skb, hook, in, out,
389 table->name, private, e);
390 #endif
391 /* Standard target? */
392 if (!t->u.kernel.target->target) {
393 int v;
394
395 v = ((struct xt_standard_target *)t)->verdict;
396 if (v < 0) {
397 /* Pop from stack? */
398 if (v != XT_RETURN) {
399 verdict = (unsigned int)(-v) - 1;
400 break;
401 }
402 if (*stackptr <= origptr)
403 e = get_entry(table_base,
404 private->underflow[hook]);
405 else
406 e = ip6t_next_entry(jumpstack[--*stackptr]);
407 continue;
408 }
409 if (table_base + v != ip6t_next_entry(e) &&
410 !(e->ipv6.flags & IP6T_F_GOTO)) {
411 if (*stackptr >= private->stacksize) {
412 verdict = NF_DROP;
413 break;
414 }
415 jumpstack[(*stackptr)++] = e;
416 }
417
418 e = get_entry(table_base, v);
419 continue;
420 }
421
422 acpar.target = t->u.kernel.target;
423 acpar.targinfo = t->data;
424
425 verdict = t->u.kernel.target->target(skb, &acpar);
426 if (verdict == XT_CONTINUE)
427 e = ip6t_next_entry(e);
428 else
429 /* Verdict */
430 break;
431 } while (!acpar.hotdrop);
432
433 *stackptr = origptr;
434
435 xt_write_recseq_end(addend);
436 local_bh_enable();
437
438 #ifdef DEBUG_ALLOW_ALL
439 return NF_ACCEPT;
440 #else
441 if (acpar.hotdrop)
442 return NF_DROP;
443 else return verdict;
444 #endif
445 }
446
447 /* Figures out from what hook each rule can be called: returns 0 if
448 there are loops. Puts hook bitmask in comefrom. */
449 static int
450 mark_source_chains(const struct xt_table_info *newinfo,
451 unsigned int valid_hooks, void *entry0)
452 {
453 unsigned int hook;
454
455 /* No recursion; use packet counter to save back ptrs (reset
456 to 0 as we leave), and comefrom to save source hook bitmask */
457 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
458 unsigned int pos = newinfo->hook_entry[hook];
459 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
460
461 if (!(valid_hooks & (1 << hook)))
462 continue;
463
464 /* Set initial back pointer. */
465 e->counters.pcnt = pos;
466
467 for (;;) {
468 const struct xt_standard_target *t
469 = (void *)ip6t_get_target_c(e);
470 int visited = e->comefrom & (1 << hook);
471
472 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
473 pr_err("iptables: loop hook %u pos %u %08X.\n",
474 hook, pos, e->comefrom);
475 return 0;
476 }
477 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
478
479 /* Unconditional return/END. */
480 if ((e->target_offset == sizeof(struct ip6t_entry) &&
481 (strcmp(t->target.u.user.name,
482 XT_STANDARD_TARGET) == 0) &&
483 t->verdict < 0 &&
484 unconditional(&e->ipv6)) || visited) {
485 unsigned int oldpos, size;
486
487 if ((strcmp(t->target.u.user.name,
488 XT_STANDARD_TARGET) == 0) &&
489 t->verdict < -NF_MAX_VERDICT - 1) {
490 duprintf("mark_source_chains: bad "
491 "negative verdict (%i)\n",
492 t->verdict);
493 return 0;
494 }
495
496 /* Return: backtrack through the last
497 big jump. */
498 do {
499 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
500 #ifdef DEBUG_IP_FIREWALL_USER
501 if (e->comefrom
502 & (1 << NF_INET_NUMHOOKS)) {
503 duprintf("Back unset "
504 "on hook %u "
505 "rule %u\n",
506 hook, pos);
507 }
508 #endif
509 oldpos = pos;
510 pos = e->counters.pcnt;
511 e->counters.pcnt = 0;
512
513 /* We're at the start. */
514 if (pos == oldpos)
515 goto next;
516
517 e = (struct ip6t_entry *)
518 (entry0 + pos);
519 } while (oldpos == pos + e->next_offset);
520
521 /* Move along one */
522 size = e->next_offset;
523 e = (struct ip6t_entry *)
524 (entry0 + pos + size);
525 e->counters.pcnt = pos;
526 pos += size;
527 } else {
528 int newpos = t->verdict;
529
530 if (strcmp(t->target.u.user.name,
531 XT_STANDARD_TARGET) == 0 &&
532 newpos >= 0) {
533 if (newpos > newinfo->size -
534 sizeof(struct ip6t_entry)) {
535 duprintf("mark_source_chains: "
536 "bad verdict (%i)\n",
537 newpos);
538 return 0;
539 }
540 /* This a jump; chase it. */
541 duprintf("Jump rule %u -> %u\n",
542 pos, newpos);
543 } else {
544 /* ... this is a fallthru */
545 newpos = pos + e->next_offset;
546 }
547 e = (struct ip6t_entry *)
548 (entry0 + newpos);
549 e->counters.pcnt = pos;
550 pos = newpos;
551 }
552 }
553 next:
554 duprintf("Finished chain %u\n", hook);
555 }
556 return 1;
557 }
558
559 static void cleanup_match(struct xt_entry_match *m, struct net *net)
560 {
561 struct xt_mtdtor_param par;
562
563 par.net = net;
564 par.match = m->u.kernel.match;
565 par.matchinfo = m->data;
566 par.family = NFPROTO_IPV6;
567 if (par.match->destroy != NULL)
568 par.match->destroy(&par);
569 module_put(par.match->me);
570 }
571
572 static int
573 check_entry(const struct ip6t_entry *e, const char *name)
574 {
575 const struct xt_entry_target *t;
576
577 if (!ip6_checkentry(&e->ipv6)) {
578 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
579 return -EINVAL;
580 }
581
582 if (e->target_offset + sizeof(struct xt_entry_target) >
583 e->next_offset)
584 return -EINVAL;
585
586 t = ip6t_get_target_c(e);
587 if (e->target_offset + t->u.target_size > e->next_offset)
588 return -EINVAL;
589
590 return 0;
591 }
592
593 static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
594 {
595 const struct ip6t_ip6 *ipv6 = par->entryinfo;
596 int ret;
597
598 par->match = m->u.kernel.match;
599 par->matchinfo = m->data;
600
601 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
602 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
603 if (ret < 0) {
604 duprintf("ip_tables: check failed for `%s'.\n",
605 par.match->name);
606 return ret;
607 }
608 return 0;
609 }
610
611 static int
612 find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
613 {
614 struct xt_match *match;
615 int ret;
616
617 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
618 m->u.user.revision);
619 if (IS_ERR(match)) {
620 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
621 return PTR_ERR(match);
622 }
623 m->u.kernel.match = match;
624
625 ret = check_match(m, par);
626 if (ret)
627 goto err;
628
629 return 0;
630 err:
631 module_put(m->u.kernel.match->me);
632 return ret;
633 }
634
635 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
636 {
637 struct xt_entry_target *t = ip6t_get_target(e);
638 struct xt_tgchk_param par = {
639 .net = net,
640 .table = name,
641 .entryinfo = e,
642 .target = t->u.kernel.target,
643 .targinfo = t->data,
644 .hook_mask = e->comefrom,
645 .family = NFPROTO_IPV6,
646 };
647 int ret;
648
649 t = ip6t_get_target(e);
650 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
651 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
652 if (ret < 0) {
653 duprintf("ip_tables: check failed for `%s'.\n",
654 t->u.kernel.target->name);
655 return ret;
656 }
657 return 0;
658 }
659
660 static int
661 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
662 unsigned int size)
663 {
664 struct xt_entry_target *t;
665 struct xt_target *target;
666 int ret;
667 unsigned int j;
668 struct xt_mtchk_param mtpar;
669 struct xt_entry_match *ematch;
670
671 ret = check_entry(e, name);
672 if (ret)
673 return ret;
674
675 j = 0;
676 mtpar.net = net;
677 mtpar.table = name;
678 mtpar.entryinfo = &e->ipv6;
679 mtpar.hook_mask = e->comefrom;
680 mtpar.family = NFPROTO_IPV6;
681 xt_ematch_foreach(ematch, e) {
682 ret = find_check_match(ematch, &mtpar);
683 if (ret != 0)
684 goto cleanup_matches;
685 ++j;
686 }
687
688 t = ip6t_get_target(e);
689 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
690 t->u.user.revision);
691 if (IS_ERR(target)) {
692 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
693 ret = PTR_ERR(target);
694 goto cleanup_matches;
695 }
696 t->u.kernel.target = target;
697
698 ret = check_target(e, net, name);
699 if (ret)
700 goto err;
701 return 0;
702 err:
703 module_put(t->u.kernel.target->me);
704 cleanup_matches:
705 xt_ematch_foreach(ematch, e) {
706 if (j-- == 0)
707 break;
708 cleanup_match(ematch, net);
709 }
710 return ret;
711 }
712
713 static bool check_underflow(const struct ip6t_entry *e)
714 {
715 const struct xt_entry_target *t;
716 unsigned int verdict;
717
718 if (!unconditional(&e->ipv6))
719 return false;
720 t = ip6t_get_target_c(e);
721 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
722 return false;
723 verdict = ((struct xt_standard_target *)t)->verdict;
724 verdict = -verdict - 1;
725 return verdict == NF_DROP || verdict == NF_ACCEPT;
726 }
727
728 static int
729 check_entry_size_and_hooks(struct ip6t_entry *e,
730 struct xt_table_info *newinfo,
731 const unsigned char *base,
732 const unsigned char *limit,
733 const unsigned int *hook_entries,
734 const unsigned int *underflows,
735 unsigned int valid_hooks)
736 {
737 unsigned int h;
738
739 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
740 (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
741 duprintf("Bad offset %p\n", e);
742 return -EINVAL;
743 }
744
745 if (e->next_offset
746 < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
747 duprintf("checking: element %p size %u\n",
748 e, e->next_offset);
749 return -EINVAL;
750 }
751
752 /* Check hooks & underflows */
753 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
754 if (!(valid_hooks & (1 << h)))
755 continue;
756 if ((unsigned char *)e - base == hook_entries[h])
757 newinfo->hook_entry[h] = hook_entries[h];
758 if ((unsigned char *)e - base == underflows[h]) {
759 if (!check_underflow(e)) {
760 pr_err("Underflows must be unconditional and "
761 "use the STANDARD target with "
762 "ACCEPT/DROP\n");
763 return -EINVAL;
764 }
765 newinfo->underflow[h] = underflows[h];
766 }
767 }
768
769 /* Clear counters and comefrom */
770 e->counters = ((struct xt_counters) { 0, 0 });
771 e->comefrom = 0;
772 return 0;
773 }
774
775 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
776 {
777 struct xt_tgdtor_param par;
778 struct xt_entry_target *t;
779 struct xt_entry_match *ematch;
780
781 /* Cleanup all matches */
782 xt_ematch_foreach(ematch, e)
783 cleanup_match(ematch, net);
784 t = ip6t_get_target(e);
785
786 par.net = net;
787 par.target = t->u.kernel.target;
788 par.targinfo = t->data;
789 par.family = NFPROTO_IPV6;
790 if (par.target->destroy != NULL)
791 par.target->destroy(&par);
792 module_put(par.target->me);
793 }
794
795 /* Checks and translates the user-supplied table segment (held in
796 newinfo) */
797 static int
798 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
799 const struct ip6t_replace *repl)
800 {
801 struct ip6t_entry *iter;
802 unsigned int i;
803 int ret = 0;
804
805 newinfo->size = repl->size;
806 newinfo->number = repl->num_entries;
807
808 /* Init all hooks to impossible value. */
809 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
810 newinfo->hook_entry[i] = 0xFFFFFFFF;
811 newinfo->underflow[i] = 0xFFFFFFFF;
812 }
813
814 duprintf("translate_table: size %u\n", newinfo->size);
815 i = 0;
816 /* Walk through entries, checking offsets. */
817 xt_entry_foreach(iter, entry0, newinfo->size) {
818 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
819 entry0 + repl->size,
820 repl->hook_entry,
821 repl->underflow,
822 repl->valid_hooks);
823 if (ret != 0)
824 return ret;
825 ++i;
826 if (strcmp(ip6t_get_target(iter)->u.user.name,
827 XT_ERROR_TARGET) == 0)
828 ++newinfo->stacksize;
829 }
830
831 if (i != repl->num_entries) {
832 duprintf("translate_table: %u not %u entries\n",
833 i, repl->num_entries);
834 return -EINVAL;
835 }
836
837 /* Check hooks all assigned */
838 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
839 /* Only hooks which are valid */
840 if (!(repl->valid_hooks & (1 << i)))
841 continue;
842 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
843 duprintf("Invalid hook entry %u %u\n",
844 i, repl->hook_entry[i]);
845 return -EINVAL;
846 }
847 if (newinfo->underflow[i] == 0xFFFFFFFF) {
848 duprintf("Invalid underflow %u %u\n",
849 i, repl->underflow[i]);
850 return -EINVAL;
851 }
852 }
853
854 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
855 return -ELOOP;
856
857 /* Finally, each sanity check must pass */
858 i = 0;
859 xt_entry_foreach(iter, entry0, newinfo->size) {
860 ret = find_check_entry(iter, net, repl->name, repl->size);
861 if (ret != 0)
862 break;
863 ++i;
864 }
865
866 if (ret != 0) {
867 xt_entry_foreach(iter, entry0, newinfo->size) {
868 if (i-- == 0)
869 break;
870 cleanup_entry(iter, net);
871 }
872 return ret;
873 }
874
875 /* And one copy for every other CPU */
876 for_each_possible_cpu(i) {
877 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
878 memcpy(newinfo->entries[i], entry0, newinfo->size);
879 }
880
881 return ret;
882 }
883
884 static void
885 get_counters(const struct xt_table_info *t,
886 struct xt_counters counters[])
887 {
888 struct ip6t_entry *iter;
889 unsigned int cpu;
890 unsigned int i;
891
892 for_each_possible_cpu(cpu) {
893 seqcount_t *s = &per_cpu(xt_recseq, cpu);
894
895 i = 0;
896 xt_entry_foreach(iter, t->entries[cpu], t->size) {
897 u64 bcnt, pcnt;
898 unsigned int start;
899
900 do {
901 start = read_seqcount_begin(s);
902 bcnt = iter->counters.bcnt;
903 pcnt = iter->counters.pcnt;
904 } while (read_seqcount_retry(s, start));
905
906 ADD_COUNTER(counters[i], bcnt, pcnt);
907 ++i;
908 }
909 }
910 }
911
912 static struct xt_counters *alloc_counters(const struct xt_table *table)
913 {
914 unsigned int countersize;
915 struct xt_counters *counters;
916 const struct xt_table_info *private = table->private;
917
918 /* We need atomic snapshot of counters: rest doesn't change
919 (other than comefrom, which userspace doesn't care
920 about). */
921 countersize = sizeof(struct xt_counters) * private->number;
922 counters = vzalloc(countersize);
923
924 if (counters == NULL)
925 return ERR_PTR(-ENOMEM);
926
927 get_counters(private, counters);
928
929 return counters;
930 }
931
932 static int
933 copy_entries_to_user(unsigned int total_size,
934 const struct xt_table *table,
935 void __user *userptr)
936 {
937 unsigned int off, num;
938 const struct ip6t_entry *e;
939 struct xt_counters *counters;
940 const struct xt_table_info *private = table->private;
941 int ret = 0;
942 const void *loc_cpu_entry;
943
944 counters = alloc_counters(table);
945 if (IS_ERR(counters))
946 return PTR_ERR(counters);
947
948 /* choose the copy that is on our node/cpu, ...
949 * This choice is lazy (because current thread is
950 * allowed to migrate to another cpu)
951 */
952 loc_cpu_entry = private->entries[raw_smp_processor_id()];
953 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
954 ret = -EFAULT;
955 goto free_counters;
956 }
957
958 /* FIXME: use iterator macros --RR */
959 /* ... then go back and fix counters and names */
960 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
961 unsigned int i;
962 const struct xt_entry_match *m;
963 const struct xt_entry_target *t;
964
965 e = (struct ip6t_entry *)(loc_cpu_entry + off);
966 if (copy_to_user(userptr + off
967 + offsetof(struct ip6t_entry, counters),
968 &counters[num],
969 sizeof(counters[num])) != 0) {
970 ret = -EFAULT;
971 goto free_counters;
972 }
973
974 for (i = sizeof(struct ip6t_entry);
975 i < e->target_offset;
976 i += m->u.match_size) {
977 m = (void *)e + i;
978
979 if (copy_to_user(userptr + off + i
980 + offsetof(struct xt_entry_match,
981 u.user.name),
982 m->u.kernel.match->name,
983 strlen(m->u.kernel.match->name)+1)
984 != 0) {
985 ret = -EFAULT;
986 goto free_counters;
987 }
988 }
989
990 t = ip6t_get_target_c(e);
991 if (copy_to_user(userptr + off + e->target_offset
992 + offsetof(struct xt_entry_target,
993 u.user.name),
994 t->u.kernel.target->name,
995 strlen(t->u.kernel.target->name)+1) != 0) {
996 ret = -EFAULT;
997 goto free_counters;
998 }
999 }
1000
1001 free_counters:
1002 vfree(counters);
1003 return ret;
1004 }
1005
1006 #ifdef CONFIG_COMPAT
1007 static void compat_standard_from_user(void *dst, const void *src)
1008 {
1009 int v = *(compat_int_t *)src;
1010
1011 if (v > 0)
1012 v += xt_compat_calc_jump(AF_INET6, v);
1013 memcpy(dst, &v, sizeof(v));
1014 }
1015
1016 static int compat_standard_to_user(void __user *dst, const void *src)
1017 {
1018 compat_int_t cv = *(int *)src;
1019
1020 if (cv > 0)
1021 cv -= xt_compat_calc_jump(AF_INET6, cv);
1022 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1023 }
1024
1025 static int compat_calc_entry(const struct ip6t_entry *e,
1026 const struct xt_table_info *info,
1027 const void *base, struct xt_table_info *newinfo)
1028 {
1029 const struct xt_entry_match *ematch;
1030 const struct xt_entry_target *t;
1031 unsigned int entry_offset;
1032 int off, i, ret;
1033
1034 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1035 entry_offset = (void *)e - base;
1036 xt_ematch_foreach(ematch, e)
1037 off += xt_compat_match_offset(ematch->u.kernel.match);
1038 t = ip6t_get_target_c(e);
1039 off += xt_compat_target_offset(t->u.kernel.target);
1040 newinfo->size -= off;
1041 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1042 if (ret)
1043 return ret;
1044
1045 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1046 if (info->hook_entry[i] &&
1047 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1048 newinfo->hook_entry[i] -= off;
1049 if (info->underflow[i] &&
1050 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1051 newinfo->underflow[i] -= off;
1052 }
1053 return 0;
1054 }
1055
1056 static int compat_table_info(const struct xt_table_info *info,
1057 struct xt_table_info *newinfo)
1058 {
1059 struct ip6t_entry *iter;
1060 void *loc_cpu_entry;
1061 int ret;
1062
1063 if (!newinfo || !info)
1064 return -EINVAL;
1065
1066 /* we dont care about newinfo->entries[] */
1067 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1068 newinfo->initial_entries = 0;
1069 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1070 xt_compat_init_offsets(AF_INET6, info->number);
1071 xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1072 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1073 if (ret != 0)
1074 return ret;
1075 }
1076 return 0;
1077 }
1078 #endif
1079
1080 static int get_info(struct net *net, void __user *user,
1081 const int *len, int compat)
1082 {
1083 char name[XT_TABLE_MAXNAMELEN];
1084 struct xt_table *t;
1085 int ret;
1086
1087 if (*len != sizeof(struct ip6t_getinfo)) {
1088 duprintf("length %u != %zu\n", *len,
1089 sizeof(struct ip6t_getinfo));
1090 return -EINVAL;
1091 }
1092
1093 if (copy_from_user(name, user, sizeof(name)) != 0)
1094 return -EFAULT;
1095
1096 name[XT_TABLE_MAXNAMELEN-1] = '\0';
1097 #ifdef CONFIG_COMPAT
1098 if (compat)
1099 xt_compat_lock(AF_INET6);
1100 #endif
1101 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1102 "ip6table_%s", name);
1103 if (!IS_ERR_OR_NULL(t)) {
1104 struct ip6t_getinfo info;
1105 const struct xt_table_info *private = t->private;
1106 #ifdef CONFIG_COMPAT
1107 struct xt_table_info tmp;
1108
1109 if (compat) {
1110 ret = compat_table_info(private, &tmp);
1111 xt_compat_flush_offsets(AF_INET6);
1112 private = &tmp;
1113 }
1114 #endif
1115 memset(&info, 0, sizeof(info));
1116 info.valid_hooks = t->valid_hooks;
1117 memcpy(info.hook_entry, private->hook_entry,
1118 sizeof(info.hook_entry));
1119 memcpy(info.underflow, private->underflow,
1120 sizeof(info.underflow));
1121 info.num_entries = private->number;
1122 info.size = private->size;
1123 strcpy(info.name, name);
1124
1125 if (copy_to_user(user, &info, *len) != 0)
1126 ret = -EFAULT;
1127 else
1128 ret = 0;
1129
1130 xt_table_unlock(t);
1131 module_put(t->me);
1132 } else
1133 ret = t ? PTR_ERR(t) : -ENOENT;
1134 #ifdef CONFIG_COMPAT
1135 if (compat)
1136 xt_compat_unlock(AF_INET6);
1137 #endif
1138 return ret;
1139 }
1140
1141 static int
1142 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1143 const int *len)
1144 {
1145 int ret;
1146 struct ip6t_get_entries get;
1147 struct xt_table *t;
1148
1149 if (*len < sizeof(get)) {
1150 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1151 return -EINVAL;
1152 }
1153 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1154 return -EFAULT;
1155 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1156 duprintf("get_entries: %u != %zu\n",
1157 *len, sizeof(get) + get.size);
1158 return -EINVAL;
1159 }
1160
1161 t = xt_find_table_lock(net, AF_INET6, get.name);
1162 if (!IS_ERR_OR_NULL(t)) {
1163 struct xt_table_info *private = t->private;
1164 duprintf("t->private->number = %u\n", private->number);
1165 if (get.size == private->size)
1166 ret = copy_entries_to_user(private->size,
1167 t, uptr->entrytable);
1168 else {
1169 duprintf("get_entries: I've got %u not %u!\n",
1170 private->size, get.size);
1171 ret = -EAGAIN;
1172 }
1173 module_put(t->me);
1174 xt_table_unlock(t);
1175 } else
1176 ret = t ? PTR_ERR(t) : -ENOENT;
1177
1178 return ret;
1179 }
1180
1181 static int
1182 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1183 struct xt_table_info *newinfo, unsigned int num_counters,
1184 void __user *counters_ptr)
1185 {
1186 int ret;
1187 struct xt_table *t;
1188 struct xt_table_info *oldinfo;
1189 struct xt_counters *counters;
1190 const void *loc_cpu_old_entry;
1191 struct ip6t_entry *iter;
1192
1193 ret = 0;
1194 counters = vzalloc(num_counters * sizeof(struct xt_counters));
1195 if (!counters) {
1196 ret = -ENOMEM;
1197 goto out;
1198 }
1199
1200 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1201 "ip6table_%s", name);
1202 if (IS_ERR_OR_NULL(t)) {
1203 ret = t ? PTR_ERR(t) : -ENOENT;
1204 goto free_newinfo_counters_untrans;
1205 }
1206
1207 /* You lied! */
1208 if (valid_hooks != t->valid_hooks) {
1209 duprintf("Valid hook crap: %08X vs %08X\n",
1210 valid_hooks, t->valid_hooks);
1211 ret = -EINVAL;
1212 goto put_module;
1213 }
1214
1215 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1216 if (!oldinfo)
1217 goto put_module;
1218
1219 /* Update module usage count based on number of rules */
1220 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1221 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1222 if ((oldinfo->number > oldinfo->initial_entries) ||
1223 (newinfo->number <= oldinfo->initial_entries))
1224 module_put(t->me);
1225 if ((oldinfo->number > oldinfo->initial_entries) &&
1226 (newinfo->number <= oldinfo->initial_entries))
1227 module_put(t->me);
1228
1229 /* Get the old counters, and synchronize with replace */
1230 get_counters(oldinfo, counters);
1231
1232 /* Decrease module usage counts and free resource */
1233 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1234 xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
1235 cleanup_entry(iter, net);
1236
1237 xt_free_table_info(oldinfo);
1238 if (copy_to_user(counters_ptr, counters,
1239 sizeof(struct xt_counters) * num_counters) != 0)
1240 ret = -EFAULT;
1241 vfree(counters);
1242 xt_table_unlock(t);
1243 return ret;
1244
1245 put_module:
1246 module_put(t->me);
1247 xt_table_unlock(t);
1248 free_newinfo_counters_untrans:
1249 vfree(counters);
1250 out:
1251 return ret;
1252 }
1253
1254 static int
1255 do_replace(struct net *net, const void __user *user, unsigned int len)
1256 {
1257 int ret;
1258 struct ip6t_replace tmp;
1259 struct xt_table_info *newinfo;
1260 void *loc_cpu_entry;
1261 struct ip6t_entry *iter;
1262
1263 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1264 return -EFAULT;
1265
1266 /* overflow check */
1267 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1268 return -ENOMEM;
1269 tmp.name[sizeof(tmp.name)-1] = 0;
1270
1271 newinfo = xt_alloc_table_info(tmp.size);
1272 if (!newinfo)
1273 return -ENOMEM;
1274
1275 /* choose the copy that is on our node/cpu */
1276 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1277 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1278 tmp.size) != 0) {
1279 ret = -EFAULT;
1280 goto free_newinfo;
1281 }
1282
1283 ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1284 if (ret != 0)
1285 goto free_newinfo;
1286
1287 duprintf("ip_tables: Translated table\n");
1288
1289 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1290 tmp.num_counters, tmp.counters);
1291 if (ret)
1292 goto free_newinfo_untrans;
1293 return 0;
1294
1295 free_newinfo_untrans:
1296 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1297 cleanup_entry(iter, net);
1298 free_newinfo:
1299 xt_free_table_info(newinfo);
1300 return ret;
1301 }
1302
1303 static int
1304 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1305 int compat)
1306 {
1307 unsigned int i, curcpu;
1308 struct xt_counters_info tmp;
1309 struct xt_counters *paddc;
1310 unsigned int num_counters;
1311 char *name;
1312 int size;
1313 void *ptmp;
1314 struct xt_table *t;
1315 const struct xt_table_info *private;
1316 int ret = 0;
1317 const void *loc_cpu_entry;
1318 struct ip6t_entry *iter;
1319 unsigned int addend;
1320 #ifdef CONFIG_COMPAT
1321 struct compat_xt_counters_info compat_tmp;
1322
1323 if (compat) {
1324 ptmp = &compat_tmp;
1325 size = sizeof(struct compat_xt_counters_info);
1326 } else
1327 #endif
1328 {
1329 ptmp = &tmp;
1330 size = sizeof(struct xt_counters_info);
1331 }
1332
1333 if (copy_from_user(ptmp, user, size) != 0)
1334 return -EFAULT;
1335
1336 #ifdef CONFIG_COMPAT
1337 if (compat) {
1338 num_counters = compat_tmp.num_counters;
1339 name = compat_tmp.name;
1340 } else
1341 #endif
1342 {
1343 num_counters = tmp.num_counters;
1344 name = tmp.name;
1345 }
1346
1347 if (len != size + num_counters * sizeof(struct xt_counters))
1348 return -EINVAL;
1349
1350 paddc = vmalloc(len - size);
1351 if (!paddc)
1352 return -ENOMEM;
1353
1354 if (copy_from_user(paddc, user + size, len - size) != 0) {
1355 ret = -EFAULT;
1356 goto free;
1357 }
1358
1359 t = xt_find_table_lock(net, AF_INET6, name);
1360 if (IS_ERR_OR_NULL(t)) {
1361 ret = t ? PTR_ERR(t) : -ENOENT;
1362 goto free;
1363 }
1364
1365
1366 local_bh_disable();
1367 private = t->private;
1368 if (private->number != num_counters) {
1369 ret = -EINVAL;
1370 goto unlock_up_free;
1371 }
1372
1373 i = 0;
1374 /* Choose the copy that is on our node */
1375 curcpu = smp_processor_id();
1376 addend = xt_write_recseq_begin();
1377 loc_cpu_entry = private->entries[curcpu];
1378 xt_entry_foreach(iter, loc_cpu_entry, private->size) {
1379 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
1380 ++i;
1381 }
1382 xt_write_recseq_end(addend);
1383
1384 unlock_up_free:
1385 local_bh_enable();
1386 xt_table_unlock(t);
1387 module_put(t->me);
1388 free:
1389 vfree(paddc);
1390
1391 return ret;
1392 }
1393
1394 #ifdef CONFIG_COMPAT
1395 struct compat_ip6t_replace {
1396 char name[XT_TABLE_MAXNAMELEN];
1397 u32 valid_hooks;
1398 u32 num_entries;
1399 u32 size;
1400 u32 hook_entry[NF_INET_NUMHOOKS];
1401 u32 underflow[NF_INET_NUMHOOKS];
1402 u32 num_counters;
1403 compat_uptr_t counters; /* struct xt_counters * */
1404 struct compat_ip6t_entry entries[0];
1405 };
1406
1407 static int
1408 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1409 unsigned int *size, struct xt_counters *counters,
1410 unsigned int i)
1411 {
1412 struct xt_entry_target *t;
1413 struct compat_ip6t_entry __user *ce;
1414 u_int16_t target_offset, next_offset;
1415 compat_uint_t origsize;
1416 const struct xt_entry_match *ematch;
1417 int ret = 0;
1418
1419 origsize = *size;
1420 ce = (struct compat_ip6t_entry __user *)*dstptr;
1421 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1422 copy_to_user(&ce->counters, &counters[i],
1423 sizeof(counters[i])) != 0)
1424 return -EFAULT;
1425
1426 *dstptr += sizeof(struct compat_ip6t_entry);
1427 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1428
1429 xt_ematch_foreach(ematch, e) {
1430 ret = xt_compat_match_to_user(ematch, dstptr, size);
1431 if (ret != 0)
1432 return ret;
1433 }
1434 target_offset = e->target_offset - (origsize - *size);
1435 t = ip6t_get_target(e);
1436 ret = xt_compat_target_to_user(t, dstptr, size);
1437 if (ret)
1438 return ret;
1439 next_offset = e->next_offset - (origsize - *size);
1440 if (put_user(target_offset, &ce->target_offset) != 0 ||
1441 put_user(next_offset, &ce->next_offset) != 0)
1442 return -EFAULT;
1443 return 0;
1444 }
1445
1446 static int
1447 compat_find_calc_match(struct xt_entry_match *m,
1448 const char *name,
1449 const struct ip6t_ip6 *ipv6,
1450 unsigned int hookmask,
1451 int *size)
1452 {
1453 struct xt_match *match;
1454
1455 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1456 m->u.user.revision);
1457 if (IS_ERR(match)) {
1458 duprintf("compat_check_calc_match: `%s' not found\n",
1459 m->u.user.name);
1460 return PTR_ERR(match);
1461 }
1462 m->u.kernel.match = match;
1463 *size += xt_compat_match_offset(match);
1464 return 0;
1465 }
1466
1467 static void compat_release_entry(struct compat_ip6t_entry *e)
1468 {
1469 struct xt_entry_target *t;
1470 struct xt_entry_match *ematch;
1471
1472 /* Cleanup all matches */
1473 xt_ematch_foreach(ematch, e)
1474 module_put(ematch->u.kernel.match->me);
1475 t = compat_ip6t_get_target(e);
1476 module_put(t->u.kernel.target->me);
1477 }
1478
1479 static int
1480 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1481 struct xt_table_info *newinfo,
1482 unsigned int *size,
1483 const unsigned char *base,
1484 const unsigned char *limit,
1485 const unsigned int *hook_entries,
1486 const unsigned int *underflows,
1487 const char *name)
1488 {
1489 struct xt_entry_match *ematch;
1490 struct xt_entry_target *t;
1491 struct xt_target *target;
1492 unsigned int entry_offset;
1493 unsigned int j;
1494 int ret, off, h;
1495
1496 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1497 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1498 (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1499 duprintf("Bad offset %p, limit = %p\n", e, limit);
1500 return -EINVAL;
1501 }
1502
1503 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1504 sizeof(struct compat_xt_entry_target)) {
1505 duprintf("checking: element %p size %u\n",
1506 e, e->next_offset);
1507 return -EINVAL;
1508 }
1509
1510 /* For purposes of check_entry casting the compat entry is fine */
1511 ret = check_entry((struct ip6t_entry *)e, name);
1512 if (ret)
1513 return ret;
1514
1515 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1516 entry_offset = (void *)e - (void *)base;
1517 j = 0;
1518 xt_ematch_foreach(ematch, e) {
1519 ret = compat_find_calc_match(ematch, name,
1520 &e->ipv6, e->comefrom, &off);
1521 if (ret != 0)
1522 goto release_matches;
1523 ++j;
1524 }
1525
1526 t = compat_ip6t_get_target(e);
1527 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1528 t->u.user.revision);
1529 if (IS_ERR(target)) {
1530 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1531 t->u.user.name);
1532 ret = PTR_ERR(target);
1533 goto release_matches;
1534 }
1535 t->u.kernel.target = target;
1536
1537 off += xt_compat_target_offset(target);
1538 *size += off;
1539 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1540 if (ret)
1541 goto out;
1542
1543 /* Check hooks & underflows */
1544 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1545 if ((unsigned char *)e - base == hook_entries[h])
1546 newinfo->hook_entry[h] = hook_entries[h];
1547 if ((unsigned char *)e - base == underflows[h])
1548 newinfo->underflow[h] = underflows[h];
1549 }
1550
1551 /* Clear counters and comefrom */
1552 memset(&e->counters, 0, sizeof(e->counters));
1553 e->comefrom = 0;
1554 return 0;
1555
1556 out:
1557 module_put(t->u.kernel.target->me);
1558 release_matches:
1559 xt_ematch_foreach(ematch, e) {
1560 if (j-- == 0)
1561 break;
1562 module_put(ematch->u.kernel.match->me);
1563 }
1564 return ret;
1565 }
1566
1567 static int
1568 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1569 unsigned int *size, const char *name,
1570 struct xt_table_info *newinfo, unsigned char *base)
1571 {
1572 struct xt_entry_target *t;
1573 struct ip6t_entry *de;
1574 unsigned int origsize;
1575 int ret, h;
1576 struct xt_entry_match *ematch;
1577
1578 ret = 0;
1579 origsize = *size;
1580 de = (struct ip6t_entry *)*dstptr;
1581 memcpy(de, e, sizeof(struct ip6t_entry));
1582 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1583
1584 *dstptr += sizeof(struct ip6t_entry);
1585 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1586
1587 xt_ematch_foreach(ematch, e) {
1588 ret = xt_compat_match_from_user(ematch, dstptr, size);
1589 if (ret != 0)
1590 return ret;
1591 }
1592 de->target_offset = e->target_offset - (origsize - *size);
1593 t = compat_ip6t_get_target(e);
1594 xt_compat_target_from_user(t, dstptr, size);
1595
1596 de->next_offset = e->next_offset - (origsize - *size);
1597 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1598 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1599 newinfo->hook_entry[h] -= origsize - *size;
1600 if ((unsigned char *)de - base < newinfo->underflow[h])
1601 newinfo->underflow[h] -= origsize - *size;
1602 }
1603 return ret;
1604 }
1605
1606 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1607 const char *name)
1608 {
1609 unsigned int j;
1610 int ret = 0;
1611 struct xt_mtchk_param mtpar;
1612 struct xt_entry_match *ematch;
1613
1614 j = 0;
1615 mtpar.net = net;
1616 mtpar.table = name;
1617 mtpar.entryinfo = &e->ipv6;
1618 mtpar.hook_mask = e->comefrom;
1619 mtpar.family = NFPROTO_IPV6;
1620 xt_ematch_foreach(ematch, e) {
1621 ret = check_match(ematch, &mtpar);
1622 if (ret != 0)
1623 goto cleanup_matches;
1624 ++j;
1625 }
1626
1627 ret = check_target(e, net, name);
1628 if (ret)
1629 goto cleanup_matches;
1630 return 0;
1631
1632 cleanup_matches:
1633 xt_ematch_foreach(ematch, e) {
1634 if (j-- == 0)
1635 break;
1636 cleanup_match(ematch, net);
1637 }
1638 return ret;
1639 }
1640
1641 static int
1642 translate_compat_table(struct net *net,
1643 const char *name,
1644 unsigned int valid_hooks,
1645 struct xt_table_info **pinfo,
1646 void **pentry0,
1647 unsigned int total_size,
1648 unsigned int number,
1649 unsigned int *hook_entries,
1650 unsigned int *underflows)
1651 {
1652 unsigned int i, j;
1653 struct xt_table_info *newinfo, *info;
1654 void *pos, *entry0, *entry1;
1655 struct compat_ip6t_entry *iter0;
1656 struct ip6t_entry *iter1;
1657 unsigned int size;
1658 int ret = 0;
1659
1660 info = *pinfo;
1661 entry0 = *pentry0;
1662 size = total_size;
1663 info->number = number;
1664
1665 /* Init all hooks to impossible value. */
1666 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1667 info->hook_entry[i] = 0xFFFFFFFF;
1668 info->underflow[i] = 0xFFFFFFFF;
1669 }
1670
1671 duprintf("translate_compat_table: size %u\n", info->size);
1672 j = 0;
1673 xt_compat_lock(AF_INET6);
1674 xt_compat_init_offsets(AF_INET6, number);
1675 /* Walk through entries, checking offsets. */
1676 xt_entry_foreach(iter0, entry0, total_size) {
1677 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1678 entry0,
1679 entry0 + total_size,
1680 hook_entries,
1681 underflows,
1682 name);
1683 if (ret != 0)
1684 goto out_unlock;
1685 ++j;
1686 }
1687
1688 ret = -EINVAL;
1689 if (j != number) {
1690 duprintf("translate_compat_table: %u not %u entries\n",
1691 j, number);
1692 goto out_unlock;
1693 }
1694
1695 /* Check hooks all assigned */
1696 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1697 /* Only hooks which are valid */
1698 if (!(valid_hooks & (1 << i)))
1699 continue;
1700 if (info->hook_entry[i] == 0xFFFFFFFF) {
1701 duprintf("Invalid hook entry %u %u\n",
1702 i, hook_entries[i]);
1703 goto out_unlock;
1704 }
1705 if (info->underflow[i] == 0xFFFFFFFF) {
1706 duprintf("Invalid underflow %u %u\n",
1707 i, underflows[i]);
1708 goto out_unlock;
1709 }
1710 }
1711
1712 ret = -ENOMEM;
1713 newinfo = xt_alloc_table_info(size);
1714 if (!newinfo)
1715 goto out_unlock;
1716
1717 newinfo->number = number;
1718 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1719 newinfo->hook_entry[i] = info->hook_entry[i];
1720 newinfo->underflow[i] = info->underflow[i];
1721 }
1722 entry1 = newinfo->entries[raw_smp_processor_id()];
1723 pos = entry1;
1724 size = total_size;
1725 xt_entry_foreach(iter0, entry0, total_size) {
1726 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1727 name, newinfo, entry1);
1728 if (ret != 0)
1729 break;
1730 }
1731 xt_compat_flush_offsets(AF_INET6);
1732 xt_compat_unlock(AF_INET6);
1733 if (ret)
1734 goto free_newinfo;
1735
1736 ret = -ELOOP;
1737 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1738 goto free_newinfo;
1739
1740 i = 0;
1741 xt_entry_foreach(iter1, entry1, newinfo->size) {
1742 ret = compat_check_entry(iter1, net, name);
1743 if (ret != 0)
1744 break;
1745 ++i;
1746 if (strcmp(ip6t_get_target(iter1)->u.user.name,
1747 XT_ERROR_TARGET) == 0)
1748 ++newinfo->stacksize;
1749 }
1750 if (ret) {
1751 /*
1752 * The first i matches need cleanup_entry (calls ->destroy)
1753 * because they had called ->check already. The other j-i
1754 * entries need only release.
1755 */
1756 int skip = i;
1757 j -= i;
1758 xt_entry_foreach(iter0, entry0, newinfo->size) {
1759 if (skip-- > 0)
1760 continue;
1761 if (j-- == 0)
1762 break;
1763 compat_release_entry(iter0);
1764 }
1765 xt_entry_foreach(iter1, entry1, newinfo->size) {
1766 if (i-- == 0)
1767 break;
1768 cleanup_entry(iter1, net);
1769 }
1770 xt_free_table_info(newinfo);
1771 return ret;
1772 }
1773
1774 /* And one copy for every other CPU */
1775 for_each_possible_cpu(i)
1776 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1777 memcpy(newinfo->entries[i], entry1, newinfo->size);
1778
1779 *pinfo = newinfo;
1780 *pentry0 = entry1;
1781 xt_free_table_info(info);
1782 return 0;
1783
1784 free_newinfo:
1785 xt_free_table_info(newinfo);
1786 out:
1787 xt_entry_foreach(iter0, entry0, total_size) {
1788 if (j-- == 0)
1789 break;
1790 compat_release_entry(iter0);
1791 }
1792 return ret;
1793 out_unlock:
1794 xt_compat_flush_offsets(AF_INET6);
1795 xt_compat_unlock(AF_INET6);
1796 goto out;
1797 }
1798
1799 static int
1800 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1801 {
1802 int ret;
1803 struct compat_ip6t_replace tmp;
1804 struct xt_table_info *newinfo;
1805 void *loc_cpu_entry;
1806 struct ip6t_entry *iter;
1807
1808 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1809 return -EFAULT;
1810
1811 /* overflow check */
1812 if (tmp.size >= INT_MAX / num_possible_cpus())
1813 return -ENOMEM;
1814 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1815 return -ENOMEM;
1816 tmp.name[sizeof(tmp.name)-1] = 0;
1817
1818 newinfo = xt_alloc_table_info(tmp.size);
1819 if (!newinfo)
1820 return -ENOMEM;
1821
1822 /* choose the copy that is on our node/cpu */
1823 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1824 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1825 tmp.size) != 0) {
1826 ret = -EFAULT;
1827 goto free_newinfo;
1828 }
1829
1830 ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1831 &newinfo, &loc_cpu_entry, tmp.size,
1832 tmp.num_entries, tmp.hook_entry,
1833 tmp.underflow);
1834 if (ret != 0)
1835 goto free_newinfo;
1836
1837 duprintf("compat_do_replace: Translated table\n");
1838
1839 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1840 tmp.num_counters, compat_ptr(tmp.counters));
1841 if (ret)
1842 goto free_newinfo_untrans;
1843 return 0;
1844
1845 free_newinfo_untrans:
1846 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1847 cleanup_entry(iter, net);
1848 free_newinfo:
1849 xt_free_table_info(newinfo);
1850 return ret;
1851 }
1852
1853 static int
1854 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1855 unsigned int len)
1856 {
1857 int ret;
1858
1859 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1860 return -EPERM;
1861
1862 switch (cmd) {
1863 case IP6T_SO_SET_REPLACE:
1864 ret = compat_do_replace(sock_net(sk), user, len);
1865 break;
1866
1867 case IP6T_SO_SET_ADD_COUNTERS:
1868 ret = do_add_counters(sock_net(sk), user, len, 1);
1869 break;
1870
1871 default:
1872 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1873 ret = -EINVAL;
1874 }
1875
1876 return ret;
1877 }
1878
1879 struct compat_ip6t_get_entries {
1880 char name[XT_TABLE_MAXNAMELEN];
1881 compat_uint_t size;
1882 struct compat_ip6t_entry entrytable[0];
1883 };
1884
1885 static int
1886 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1887 void __user *userptr)
1888 {
1889 struct xt_counters *counters;
1890 const struct xt_table_info *private = table->private;
1891 void __user *pos;
1892 unsigned int size;
1893 int ret = 0;
1894 const void *loc_cpu_entry;
1895 unsigned int i = 0;
1896 struct ip6t_entry *iter;
1897
1898 counters = alloc_counters(table);
1899 if (IS_ERR(counters))
1900 return PTR_ERR(counters);
1901
1902 /* choose the copy that is on our node/cpu, ...
1903 * This choice is lazy (because current thread is
1904 * allowed to migrate to another cpu)
1905 */
1906 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1907 pos = userptr;
1908 size = total_size;
1909 xt_entry_foreach(iter, loc_cpu_entry, total_size) {
1910 ret = compat_copy_entry_to_user(iter, &pos,
1911 &size, counters, i++);
1912 if (ret != 0)
1913 break;
1914 }
1915
1916 vfree(counters);
1917 return ret;
1918 }
1919
1920 static int
1921 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1922 int *len)
1923 {
1924 int ret;
1925 struct compat_ip6t_get_entries get;
1926 struct xt_table *t;
1927
1928 if (*len < sizeof(get)) {
1929 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1930 return -EINVAL;
1931 }
1932
1933 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1934 return -EFAULT;
1935
1936 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1937 duprintf("compat_get_entries: %u != %zu\n",
1938 *len, sizeof(get) + get.size);
1939 return -EINVAL;
1940 }
1941
1942 xt_compat_lock(AF_INET6);
1943 t = xt_find_table_lock(net, AF_INET6, get.name);
1944 if (!IS_ERR_OR_NULL(t)) {
1945 const struct xt_table_info *private = t->private;
1946 struct xt_table_info info;
1947 duprintf("t->private->number = %u\n", private->number);
1948 ret = compat_table_info(private, &info);
1949 if (!ret && get.size == info.size) {
1950 ret = compat_copy_entries_to_user(private->size,
1951 t, uptr->entrytable);
1952 } else if (!ret) {
1953 duprintf("compat_get_entries: I've got %u not %u!\n",
1954 private->size, get.size);
1955 ret = -EAGAIN;
1956 }
1957 xt_compat_flush_offsets(AF_INET6);
1958 module_put(t->me);
1959 xt_table_unlock(t);
1960 } else
1961 ret = t ? PTR_ERR(t) : -ENOENT;
1962
1963 xt_compat_unlock(AF_INET6);
1964 return ret;
1965 }
1966
1967 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1968
1969 static int
1970 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1971 {
1972 int ret;
1973
1974 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1975 return -EPERM;
1976
1977 switch (cmd) {
1978 case IP6T_SO_GET_INFO:
1979 ret = get_info(sock_net(sk), user, len, 1);
1980 break;
1981 case IP6T_SO_GET_ENTRIES:
1982 ret = compat_get_entries(sock_net(sk), user, len);
1983 break;
1984 default:
1985 ret = do_ip6t_get_ctl(sk, cmd, user, len);
1986 }
1987 return ret;
1988 }
1989 #endif
1990
1991 static int
1992 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1993 {
1994 int ret;
1995
1996 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1997 return -EPERM;
1998
1999 switch (cmd) {
2000 case IP6T_SO_SET_REPLACE:
2001 ret = do_replace(sock_net(sk), user, len);
2002 break;
2003
2004 case IP6T_SO_SET_ADD_COUNTERS:
2005 ret = do_add_counters(sock_net(sk), user, len, 0);
2006 break;
2007
2008 default:
2009 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2010 ret = -EINVAL;
2011 }
2012
2013 return ret;
2014 }
2015
2016 static int
2017 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2018 {
2019 int ret;
2020
2021 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2022 return -EPERM;
2023
2024 switch (cmd) {
2025 case IP6T_SO_GET_INFO:
2026 ret = get_info(sock_net(sk), user, len, 0);
2027 break;
2028
2029 case IP6T_SO_GET_ENTRIES:
2030 ret = get_entries(sock_net(sk), user, len);
2031 break;
2032
2033 case IP6T_SO_GET_REVISION_MATCH:
2034 case IP6T_SO_GET_REVISION_TARGET: {
2035 struct xt_get_revision rev;
2036 int target;
2037
2038 if (*len != sizeof(rev)) {
2039 ret = -EINVAL;
2040 break;
2041 }
2042 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2043 ret = -EFAULT;
2044 break;
2045 }
2046 rev.name[sizeof(rev.name)-1] = 0;
2047
2048 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2049 target = 1;
2050 else
2051 target = 0;
2052
2053 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2054 rev.revision,
2055 target, &ret),
2056 "ip6t_%s", rev.name);
2057 break;
2058 }
2059
2060 default:
2061 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2062 ret = -EINVAL;
2063 }
2064
2065 return ret;
2066 }
2067
2068 struct xt_table *ip6t_register_table(struct net *net,
2069 const struct xt_table *table,
2070 const struct ip6t_replace *repl)
2071 {
2072 int ret;
2073 struct xt_table_info *newinfo;
2074 struct xt_table_info bootstrap = {0};
2075 void *loc_cpu_entry;
2076 struct xt_table *new_table;
2077
2078 newinfo = xt_alloc_table_info(repl->size);
2079 if (!newinfo) {
2080 ret = -ENOMEM;
2081 goto out;
2082 }
2083
2084 /* choose the copy on our node/cpu, but dont care about preemption */
2085 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2086 memcpy(loc_cpu_entry, repl->entries, repl->size);
2087
2088 ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2089 if (ret != 0)
2090 goto out_free;
2091
2092 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2093 if (IS_ERR(new_table)) {
2094 ret = PTR_ERR(new_table);
2095 goto out_free;
2096 }
2097 return new_table;
2098
2099 out_free:
2100 xt_free_table_info(newinfo);
2101 out:
2102 return ERR_PTR(ret);
2103 }
2104
2105 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2106 {
2107 struct xt_table_info *private;
2108 void *loc_cpu_entry;
2109 struct module *table_owner = table->me;
2110 struct ip6t_entry *iter;
2111
2112 private = xt_unregister_table(table);
2113
2114 /* Decrease module usage counts and free resources */
2115 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2116 xt_entry_foreach(iter, loc_cpu_entry, private->size)
2117 cleanup_entry(iter, net);
2118 if (private->number > private->initial_entries)
2119 module_put(table_owner);
2120 xt_free_table_info(private);
2121 }
2122
2123 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2124 static inline bool
2125 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2126 u_int8_t type, u_int8_t code,
2127 bool invert)
2128 {
2129 return (type == test_type && code >= min_code && code <= max_code)
2130 ^ invert;
2131 }
2132
2133 static bool
2134 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2135 {
2136 const struct icmp6hdr *ic;
2137 struct icmp6hdr _icmph;
2138 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2139
2140 /* Must not be a fragment. */
2141 if (par->fragoff != 0)
2142 return false;
2143
2144 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2145 if (ic == NULL) {
2146 /* We've been asked to examine this packet, and we
2147 * can't. Hence, no choice but to drop.
2148 */
2149 duprintf("Dropping evil ICMP tinygram.\n");
2150 par->hotdrop = true;
2151 return false;
2152 }
2153
2154 return icmp6_type_code_match(icmpinfo->type,
2155 icmpinfo->code[0],
2156 icmpinfo->code[1],
2157 ic->icmp6_type, ic->icmp6_code,
2158 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2159 }
2160
2161 /* Called when user tries to insert an entry of this type. */
2162 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2163 {
2164 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2165
2166 /* Must specify no unknown invflags */
2167 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2168 }
2169
2170 /* The built-in targets: standard (NULL) and error. */
2171 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2172 {
2173 .name = XT_STANDARD_TARGET,
2174 .targetsize = sizeof(int),
2175 .family = NFPROTO_IPV6,
2176 #ifdef CONFIG_COMPAT
2177 .compatsize = sizeof(compat_int_t),
2178 .compat_from_user = compat_standard_from_user,
2179 .compat_to_user = compat_standard_to_user,
2180 #endif
2181 },
2182 {
2183 .name = XT_ERROR_TARGET,
2184 .target = ip6t_error,
2185 .targetsize = XT_FUNCTION_MAXNAMELEN,
2186 .family = NFPROTO_IPV6,
2187 },
2188 };
2189
2190 static struct nf_sockopt_ops ip6t_sockopts = {
2191 .pf = PF_INET6,
2192 .set_optmin = IP6T_BASE_CTL,
2193 .set_optmax = IP6T_SO_SET_MAX+1,
2194 .set = do_ip6t_set_ctl,
2195 #ifdef CONFIG_COMPAT
2196 .compat_set = compat_do_ip6t_set_ctl,
2197 #endif
2198 .get_optmin = IP6T_BASE_CTL,
2199 .get_optmax = IP6T_SO_GET_MAX+1,
2200 .get = do_ip6t_get_ctl,
2201 #ifdef CONFIG_COMPAT
2202 .compat_get = compat_do_ip6t_get_ctl,
2203 #endif
2204 .owner = THIS_MODULE,
2205 };
2206
2207 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2208 {
2209 .name = "icmp6",
2210 .match = icmp6_match,
2211 .matchsize = sizeof(struct ip6t_icmp),
2212 .checkentry = icmp6_checkentry,
2213 .proto = IPPROTO_ICMPV6,
2214 .family = NFPROTO_IPV6,
2215 },
2216 };
2217
2218 static int __net_init ip6_tables_net_init(struct net *net)
2219 {
2220 return xt_proto_init(net, NFPROTO_IPV6);
2221 }
2222
2223 static void __net_exit ip6_tables_net_exit(struct net *net)
2224 {
2225 xt_proto_fini(net, NFPROTO_IPV6);
2226 }
2227
2228 static struct pernet_operations ip6_tables_net_ops = {
2229 .init = ip6_tables_net_init,
2230 .exit = ip6_tables_net_exit,
2231 };
2232
2233 static int __init ip6_tables_init(void)
2234 {
2235 int ret;
2236
2237 ret = register_pernet_subsys(&ip6_tables_net_ops);
2238 if (ret < 0)
2239 goto err1;
2240
2241 /* No one else will be downing sem now, so we won't sleep */
2242 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2243 if (ret < 0)
2244 goto err2;
2245 ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2246 if (ret < 0)
2247 goto err4;
2248
2249 /* Register setsockopt */
2250 ret = nf_register_sockopt(&ip6t_sockopts);
2251 if (ret < 0)
2252 goto err5;
2253
2254 pr_info("(C) 2000-2006 Netfilter Core Team\n");
2255 return 0;
2256
2257 err5:
2258 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2259 err4:
2260 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2261 err2:
2262 unregister_pernet_subsys(&ip6_tables_net_ops);
2263 err1:
2264 return ret;
2265 }
2266
2267 static void __exit ip6_tables_fini(void)
2268 {
2269 nf_unregister_sockopt(&ip6t_sockopts);
2270
2271 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2272 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2273 unregister_pernet_subsys(&ip6_tables_net_ops);
2274 }
2275
2276 EXPORT_SYMBOL(ip6t_register_table);
2277 EXPORT_SYMBOL(ip6t_unregister_table);
2278 EXPORT_SYMBOL(ip6t_do_table);
2279
2280 module_init(ip6_tables_init);
2281 module_exit(ip6_tables_fini);