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