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