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