0c9973a657fb8e3ec2c0378aab0dffd0a9aa4e1f
[pandora-kernel.git] / net / ipv6 / netfilter / ip6_tables.c
1 /*
2  * Packet matching code.
3  *
4  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5  * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 #include <linux/capability.h>
13 #include <linux/in.h>
14 #include <linux/skbuff.h>
15 #include <linux/kmod.h>
16 #include <linux/vmalloc.h>
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <linux/poison.h>
20 #include <linux/icmpv6.h>
21 #include <net/ipv6.h>
22 #include <net/compat.h>
23 #include <asm/uaccess.h>
24 #include <linux/mutex.h>
25 #include <linux/proc_fs.h>
26 #include <linux/err.h>
27 #include <linux/cpumask.h>
28
29 #include <linux/netfilter_ipv6/ip6_tables.h>
30 #include <linux/netfilter/x_tables.h>
31 #include <net/netfilter/nf_log.h>
32 #include "../../netfilter/xt_repldata.h"
33
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
37
38 /*#define DEBUG_IP_FIREWALL*/
39 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
40 /*#define DEBUG_IP_FIREWALL_USER*/
41
42 #ifdef DEBUG_IP_FIREWALL
43 #define dprintf(format, args...) pr_info(format , ## args)
44 #else
45 #define dprintf(format, args...)
46 #endif
47
48 #ifdef DEBUG_IP_FIREWALL_USER
49 #define duprintf(format, args...) pr_info(format , ## args)
50 #else
51 #define duprintf(format, args...)
52 #endif
53
54 #ifdef CONFIG_NETFILTER_DEBUG
55 #define IP_NF_ASSERT(x) 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_compat_init_offsets(AF_INET6, info->number);
1097         xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1098                 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1099                 if (ret != 0)
1100                         return ret;
1101         }
1102         return 0;
1103 }
1104 #endif
1105
1106 static int get_info(struct net *net, void __user *user,
1107                     const int *len, int compat)
1108 {
1109         char name[XT_TABLE_MAXNAMELEN];
1110         struct xt_table *t;
1111         int ret;
1112
1113         if (*len != sizeof(struct ip6t_getinfo)) {
1114                 duprintf("length %u != %zu\n", *len,
1115                          sizeof(struct ip6t_getinfo));
1116                 return -EINVAL;
1117         }
1118
1119         if (copy_from_user(name, user, sizeof(name)) != 0)
1120                 return -EFAULT;
1121
1122         name[XT_TABLE_MAXNAMELEN-1] = '\0';
1123 #ifdef CONFIG_COMPAT
1124         if (compat)
1125                 xt_compat_lock(AF_INET6);
1126 #endif
1127         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1128                                     "ip6table_%s", name);
1129         if (t && !IS_ERR(t)) {
1130                 struct ip6t_getinfo info;
1131                 const struct xt_table_info *private = t->private;
1132 #ifdef CONFIG_COMPAT
1133                 struct xt_table_info tmp;
1134
1135                 if (compat) {
1136                         ret = compat_table_info(private, &tmp);
1137                         xt_compat_flush_offsets(AF_INET6);
1138                         private = &tmp;
1139                 }
1140 #endif
1141                 memset(&info, 0, sizeof(info));
1142                 info.valid_hooks = t->valid_hooks;
1143                 memcpy(info.hook_entry, private->hook_entry,
1144                        sizeof(info.hook_entry));
1145                 memcpy(info.underflow, private->underflow,
1146                        sizeof(info.underflow));
1147                 info.num_entries = private->number;
1148                 info.size = private->size;
1149                 strcpy(info.name, name);
1150
1151                 if (copy_to_user(user, &info, *len) != 0)
1152                         ret = -EFAULT;
1153                 else
1154                         ret = 0;
1155
1156                 xt_table_unlock(t);
1157                 module_put(t->me);
1158         } else
1159                 ret = t ? PTR_ERR(t) : -ENOENT;
1160 #ifdef CONFIG_COMPAT
1161         if (compat)
1162                 xt_compat_unlock(AF_INET6);
1163 #endif
1164         return ret;
1165 }
1166
1167 static int
1168 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1169             const int *len)
1170 {
1171         int ret;
1172         struct ip6t_get_entries get;
1173         struct xt_table *t;
1174
1175         if (*len < sizeof(get)) {
1176                 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1177                 return -EINVAL;
1178         }
1179         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1180                 return -EFAULT;
1181         if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1182                 duprintf("get_entries: %u != %zu\n",
1183                          *len, sizeof(get) + get.size);
1184                 return -EINVAL;
1185         }
1186
1187         t = xt_find_table_lock(net, AF_INET6, get.name);
1188         if (t && !IS_ERR(t)) {
1189                 struct xt_table_info *private = t->private;
1190                 duprintf("t->private->number = %u\n", private->number);
1191                 if (get.size == private->size)
1192                         ret = copy_entries_to_user(private->size,
1193                                                    t, uptr->entrytable);
1194                 else {
1195                         duprintf("get_entries: I've got %u not %u!\n",
1196                                  private->size, get.size);
1197                         ret = -EAGAIN;
1198                 }
1199                 module_put(t->me);
1200                 xt_table_unlock(t);
1201         } else
1202                 ret = t ? PTR_ERR(t) : -ENOENT;
1203
1204         return ret;
1205 }
1206
1207 static int
1208 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1209              struct xt_table_info *newinfo, unsigned int num_counters,
1210              void __user *counters_ptr)
1211 {
1212         int ret;
1213         struct xt_table *t;
1214         struct xt_table_info *oldinfo;
1215         struct xt_counters *counters;
1216         const void *loc_cpu_old_entry;
1217         struct ip6t_entry *iter;
1218
1219         ret = 0;
1220         counters = vmalloc(num_counters * sizeof(struct xt_counters));
1221         if (!counters) {
1222                 ret = -ENOMEM;
1223                 goto out;
1224         }
1225
1226         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1227                                     "ip6table_%s", name);
1228         if (!t || IS_ERR(t)) {
1229                 ret = t ? PTR_ERR(t) : -ENOENT;
1230                 goto free_newinfo_counters_untrans;
1231         }
1232
1233         /* You lied! */
1234         if (valid_hooks != t->valid_hooks) {
1235                 duprintf("Valid hook crap: %08X vs %08X\n",
1236                          valid_hooks, t->valid_hooks);
1237                 ret = -EINVAL;
1238                 goto put_module;
1239         }
1240
1241         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1242         if (!oldinfo)
1243                 goto put_module;
1244
1245         /* Update module usage count based on number of rules */
1246         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1247                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1248         if ((oldinfo->number > oldinfo->initial_entries) ||
1249             (newinfo->number <= oldinfo->initial_entries))
1250                 module_put(t->me);
1251         if ((oldinfo->number > oldinfo->initial_entries) &&
1252             (newinfo->number <= oldinfo->initial_entries))
1253                 module_put(t->me);
1254
1255         /* Get the old counters, and synchronize with replace */
1256         get_counters(oldinfo, counters);
1257
1258         /* Decrease module usage counts and free resource */
1259         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1260         xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
1261                 cleanup_entry(iter, net);
1262
1263         xt_free_table_info(oldinfo);
1264         if (copy_to_user(counters_ptr, counters,
1265                          sizeof(struct xt_counters) * num_counters) != 0)
1266                 ret = -EFAULT;
1267         vfree(counters);
1268         xt_table_unlock(t);
1269         return ret;
1270
1271  put_module:
1272         module_put(t->me);
1273         xt_table_unlock(t);
1274  free_newinfo_counters_untrans:
1275         vfree(counters);
1276  out:
1277         return ret;
1278 }
1279
1280 static int
1281 do_replace(struct net *net, const void __user *user, unsigned int len)
1282 {
1283         int ret;
1284         struct ip6t_replace tmp;
1285         struct xt_table_info *newinfo;
1286         void *loc_cpu_entry;
1287         struct ip6t_entry *iter;
1288
1289         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1290                 return -EFAULT;
1291
1292         /* overflow check */
1293         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1294                 return -ENOMEM;
1295
1296         newinfo = xt_alloc_table_info(tmp.size);
1297         if (!newinfo)
1298                 return -ENOMEM;
1299
1300         /* choose the copy that is on our node/cpu */
1301         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1302         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1303                            tmp.size) != 0) {
1304                 ret = -EFAULT;
1305                 goto free_newinfo;
1306         }
1307
1308         ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1309         if (ret != 0)
1310                 goto free_newinfo;
1311
1312         duprintf("ip_tables: Translated table\n");
1313
1314         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1315                            tmp.num_counters, tmp.counters);
1316         if (ret)
1317                 goto free_newinfo_untrans;
1318         return 0;
1319
1320  free_newinfo_untrans:
1321         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1322                 cleanup_entry(iter, net);
1323  free_newinfo:
1324         xt_free_table_info(newinfo);
1325         return ret;
1326 }
1327
1328 static int
1329 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1330                 int compat)
1331 {
1332         unsigned int i, curcpu;
1333         struct xt_counters_info tmp;
1334         struct xt_counters *paddc;
1335         unsigned int num_counters;
1336         char *name;
1337         int size;
1338         void *ptmp;
1339         struct xt_table *t;
1340         const struct xt_table_info *private;
1341         int ret = 0;
1342         const void *loc_cpu_entry;
1343         struct ip6t_entry *iter;
1344 #ifdef CONFIG_COMPAT
1345         struct compat_xt_counters_info compat_tmp;
1346
1347         if (compat) {
1348                 ptmp = &compat_tmp;
1349                 size = sizeof(struct compat_xt_counters_info);
1350         } else
1351 #endif
1352         {
1353                 ptmp = &tmp;
1354                 size = sizeof(struct xt_counters_info);
1355         }
1356
1357         if (copy_from_user(ptmp, user, size) != 0)
1358                 return -EFAULT;
1359
1360 #ifdef CONFIG_COMPAT
1361         if (compat) {
1362                 num_counters = compat_tmp.num_counters;
1363                 name = compat_tmp.name;
1364         } else
1365 #endif
1366         {
1367                 num_counters = tmp.num_counters;
1368                 name = tmp.name;
1369         }
1370
1371         if (len != size + num_counters * sizeof(struct xt_counters))
1372                 return -EINVAL;
1373
1374         paddc = vmalloc(len - size);
1375         if (!paddc)
1376                 return -ENOMEM;
1377
1378         if (copy_from_user(paddc, user + size, len - size) != 0) {
1379                 ret = -EFAULT;
1380                 goto free;
1381         }
1382
1383         t = xt_find_table_lock(net, AF_INET6, name);
1384         if (!t || IS_ERR(t)) {
1385                 ret = t ? PTR_ERR(t) : -ENOENT;
1386                 goto free;
1387         }
1388
1389
1390         local_bh_disable();
1391         private = t->private;
1392         if (private->number != num_counters) {
1393                 ret = -EINVAL;
1394                 goto unlock_up_free;
1395         }
1396
1397         i = 0;
1398         /* Choose the copy that is on our node */
1399         curcpu = smp_processor_id();
1400         xt_info_wrlock(curcpu);
1401         loc_cpu_entry = private->entries[curcpu];
1402         xt_entry_foreach(iter, loc_cpu_entry, private->size) {
1403                 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
1404                 ++i;
1405         }
1406         xt_info_wrunlock(curcpu);
1407
1408  unlock_up_free:
1409         local_bh_enable();
1410         xt_table_unlock(t);
1411         module_put(t->me);
1412  free:
1413         vfree(paddc);
1414
1415         return ret;
1416 }
1417
1418 #ifdef CONFIG_COMPAT
1419 struct compat_ip6t_replace {
1420         char                    name[XT_TABLE_MAXNAMELEN];
1421         u32                     valid_hooks;
1422         u32                     num_entries;
1423         u32                     size;
1424         u32                     hook_entry[NF_INET_NUMHOOKS];
1425         u32                     underflow[NF_INET_NUMHOOKS];
1426         u32                     num_counters;
1427         compat_uptr_t           counters;       /* struct xt_counters * */
1428         struct compat_ip6t_entry entries[0];
1429 };
1430
1431 static int
1432 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1433                           unsigned int *size, struct xt_counters *counters,
1434                           unsigned int i)
1435 {
1436         struct xt_entry_target *t;
1437         struct compat_ip6t_entry __user *ce;
1438         u_int16_t target_offset, next_offset;
1439         compat_uint_t origsize;
1440         const struct xt_entry_match *ematch;
1441         int ret = 0;
1442
1443         origsize = *size;
1444         ce = (struct compat_ip6t_entry __user *)*dstptr;
1445         if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1446             copy_to_user(&ce->counters, &counters[i],
1447             sizeof(counters[i])) != 0)
1448                 return -EFAULT;
1449
1450         *dstptr += sizeof(struct compat_ip6t_entry);
1451         *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1452
1453         xt_ematch_foreach(ematch, e) {
1454                 ret = xt_compat_match_to_user(ematch, dstptr, size);
1455                 if (ret != 0)
1456                         return ret;
1457         }
1458         target_offset = e->target_offset - (origsize - *size);
1459         t = ip6t_get_target(e);
1460         ret = xt_compat_target_to_user(t, dstptr, size);
1461         if (ret)
1462                 return ret;
1463         next_offset = e->next_offset - (origsize - *size);
1464         if (put_user(target_offset, &ce->target_offset) != 0 ||
1465             put_user(next_offset, &ce->next_offset) != 0)
1466                 return -EFAULT;
1467         return 0;
1468 }
1469
1470 static int
1471 compat_find_calc_match(struct xt_entry_match *m,
1472                        const char *name,
1473                        const struct ip6t_ip6 *ipv6,
1474                        unsigned int hookmask,
1475                        int *size)
1476 {
1477         struct xt_match *match;
1478
1479         match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1480                                       m->u.user.revision);
1481         if (IS_ERR(match)) {
1482                 duprintf("compat_check_calc_match: `%s' not found\n",
1483                          m->u.user.name);
1484                 return PTR_ERR(match);
1485         }
1486         m->u.kernel.match = match;
1487         *size += xt_compat_match_offset(match);
1488         return 0;
1489 }
1490
1491 static void compat_release_entry(struct compat_ip6t_entry *e)
1492 {
1493         struct xt_entry_target *t;
1494         struct xt_entry_match *ematch;
1495
1496         /* Cleanup all matches */
1497         xt_ematch_foreach(ematch, e)
1498                 module_put(ematch->u.kernel.match->me);
1499         t = compat_ip6t_get_target(e);
1500         module_put(t->u.kernel.target->me);
1501 }
1502
1503 static int
1504 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1505                                   struct xt_table_info *newinfo,
1506                                   unsigned int *size,
1507                                   const unsigned char *base,
1508                                   const unsigned char *limit,
1509                                   const unsigned int *hook_entries,
1510                                   const unsigned int *underflows,
1511                                   const char *name)
1512 {
1513         struct xt_entry_match *ematch;
1514         struct xt_entry_target *t;
1515         struct xt_target *target;
1516         unsigned int entry_offset;
1517         unsigned int j;
1518         int ret, off, h;
1519
1520         duprintf("check_compat_entry_size_and_hooks %p\n", e);
1521         if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1522             (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1523                 duprintf("Bad offset %p, limit = %p\n", e, limit);
1524                 return -EINVAL;
1525         }
1526
1527         if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1528                              sizeof(struct compat_xt_entry_target)) {
1529                 duprintf("checking: element %p size %u\n",
1530                          e, e->next_offset);
1531                 return -EINVAL;
1532         }
1533
1534         /* For purposes of check_entry casting the compat entry is fine */
1535         ret = check_entry((struct ip6t_entry *)e, name);
1536         if (ret)
1537                 return ret;
1538
1539         off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1540         entry_offset = (void *)e - (void *)base;
1541         j = 0;
1542         xt_ematch_foreach(ematch, e) {
1543                 ret = compat_find_calc_match(ematch, name,
1544                                              &e->ipv6, e->comefrom, &off);
1545                 if (ret != 0)
1546                         goto release_matches;
1547                 ++j;
1548         }
1549
1550         t = compat_ip6t_get_target(e);
1551         target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1552                                         t->u.user.revision);
1553         if (IS_ERR(target)) {
1554                 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1555                          t->u.user.name);
1556                 ret = PTR_ERR(target);
1557                 goto release_matches;
1558         }
1559         t->u.kernel.target = target;
1560
1561         off += xt_compat_target_offset(target);
1562         *size += off;
1563         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1564         if (ret)
1565                 goto out;
1566
1567         /* Check hooks & underflows */
1568         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1569                 if ((unsigned char *)e - base == hook_entries[h])
1570                         newinfo->hook_entry[h] = hook_entries[h];
1571                 if ((unsigned char *)e - base == underflows[h])
1572                         newinfo->underflow[h] = underflows[h];
1573         }
1574
1575         /* Clear counters and comefrom */
1576         memset(&e->counters, 0, sizeof(e->counters));
1577         e->comefrom = 0;
1578         return 0;
1579
1580 out:
1581         module_put(t->u.kernel.target->me);
1582 release_matches:
1583         xt_ematch_foreach(ematch, e) {
1584                 if (j-- == 0)
1585                         break;
1586                 module_put(ematch->u.kernel.match->me);
1587         }
1588         return ret;
1589 }
1590
1591 static int
1592 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1593                             unsigned int *size, const char *name,
1594                             struct xt_table_info *newinfo, unsigned char *base)
1595 {
1596         struct xt_entry_target *t;
1597         struct xt_target *target;
1598         struct ip6t_entry *de;
1599         unsigned int origsize;
1600         int ret, h;
1601         struct xt_entry_match *ematch;
1602
1603         ret = 0;
1604         origsize = *size;
1605         de = (struct ip6t_entry *)*dstptr;
1606         memcpy(de, e, sizeof(struct ip6t_entry));
1607         memcpy(&de->counters, &e->counters, sizeof(e->counters));
1608
1609         *dstptr += sizeof(struct ip6t_entry);
1610         *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1611
1612         xt_ematch_foreach(ematch, e) {
1613                 ret = xt_compat_match_from_user(ematch, dstptr, size);
1614                 if (ret != 0)
1615                         return ret;
1616         }
1617         de->target_offset = e->target_offset - (origsize - *size);
1618         t = compat_ip6t_get_target(e);
1619         target = t->u.kernel.target;
1620         xt_compat_target_from_user(t, dstptr, size);
1621
1622         de->next_offset = e->next_offset - (origsize - *size);
1623         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1624                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1625                         newinfo->hook_entry[h] -= origsize - *size;
1626                 if ((unsigned char *)de - base < newinfo->underflow[h])
1627                         newinfo->underflow[h] -= origsize - *size;
1628         }
1629         return ret;
1630 }
1631
1632 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1633                               const char *name)
1634 {
1635         unsigned int j;
1636         int ret = 0;
1637         struct xt_mtchk_param mtpar;
1638         struct xt_entry_match *ematch;
1639
1640         j = 0;
1641         mtpar.net       = net;
1642         mtpar.table     = name;
1643         mtpar.entryinfo = &e->ipv6;
1644         mtpar.hook_mask = e->comefrom;
1645         mtpar.family    = NFPROTO_IPV6;
1646         xt_ematch_foreach(ematch, e) {
1647                 ret = check_match(ematch, &mtpar);
1648                 if (ret != 0)
1649                         goto cleanup_matches;
1650                 ++j;
1651         }
1652
1653         ret = check_target(e, net, name);
1654         if (ret)
1655                 goto cleanup_matches;
1656         return 0;
1657
1658  cleanup_matches:
1659         xt_ematch_foreach(ematch, e) {
1660                 if (j-- == 0)
1661                         break;
1662                 cleanup_match(ematch, net);
1663         }
1664         return ret;
1665 }
1666
1667 static int
1668 translate_compat_table(struct net *net,
1669                        const char *name,
1670                        unsigned int valid_hooks,
1671                        struct xt_table_info **pinfo,
1672                        void **pentry0,
1673                        unsigned int total_size,
1674                        unsigned int number,
1675                        unsigned int *hook_entries,
1676                        unsigned int *underflows)
1677 {
1678         unsigned int i, j;
1679         struct xt_table_info *newinfo, *info;
1680         void *pos, *entry0, *entry1;
1681         struct compat_ip6t_entry *iter0;
1682         struct ip6t_entry *iter1;
1683         unsigned int size;
1684         int ret = 0;
1685
1686         info = *pinfo;
1687         entry0 = *pentry0;
1688         size = total_size;
1689         info->number = number;
1690
1691         /* Init all hooks to impossible value. */
1692         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1693                 info->hook_entry[i] = 0xFFFFFFFF;
1694                 info->underflow[i] = 0xFFFFFFFF;
1695         }
1696
1697         duprintf("translate_compat_table: size %u\n", info->size);
1698         j = 0;
1699         xt_compat_lock(AF_INET6);
1700         xt_compat_init_offsets(AF_INET6, number);
1701         /* Walk through entries, checking offsets. */
1702         xt_entry_foreach(iter0, entry0, total_size) {
1703                 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1704                                                         entry0,
1705                                                         entry0 + total_size,
1706                                                         hook_entries,
1707                                                         underflows,
1708                                                         name);
1709                 if (ret != 0)
1710                         goto out_unlock;
1711                 ++j;
1712         }
1713
1714         ret = -EINVAL;
1715         if (j != number) {
1716                 duprintf("translate_compat_table: %u not %u entries\n",
1717                          j, number);
1718                 goto out_unlock;
1719         }
1720
1721         /* Check hooks all assigned */
1722         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1723                 /* Only hooks which are valid */
1724                 if (!(valid_hooks & (1 << i)))
1725                         continue;
1726                 if (info->hook_entry[i] == 0xFFFFFFFF) {
1727                         duprintf("Invalid hook entry %u %u\n",
1728                                  i, hook_entries[i]);
1729                         goto out_unlock;
1730                 }
1731                 if (info->underflow[i] == 0xFFFFFFFF) {
1732                         duprintf("Invalid underflow %u %u\n",
1733                                  i, underflows[i]);
1734                         goto out_unlock;
1735                 }
1736         }
1737
1738         ret = -ENOMEM;
1739         newinfo = xt_alloc_table_info(size);
1740         if (!newinfo)
1741                 goto out_unlock;
1742
1743         newinfo->number = number;
1744         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1745                 newinfo->hook_entry[i] = info->hook_entry[i];
1746                 newinfo->underflow[i] = info->underflow[i];
1747         }
1748         entry1 = newinfo->entries[raw_smp_processor_id()];
1749         pos = entry1;
1750         size = total_size;
1751         xt_entry_foreach(iter0, entry0, total_size) {
1752                 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1753                                                   name, newinfo, entry1);
1754                 if (ret != 0)
1755                         break;
1756         }
1757         xt_compat_flush_offsets(AF_INET6);
1758         xt_compat_unlock(AF_INET6);
1759         if (ret)
1760                 goto free_newinfo;
1761
1762         ret = -ELOOP;
1763         if (!mark_source_chains(newinfo, valid_hooks, entry1))
1764                 goto free_newinfo;
1765
1766         i = 0;
1767         xt_entry_foreach(iter1, entry1, newinfo->size) {
1768                 ret = compat_check_entry(iter1, net, name);
1769                 if (ret != 0)
1770                         break;
1771                 ++i;
1772                 if (strcmp(ip6t_get_target(iter1)->u.user.name,
1773                     XT_ERROR_TARGET) == 0)
1774                         ++newinfo->stacksize;
1775         }
1776         if (ret) {
1777                 /*
1778                  * The first i matches need cleanup_entry (calls ->destroy)
1779                  * because they had called ->check already. The other j-i
1780                  * entries need only release.
1781                  */
1782                 int skip = i;
1783                 j -= i;
1784                 xt_entry_foreach(iter0, entry0, newinfo->size) {
1785                         if (skip-- > 0)
1786                                 continue;
1787                         if (j-- == 0)
1788                                 break;
1789                         compat_release_entry(iter0);
1790                 }
1791                 xt_entry_foreach(iter1, entry1, newinfo->size) {
1792                         if (i-- == 0)
1793                                 break;
1794                         cleanup_entry(iter1, net);
1795                 }
1796                 xt_free_table_info(newinfo);
1797                 return ret;
1798         }
1799
1800         /* And one copy for every other CPU */
1801         for_each_possible_cpu(i)
1802                 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1803                         memcpy(newinfo->entries[i], entry1, newinfo->size);
1804
1805         *pinfo = newinfo;
1806         *pentry0 = entry1;
1807         xt_free_table_info(info);
1808         return 0;
1809
1810 free_newinfo:
1811         xt_free_table_info(newinfo);
1812 out:
1813         xt_entry_foreach(iter0, entry0, total_size) {
1814                 if (j-- == 0)
1815                         break;
1816                 compat_release_entry(iter0);
1817         }
1818         return ret;
1819 out_unlock:
1820         xt_compat_flush_offsets(AF_INET6);
1821         xt_compat_unlock(AF_INET6);
1822         goto out;
1823 }
1824
1825 static int
1826 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1827 {
1828         int ret;
1829         struct compat_ip6t_replace tmp;
1830         struct xt_table_info *newinfo;
1831         void *loc_cpu_entry;
1832         struct ip6t_entry *iter;
1833
1834         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1835                 return -EFAULT;
1836
1837         /* overflow check */
1838         if (tmp.size >= INT_MAX / num_possible_cpus())
1839                 return -ENOMEM;
1840         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1841                 return -ENOMEM;
1842
1843         newinfo = xt_alloc_table_info(tmp.size);
1844         if (!newinfo)
1845                 return -ENOMEM;
1846
1847         /* choose the copy that is on our node/cpu */
1848         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1849         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1850                            tmp.size) != 0) {
1851                 ret = -EFAULT;
1852                 goto free_newinfo;
1853         }
1854
1855         ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1856                                      &newinfo, &loc_cpu_entry, tmp.size,
1857                                      tmp.num_entries, tmp.hook_entry,
1858                                      tmp.underflow);
1859         if (ret != 0)
1860                 goto free_newinfo;
1861
1862         duprintf("compat_do_replace: Translated table\n");
1863
1864         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1865                            tmp.num_counters, compat_ptr(tmp.counters));
1866         if (ret)
1867                 goto free_newinfo_untrans;
1868         return 0;
1869
1870  free_newinfo_untrans:
1871         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1872                 cleanup_entry(iter, net);
1873  free_newinfo:
1874         xt_free_table_info(newinfo);
1875         return ret;
1876 }
1877
1878 static int
1879 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1880                        unsigned int len)
1881 {
1882         int ret;
1883
1884         if (!capable(CAP_NET_ADMIN))
1885                 return -EPERM;
1886
1887         switch (cmd) {
1888         case IP6T_SO_SET_REPLACE:
1889                 ret = compat_do_replace(sock_net(sk), user, len);
1890                 break;
1891
1892         case IP6T_SO_SET_ADD_COUNTERS:
1893                 ret = do_add_counters(sock_net(sk), user, len, 1);
1894                 break;
1895
1896         default:
1897                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1898                 ret = -EINVAL;
1899         }
1900
1901         return ret;
1902 }
1903
1904 struct compat_ip6t_get_entries {
1905         char name[XT_TABLE_MAXNAMELEN];
1906         compat_uint_t size;
1907         struct compat_ip6t_entry entrytable[0];
1908 };
1909
1910 static int
1911 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1912                             void __user *userptr)
1913 {
1914         struct xt_counters *counters;
1915         const struct xt_table_info *private = table->private;
1916         void __user *pos;
1917         unsigned int size;
1918         int ret = 0;
1919         const void *loc_cpu_entry;
1920         unsigned int i = 0;
1921         struct ip6t_entry *iter;
1922
1923         counters = alloc_counters(table);
1924         if (IS_ERR(counters))
1925                 return PTR_ERR(counters);
1926
1927         /* choose the copy that is on our node/cpu, ...
1928          * This choice is lazy (because current thread is
1929          * allowed to migrate to another cpu)
1930          */
1931         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1932         pos = userptr;
1933         size = total_size;
1934         xt_entry_foreach(iter, loc_cpu_entry, total_size) {
1935                 ret = compat_copy_entry_to_user(iter, &pos,
1936                                                 &size, counters, i++);
1937                 if (ret != 0)
1938                         break;
1939         }
1940
1941         vfree(counters);
1942         return ret;
1943 }
1944
1945 static int
1946 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1947                    int *len)
1948 {
1949         int ret;
1950         struct compat_ip6t_get_entries get;
1951         struct xt_table *t;
1952
1953         if (*len < sizeof(get)) {
1954                 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1955                 return -EINVAL;
1956         }
1957
1958         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1959                 return -EFAULT;
1960
1961         if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1962                 duprintf("compat_get_entries: %u != %zu\n",
1963                          *len, sizeof(get) + get.size);
1964                 return -EINVAL;
1965         }
1966
1967         xt_compat_lock(AF_INET6);
1968         t = xt_find_table_lock(net, AF_INET6, get.name);
1969         if (t && !IS_ERR(t)) {
1970                 const struct xt_table_info *private = t->private;
1971                 struct xt_table_info info;
1972                 duprintf("t->private->number = %u\n", private->number);
1973                 ret = compat_table_info(private, &info);
1974                 if (!ret && get.size == info.size) {
1975                         ret = compat_copy_entries_to_user(private->size,
1976                                                           t, uptr->entrytable);
1977                 } else if (!ret) {
1978                         duprintf("compat_get_entries: I've got %u not %u!\n",
1979                                  private->size, get.size);
1980                         ret = -EAGAIN;
1981                 }
1982                 xt_compat_flush_offsets(AF_INET6);
1983                 module_put(t->me);
1984                 xt_table_unlock(t);
1985         } else
1986                 ret = t ? PTR_ERR(t) : -ENOENT;
1987
1988         xt_compat_unlock(AF_INET6);
1989         return ret;
1990 }
1991
1992 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1993
1994 static int
1995 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1996 {
1997         int ret;
1998
1999         if (!capable(CAP_NET_ADMIN))
2000                 return -EPERM;
2001
2002         switch (cmd) {
2003         case IP6T_SO_GET_INFO:
2004                 ret = get_info(sock_net(sk), user, len, 1);
2005                 break;
2006         case IP6T_SO_GET_ENTRIES:
2007                 ret = compat_get_entries(sock_net(sk), user, len);
2008                 break;
2009         default:
2010                 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2011         }
2012         return ret;
2013 }
2014 #endif
2015
2016 static int
2017 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2018 {
2019         int ret;
2020
2021         if (!capable(CAP_NET_ADMIN))
2022                 return -EPERM;
2023
2024         switch (cmd) {
2025         case IP6T_SO_SET_REPLACE:
2026                 ret = do_replace(sock_net(sk), user, len);
2027                 break;
2028
2029         case IP6T_SO_SET_ADD_COUNTERS:
2030                 ret = do_add_counters(sock_net(sk), user, len, 0);
2031                 break;
2032
2033         default:
2034                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
2035                 ret = -EINVAL;
2036         }
2037
2038         return ret;
2039 }
2040
2041 static int
2042 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2043 {
2044         int ret;
2045
2046         if (!capable(CAP_NET_ADMIN))
2047                 return -EPERM;
2048
2049         switch (cmd) {
2050         case IP6T_SO_GET_INFO:
2051                 ret = get_info(sock_net(sk), user, len, 0);
2052                 break;
2053
2054         case IP6T_SO_GET_ENTRIES:
2055                 ret = get_entries(sock_net(sk), user, len);
2056                 break;
2057
2058         case IP6T_SO_GET_REVISION_MATCH:
2059         case IP6T_SO_GET_REVISION_TARGET: {
2060                 struct xt_get_revision rev;
2061                 int target;
2062
2063                 if (*len != sizeof(rev)) {
2064                         ret = -EINVAL;
2065                         break;
2066                 }
2067                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2068                         ret = -EFAULT;
2069                         break;
2070                 }
2071
2072                 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2073                         target = 1;
2074                 else
2075                         target = 0;
2076
2077                 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2078                                                          rev.revision,
2079                                                          target, &ret),
2080                                         "ip6t_%s", rev.name);
2081                 break;
2082         }
2083
2084         default:
2085                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2086                 ret = -EINVAL;
2087         }
2088
2089         return ret;
2090 }
2091
2092 struct xt_table *ip6t_register_table(struct net *net,
2093                                      const struct xt_table *table,
2094                                      const struct ip6t_replace *repl)
2095 {
2096         int ret;
2097         struct xt_table_info *newinfo;
2098         struct xt_table_info bootstrap = {0};
2099         void *loc_cpu_entry;
2100         struct xt_table *new_table;
2101
2102         newinfo = xt_alloc_table_info(repl->size);
2103         if (!newinfo) {
2104                 ret = -ENOMEM;
2105                 goto out;
2106         }
2107
2108         /* choose the copy on our node/cpu, but dont care about preemption */
2109         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2110         memcpy(loc_cpu_entry, repl->entries, repl->size);
2111
2112         ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2113         if (ret != 0)
2114                 goto out_free;
2115
2116         new_table = xt_register_table(net, table, &bootstrap, newinfo);
2117         if (IS_ERR(new_table)) {
2118                 ret = PTR_ERR(new_table);
2119                 goto out_free;
2120         }
2121         return new_table;
2122
2123 out_free:
2124         xt_free_table_info(newinfo);
2125 out:
2126         return ERR_PTR(ret);
2127 }
2128
2129 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2130 {
2131         struct xt_table_info *private;
2132         void *loc_cpu_entry;
2133         struct module *table_owner = table->me;
2134         struct ip6t_entry *iter;
2135
2136         private = xt_unregister_table(table);
2137
2138         /* Decrease module usage counts and free resources */
2139         loc_cpu_entry = private->entries[raw_smp_processor_id()];
2140         xt_entry_foreach(iter, loc_cpu_entry, private->size)
2141                 cleanup_entry(iter, net);
2142         if (private->number > private->initial_entries)
2143                 module_put(table_owner);
2144         xt_free_table_info(private);
2145 }
2146
2147 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2148 static inline bool
2149 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2150                      u_int8_t type, u_int8_t code,
2151                      bool invert)
2152 {
2153         return (type == test_type && code >= min_code && code <= max_code)
2154                 ^ invert;
2155 }
2156
2157 static bool
2158 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2159 {
2160         const struct icmp6hdr *ic;
2161         struct icmp6hdr _icmph;
2162         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2163
2164         /* Must not be a fragment. */
2165         if (par->fragoff != 0)
2166                 return false;
2167
2168         ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2169         if (ic == NULL) {
2170                 /* We've been asked to examine this packet, and we
2171                  * can't.  Hence, no choice but to drop.
2172                  */
2173                 duprintf("Dropping evil ICMP tinygram.\n");
2174                 par->hotdrop = true;
2175                 return false;
2176         }
2177
2178         return icmp6_type_code_match(icmpinfo->type,
2179                                      icmpinfo->code[0],
2180                                      icmpinfo->code[1],
2181                                      ic->icmp6_type, ic->icmp6_code,
2182                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
2183 }
2184
2185 /* Called when user tries to insert an entry of this type. */
2186 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2187 {
2188         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2189
2190         /* Must specify no unknown invflags */
2191         return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2192 }
2193
2194 /* The built-in targets: standard (NULL) and error. */
2195 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2196         {
2197                 .name             = XT_STANDARD_TARGET,
2198                 .targetsize       = sizeof(int),
2199                 .family           = NFPROTO_IPV6,
2200 #ifdef CONFIG_COMPAT
2201                 .compatsize       = sizeof(compat_int_t),
2202                 .compat_from_user = compat_standard_from_user,
2203                 .compat_to_user   = compat_standard_to_user,
2204 #endif
2205         },
2206         {
2207                 .name             = XT_ERROR_TARGET,
2208                 .target           = ip6t_error,
2209                 .targetsize       = XT_FUNCTION_MAXNAMELEN,
2210                 .family           = NFPROTO_IPV6,
2211         },
2212 };
2213
2214 static struct nf_sockopt_ops ip6t_sockopts = {
2215         .pf             = PF_INET6,
2216         .set_optmin     = IP6T_BASE_CTL,
2217         .set_optmax     = IP6T_SO_SET_MAX+1,
2218         .set            = do_ip6t_set_ctl,
2219 #ifdef CONFIG_COMPAT
2220         .compat_set     = compat_do_ip6t_set_ctl,
2221 #endif
2222         .get_optmin     = IP6T_BASE_CTL,
2223         .get_optmax     = IP6T_SO_GET_MAX+1,
2224         .get            = do_ip6t_get_ctl,
2225 #ifdef CONFIG_COMPAT
2226         .compat_get     = compat_do_ip6t_get_ctl,
2227 #endif
2228         .owner          = THIS_MODULE,
2229 };
2230
2231 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2232         {
2233                 .name       = "icmp6",
2234                 .match      = icmp6_match,
2235                 .matchsize  = sizeof(struct ip6t_icmp),
2236                 .checkentry = icmp6_checkentry,
2237                 .proto      = IPPROTO_ICMPV6,
2238                 .family     = NFPROTO_IPV6,
2239         },
2240 };
2241
2242 static int __net_init ip6_tables_net_init(struct net *net)
2243 {
2244         return xt_proto_init(net, NFPROTO_IPV6);
2245 }
2246
2247 static void __net_exit ip6_tables_net_exit(struct net *net)
2248 {
2249         xt_proto_fini(net, NFPROTO_IPV6);
2250 }
2251
2252 static struct pernet_operations ip6_tables_net_ops = {
2253         .init = ip6_tables_net_init,
2254         .exit = ip6_tables_net_exit,
2255 };
2256
2257 static int __init ip6_tables_init(void)
2258 {
2259         int ret;
2260
2261         ret = register_pernet_subsys(&ip6_tables_net_ops);
2262         if (ret < 0)
2263                 goto err1;
2264
2265         /* Noone else will be downing sem now, so we won't sleep */
2266         ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2267         if (ret < 0)
2268                 goto err2;
2269         ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2270         if (ret < 0)
2271                 goto err4;
2272
2273         /* Register setsockopt */
2274         ret = nf_register_sockopt(&ip6t_sockopts);
2275         if (ret < 0)
2276                 goto err5;
2277
2278         pr_info("(C) 2000-2006 Netfilter Core Team\n");
2279         return 0;
2280
2281 err5:
2282         xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2283 err4:
2284         xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2285 err2:
2286         unregister_pernet_subsys(&ip6_tables_net_ops);
2287 err1:
2288         return ret;
2289 }
2290
2291 static void __exit ip6_tables_fini(void)
2292 {
2293         nf_unregister_sockopt(&ip6t_sockopts);
2294
2295         xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2296         xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2297         unregister_pernet_subsys(&ip6_tables_net_ops);
2298 }
2299
2300 /*
2301  * find the offset to specified header or the protocol number of last header
2302  * if target < 0. "last header" is transport protocol header, ESP, or
2303  * "No next header".
2304  *
2305  * If target header is found, its offset is set in *offset and return protocol
2306  * number. Otherwise, return -1.
2307  *
2308  * If the first fragment doesn't contain the final protocol header or
2309  * NEXTHDR_NONE it is considered invalid.
2310  *
2311  * Note that non-1st fragment is special case that "the protocol number
2312  * of last header" is "next header" field in Fragment header. In this case,
2313  * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2314  * isn't NULL.
2315  *
2316  */
2317 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2318                   int target, unsigned short *fragoff)
2319 {
2320         unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2321         u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2322         unsigned int len = skb->len - start;
2323
2324         if (fragoff)
2325                 *fragoff = 0;
2326
2327         while (nexthdr != target) {
2328                 struct ipv6_opt_hdr _hdr, *hp;
2329                 unsigned int hdrlen;
2330
2331                 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2332                         if (target < 0)
2333                                 break;
2334                         return -ENOENT;
2335                 }
2336
2337                 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2338                 if (hp == NULL)
2339                         return -EBADMSG;
2340                 if (nexthdr == NEXTHDR_FRAGMENT) {
2341                         unsigned short _frag_off;
2342                         __be16 *fp;
2343                         fp = skb_header_pointer(skb,
2344                                                 start+offsetof(struct frag_hdr,
2345                                                                frag_off),
2346                                                 sizeof(_frag_off),
2347                                                 &_frag_off);
2348                         if (fp == NULL)
2349                                 return -EBADMSG;
2350
2351                         _frag_off = ntohs(*fp) & ~0x7;
2352                         if (_frag_off) {
2353                                 if (target < 0 &&
2354                                     ((!ipv6_ext_hdr(hp->nexthdr)) ||
2355                                      hp->nexthdr == NEXTHDR_NONE)) {
2356                                         if (fragoff)
2357                                                 *fragoff = _frag_off;
2358                                         return hp->nexthdr;
2359                                 }
2360                                 return -ENOENT;
2361                         }
2362                         hdrlen = 8;
2363                 } else if (nexthdr == NEXTHDR_AUTH)
2364                         hdrlen = (hp->hdrlen + 2) << 2;
2365                 else
2366                         hdrlen = ipv6_optlen(hp);
2367
2368                 nexthdr = hp->nexthdr;
2369                 len -= hdrlen;
2370                 start += hdrlen;
2371         }
2372
2373         *offset = start;
2374         return nexthdr;
2375 }
2376
2377 EXPORT_SYMBOL(ip6t_register_table);
2378 EXPORT_SYMBOL(ip6t_unregister_table);
2379 EXPORT_SYMBOL(ip6t_do_table);
2380 EXPORT_SYMBOL(ip6t_ext_hdr);
2381 EXPORT_SYMBOL(ipv6_find_hdr);
2382
2383 module_init(ip6_tables_init);
2384 module_exit(ip6_tables_fini);