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