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