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