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