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